consilience / laravel-odoo-api-client
Laravel 对 Odoo API 的提供者
Requires
- php: >= 7.0.0
- phpxmlrpc/phpxmlrpc: ~4.3
README
支持 Laravel 5.7 和 Odoo 7 (OpenERP 7)。
简介
本包的目的是从 Laravel 内部方便地访问 OpenERP/Odoo XML-RPC API。只需设置一些配置,从 OdooApi
门面获取一个客户端,然后传递一些数据即可。
理想情况下,这将是两部分:一个 API 包和一个 Laravel 包装器。这可以稍后完成,但到目前为止这已经满足我们的需求,并且 Laravel 提供的一些辅助器使得事情运行得更加顺畅(集合,数组/对象点符号访问)。
安装
通过 composer
composer require consilience/laravel-odoo-api-client
注意:待发布到 packagist,需要在 composer.json
中添加以下条目以定位此包
"repositories": [ { "type": "vcs", "url": "https://github.com/consilience/laravel-odoo-api-client.git" } ... ] ...
发布配置
使用 Laravel artisan 命令发布 config\odoo-api.php
artisan vendor:publish --provider="Consilience\OdooApi\OdooServiceProvider"
在 .env.example
中可以找到 .env
的示例设置。
您可以在 config\odoo-api.php
中添加多个配置集,并在您的应用程序中同时使用它们。配置集名称通过 OdooApi::getClient('config-name')
传递。
示例
一个非常简单的示例
// This facade is auto-discovered for Laravel 5.6+ use OdooApi; // The default config. // getClient() will take other configuration names. $client = OdooApi::getClient(); // Note the criteria is a nested list of scalar values. // The datatypes will converted to the appropriate objects internally. // You can mix scalars and objects here to force the datatype, for example // ['name', $client->stringValue('ilike'), 'mich'] $criteria = [ ['name', 'ilike', 'mich'], ]; // First 10 matching IDs $client->search('res.partner', $criteria, 0, 10, 'id desc')->value()->me['array'] // Total count for the criteria. $client->searchCount('res.partner', $criteria); // Read the complete details of two specific partners. $client->read('res.partner', [17858, 17852])->value()->me['array']
如果您对 XML-RPC 客户端有特定的要求,例如要添加 SSL 证书,则可以使用以下方式获取客户端实例
$xmlRpcClient = $client->getXmlRpcClient($type);
其中 $type
通常为 'db'、'common' 或 'object'。
您可以从头开始构造自己的消息,如上所示,并且 $client
中有辅助方法可以将原生 PHP 数据类型转换为 XML RPC 值对象,以及从 XML RPC 值对象转换回原生 PHP 数据类型。但是,您应该能够让客户端在后台处理所有这些转换 - 只需给它数组/字符串/整数等数据,然后返回模型和数组。
搜索条件
搜索条件是搜索术语和逻辑运算符的数组,用波兰表示法表达。
用于比较搜索术语的逻辑运算符是
&
- 逻辑 AND|
- 逻辑 OR!
- 逻辑 NOT
每个搜索术语的形式如下
[field_name, operator, value]
搜索术语运算符是
- =
- !=
- >
- >=
- <
- <=
- like
- ilike
- in
- not in
- child_of - 记录是给定记录的子记录或孙记录,
- parent_left
- parent_right
示例:搜索名称类似于 'Fred%' 或 'Jane%' 且合作伙伴 ID 为 1 或 2 的记录,将如下所示
[ '&', '|', ['name', 'like', 'Fred%'], ['name', 'like', 'Jane%'], ['partner_id', 'in', [1, 2]], ]
波兰表示法从内到外工作。第一个 &
运算符取下两个术语并将它们进行 AND 运算。两个术语中的第一个是 |
运算符。然后 |
运算符取下两个术语并将它们进行 OR 运算,从而得到一个单一的条件,该条件作为输入传递给 'AND'。最后一个术语作为 'AND' 条件输入。结果是
(name like 'Fred%' or name like 'Jane%') and partner_id in (1, 2)
查询方法
以下方法受到支持,并将返回一个集合
- search() - 整数集合
- searchRead() - 模型集合
- read() - 模型集合
- getResourceIds - 整数集合
- fieldsGet() - 数组集合
以下辅助函数返回原生 PHP 类型
- searchCount - 整数
- getResourceId - 整数
- unlink - 布尔值
- create - 整数
- write - 布尔值
所有 read()
和 searchRead()
方法将返回一组模型。默认模型将是 Consilience\OdooApi\Model
,但也可以指定其他模型。odoo-api.php
配置提供了一个数组设置,用于将 OpenERP 模型名称映射到模型类名称以进行实例化。可以通过使用 $client->addMapping('odoo.model.name', \FQDN\Class\name::class)
在客户端添加更多映射。
注意,对于小于 8.0 版本的 Odoo(OpenERP),searchRead
将模拟服务器的 search_read
,但对于 8.0 版本以上的 Odoo,则使用原生的 search_read
。
读取选项
read()
方法接受一个选项数组,它在 OpenERP/Odoo 版本之间差异很大。该包目前不尝试处理这一点。
例如,要限制读取到命名属性,以下格式被使用
- OpenERP 7: $client->read('account.invoice', [123], ['type', 'partner_id']);
- OpenERP 8: $client->read('account.invoice', [123], ['fields' => ['type', 'partner_id']]);
- OpenERP 10: $client->read('account.invoice', [123], ['attributes' => ['type', 'partner_id']]);
这使得在 API 上寻找帮助变得困难,因为许多文章没有明确说明 OpenERP/Odoo 版本号。
设置关系
有创建关系数据的助手。以下是一个简单的示例,用一组新的发票替换属于合作伙伴的所有发票
$invoiceIds = ... // array or collection of resource IDs for the invoices to link $response = $client->write( 'res.partner', $partnerResourceId, [ 'invoice_ids' => $client->relationReplaceAllLinks($invoiceIds), // other optional fields and relations can be set here as nornmal ] );
设置关系的一般方法是设置关系(在本例中为 invoice_ids
)到一个包含 ID 列表及其对这些 ID 执行操作说明的数据结构。
这里的 relationReplaceAllLinks()
生成数据结构以指导 Odoo 用新的 $invoiceIds
(一个数组)替换 res.partner
与任何他们拥有的发票之间的所有链接。您可以自己构造这些数据结构,或使用以下助手
// Relate a resource. $client->relationCreate(array $resourceIds) // Update a related resource. // e.g. change the product on an invoice line for an invoice relationUpdate(int $resourceId, array $values) // Delete a related resource completely. // e.g. delete an invoice line on an invoice relationDelete(int $resourceId) // Remove the relation to a related resource, but leave the resource intact. // e.g. remove an invoice from a contact so it can be adde to a new contact relationRemoveLink(int $resourceId) // Add a resource to a relation, leaving existing relations intact. // e.g. add an additional line to an invoice. relationAddLink(int $resourceId) // Remove all relations to a resource type. // e.g. remove all invoices from a contact, before the contatc can is deleted. relationRemoveAllLinks() // Replace all relations with a new set of relations. // e.g. remove all invoices from contact, and give them a new bunch of invoices // to be responsible for. relationReplaceAllLinks(iterable $resourceIds)
非 CRUD 请求
有助手函数提供 read
、write
、unlink
、search
功能,但您也可以访问较低级别的其他 API 方法。例如,可以使用销售订单的 message_post
函数向销售发票添加备注。下面的示例展示了如何做到这一点。
use OdooApi; $client = OdooApi::getClient(); // Resource and action, the remote RPC function. // Note that the message_post() function for each resource type is // different, i.e. this is not something that can be genereralised // in the API. // This starts to build the request message and addes the first // few positional parameters and authentication details. $msg = $client->getBaseObjectRequest('sale.order', 'message_post'); // Further positional parameters. // This is for an Odoo 7.0 installation. Other versions may differ. $msg->addParam($client->nativeToValue([$orderId])); // Resource(s) ID $msg->addParam($client->nativeToValue($text_message)); // Body $msg->addParam($client->nativeToValue(false)); // Subject $msg->addParam($client->nativeToValue('comment')); // Subtype $msg->addParam($client->nativeToValue(false)); // Partner IDs to send a copy to // Send the message. $response = $client->getXmlRpcClient('object')->send($msg); // If you want to inspect the result, then this will give you // what the Odoo message_post() function returns. $result = $client->valueToNative($response->value());
加载函数
Odoo 提供了一个处理资源加载的加载器 API。该包提供了 load()
和 loadOne()
方法来访问该 API。
加载器使用 id
作为外部 ID。如果资源已存在,它将找到资源并更新它;否则,如果资源不存在,它将创建资源。
列表中的每个资源都可以指定不同的字段,但所有字段都必须为同一资源模型。
// Load one or more partners. $loadResult = $client->load('res.partner', [ [ "name" => "JJ Test", "active" => "TRUE", "type" => "developer", "id" => "external.partner_12345", ], // Further records for this model... ]);
响应将是一个包含两个元素的数组,ids
和 messages
,两者都是集合。
ids
集合将包含任何更新或创建的资源 内部 ID。messages
集合将包含任何失败更新或资源创建的验证错误。对于单个失败的记录可能有多个消息。
// Example response with no errors and two resources updated or created. array:2 [ "ids" => Collection { #items: array:2 [ 0 => 7252 1 => 7251 ] } "messages" => Collection { #items: [] } ] // Example with oen validation error. // Note no records are loaded at all if any record fails validation. array:2 [ "ids" => Collection { #items: [] } "messages" => Collection { #items: array:1 [ 0 => array:5 [ "field" => "year" "rows" => array:2 [ "to" => 1 "from" => 1 ] "record" => 1 "message" => "'2019x' does not seem to be an integer for field 'My Year'" "type" => "error" ] ] } ]
尽管记录键可以在记录之间有所不同,但 Odoo API 不支持内部这一点。该包通过将具有相同键的记录分组并分组加载来解决此问题。这意味着一个组中的验证错误不会阻止另一个组中的记录加载,因此结果可以是失败和加载记录的混合。
在 Odoo 中,对于不可恢复的错误(例如数据库完整性约束违反),将抛出异常。
loadOne()
方法以类似的方式工作,但它只接受一个记录进行加载。它将返回一个包含整数 内部 ID
的 id
元素,如果记录失败加载则返回 null
,以及一个包含消息的集合。
待办事项
- 尚未测试
date
类型的转换。理想情况下,我们会支持 Carbon 2 以发送日期并获取返回的日期。 - 测试。当时间受限时,总是测试被遗忘。它们需要在Laravel环境中运行,因此需要相应的助手。
- 如果能将其拆分为非Laravel包,并为它添加一个独立的Laravel包装器,那就很棒了。但是集合太好了,所以这可能不会发生。
- 一些Odoo版本特定数据结构的助手方法。例如,为版本7、8和10的
read
指定要检索的字段列表引入了新的结构。客户端类在此阶段可能会变得有些繁琐,因此将一些XML-RPC特定的内容(消息创建、数据转换)移动到单独的连接类中会更好。 - 位置参数构建助手。
- 一些更具体的异常。