Skip to content

Commit

Permalink
Merge pull request #2 from FLUX-SE/json-rpc
Browse files Browse the repository at this point in the history
Json rpc
  • Loading branch information
Prometee authored Aug 9, 2023
2 parents d030e59 + 851b493 commit 9d6043b
Show file tree
Hide file tree
Showing 72 changed files with 839 additions and 632 deletions.
15 changes: 7 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ jobs:
fail-fast: false
matrix:
odoo: [13, 14, 15, 16]
symfony: ["^5.4", "^6.0"]
php: [7.4, 8.0]
symfony: ["^5.4", "^6.3"]
php: [8.0, 8.1, 8.2]
exclude:
- symfony: "^6.0"
php: 7.4
- symfony: "^6.3"
php: 8.0
services:
postgres:
image: postgres
Expand Down Expand Up @@ -114,10 +114,6 @@ jobs:
composer validate --strict
vendor/bin/ecs check src tests
-
name: Run PHPStan
run: vendor/bin/phpstan analyse -l max src/

-
name: Wait until odoo is ready
run: |
Expand All @@ -135,6 +131,9 @@ jobs:
"Tests\\FluxSE\\OdooApiClient\\TestModel\\Object"
# Need classes from Odoo to be generated for the tests folder
-
name: Run PHPStan
run: vendor/bin/phpstan analyse -l max src/ tests/
-
name: Run Psalm
run: vendor/bin/psalm
Expand Down
118 changes: 94 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@

## Odoo API client

This library allow communication trough Odoo XMLRPC API.
This library allow communication trough Odoo JSON-RPC or XML-RPC API.
Documentation about it can be found here :
https://www.odoo.com/documentation/master/webservices/odoo.html
https://www.odoo.com/documentation/master/developer/reference/external_api.html

This library will allows you to :
This library will allow you to :

* Generate PHP model classes based on the info available into your Odoo database to ease your calls to the API
* Send requests to your Odoo instance through the XMLRPC API
* Generate PHP model classes based on the info available into your own Odoo database to ease your calls to the API
* Send requests to your Odoo instance through the JSON-RPC or the XML-RPC API
* Make raw requests like [Ripcord](https://github.com/poef/ripcord) was doing it but using newer libs like :
* `php-http/httplug` to make http requests
* `symfony/serializer` to handle the XMLRPC format and to transform resulting array to dedicated object classes.
* `symfony/serializer` to handle the JSON/XML-RPC format and to transform resulting array to dedicated object classes.

## Installation

Expand All @@ -24,15 +24,24 @@ This library will allows you to :
Install using Composer :

```shell
composer require flux-se/odoo-api-client php-http/guzzle6-adapter http-interop/http-factory-guzzle
composer require flux-se/odoo-api-client php-http/guzzle7-adapter http-interop/http-factory-guzzle
```
> `php-http/guzzle6-adapter` and `http-interop/http-factory-guzzle` are 2 requirements which can be chosen among
> `php-http/guzzle7-adapter` and `http-interop/http-factory-guzzle` are 2 requirements which can be chosen among
> [php-http/client-implementation](https://packagist.org/providers/php-http/client-implementation) and [psr/http-factory-implementation](https://packagist.org/providers/psr/http-factory-implementation)
### Object models generation

Depending on your instance the object models available will be different.
That's why you can generate model classes using this cli command :
**First gather required credential and database info described [here](https://www.odoo.com/documentation/master/developer/reference/external_api.html#connection).**

Depending on your instance the object models available will be different,
that's why this library is allowing you to generate model classes using this cli command :

> This command is using env vars to guess the credentials and database info,
> you can use those env vars to set your credential globally :
> * `ODOO_API_HOST`
> * `ODOO_API_DATABASE`
> * `ODOO_API_USERNAME`
> * `ODOO_API_PASSWORD`
```shell
#> vendor/bin/odoo-model-classes-generator --help
Expand All @@ -47,7 +56,7 @@ Options:
--host[=HOST] Your Odoo base host (default: http://localhost:8069) [default: "http://localhost:8069"]
--database[=DATABASE] Your Odoo database name (default: odoo-master) [default: "odoo-master"]
--username[=USERNAME] Your Odoo account username. (default: admin) [default: "admin"]
--password[=PASSWORD] Your Odoo account password (default: admin) [default: "admin"]
--password[=PASSWORD] Your Odoo account password or API key (since Odoo v14, default: admin) [default: "admin"]
-h, --help Display help for the given command. When no command is given display help for the vendor/bin/odoo-model-classes-generator command
-q, --quiet Do not output any message
-V, --version Display this application version
Expand All @@ -67,7 +76,44 @@ Example :

## Introduction

The Odoo XMLRPC API expose 3 main endpoints :
This chapter will describe how the two Odoo APIs are working.

### JSON-RPC

The Odoo JSON-RPC API expose 1 main endpoint `/jsonrpc`.
The body request payload is a JSON object with specific data into it :

```json
{
"jsonrpc": "2.0",
"method": 'call',
"params": {
{
"service": 'common',
"method": 'login',
"args": [
'database',
'username',
'password'
]
}
},
"id": 123456890
}
```

The service param can be set with those 3 values :

- `db` allowing to manage the postgres database
- `common` allowing to authenticate a user or get info about the Odoo installation
- `object` allowing operations with all API exposed models

This library help you to use those endpoints using `ext-json` and `HttPlug`, **it also allows you to
consume Odoo API using PHP classes representation of all installed Odoo Models**.

### XML-RPC

The Odoo XML-RPC API expose 3 main endpoints :

- `/xmlrpc/2/db` allowing to manage the postgres database
- `/xmlrpc/2/common` allowing to authenticate a user or get info about the Odoo installation
Expand All @@ -77,13 +123,13 @@ This library help you to use those endpoints using `ext-xmlrpc` and `HttPlug`, *
consume Odoo API using PHP classes representation of all installed Odoo Models**.

The authentication is not standard (compare to other APIs), your username and your password will be used during a call to
`/xmlrpc/2/common` with the XMLRPC method `authenticate` returning your Odoo user id (`uid`).
`/xmlrpc/2/common` with the XML-RPC method `authenticate` (or `login`) returning your Odoo user id (`uid`).
This uid, your password and your Odoo database name are required to make every request calls to the
`/xmlrpc/2/object` endpoint.

## Usage example

Using this library you will be able to use two ways of consuming the Odoo XMLRPC API :
Using this library you will be able to use two ways of consuming the Odoo XML-RPC API :

1. using array
2. using object model classes
Expand All @@ -104,29 +150,30 @@ use FluxSE\OdooApiClient\Operations\Object\ExecuteKw\Arguments\SearchDomains;
$host = 'https://myapp.odoo.com';
$database = 'myapp';
$username = '[email protected]';
$password = 'myOdooPassword';
$password = 'myOdooUserApiKey';

// 1 - instantiate the Odoo API client builder
$odooApiClientBuilder = new OdooApiClientBuilder($host);

// 2 - "Object" endpoint XMLRPC "execute_kw" call with method name like "search*" or "read")
// 2 - service allowing to query Odoo API using `execute_kw` method
$recordListOperations = $odooApiClientBuilder->buildExecuteKwOperations(
RecordListOperations::class,
$database,
$username,
$password
);

// 2.1 - Helper class to set parameters to your request
// 3.1 - Helper class to set parameters to your request
$searchDomains = new SearchDomains();
$searchDomains->addCriterion(Criterion::equal('is_company', true));
// will be translated to : [['is_company', '=', true]]

// 2.2 - Helper class to set options to your request
// 3.2 - Helper class to set options to your request
$searchReadOptions = new SearchReadOptions();
$searchReadOptions->setLimit(1);
$searchReadOptions->addField('name');

// 3.3 - Search for the first Partner being a company and only return its name
$partners = $recordListOperations->search_read('res.partner', $searchDomains, $searchReadOptions);

dump($partners);
Expand All @@ -143,44 +190,59 @@ array:1 [
**/
```

> By default, the **JSON-RPC** API will be used, if you want to use XML-RPC
> create an Odoo Api Client builder like this :
>
> ```php
> use FluxSE\OdooApiClient\Api\OdooApiRequestMakerInterface;
> use FluxSE\OdooApiClient\Builder\OdooApiClientBuilder;
>
> $odooApiClientBuilder = new OdooApiClientBuilder(
> $host,
> OdooApiRequestMakerInterface::BASE_XMLRPC_PATH
> );
> ```
## Using object model
```php
$loader = require_once( __DIR__.'/vendor/autoload.php');
use App\Odoo\Model\Object\Res\Partner;
use FluxSE\OdooApiClient\Builder\OdooApiClientBuilder;
use FluxSE\OdooApiClient\Manager\ModelListManager;
use FluxSE\OdooApiClient\Operations\Object\ExecuteKw\RecordListOperations;
use FluxSE\OdooApiClient\Operations\Object\ExecuteKw\Arguments\Criterion;
use FluxSE\OdooApiClient\Operations\Object\ExecuteKw\Arguments\SearchDomains;
$host = 'https://myapp.odoo.com';
$database = 'myapp';
$username = '[email protected]';
$password = 'myOdooPassword';
$password = 'myOdooUserApiKey';
// 1 - instantiate the Odoo API client builder
// 1 - instantiate the Odoo API client builder
$odooApiClientBuilder = new OdooApiClientBuilder($host);
// 2 - "Object" endpoint XMLRPC "execute_kw" call with method name like "search*" or "read")
// 2 - service allowing to query Odoo API using `execute_kw` method
$recordListOperations = $odooApiClientBuilder->buildExecuteKwOperations(
RecordListOperations::class,
$database,
$username,
$password
);
// 3 - upper service allowing to return classes instead of raw array data
$modelListManager = new ModelListManager(
$odooApiClientBuilder->buildSerializer(),
$recordListOperations
);
// 2 - Helper class to set parameters to your request
// 4.1- Helper class to set parameters to your request
$searchDomains = new SearchDomains();
$searchDomains->addCriterion(Criterion::equal('is_company', true));
// will be translated to : [['is_company', '=', true]]

// 4.2 - Search for the first Partner being a company
$partner = $modelListManager->findOneBy(Partner::class, $searchDomains);
dump($partner);
Expand All @@ -205,6 +267,10 @@ App\Odoo\Model\Object\Res\Partner
**/
```
# Know issues

* Since Odoo v16 some new fields can produce 500 errors, I try to create issues about them when I get the error, you can found the relates issues here : https://github.com/odoo/odoo/issues?q=is%3Aissue+author%3APrometee+

# Development

## Using docker
Expand All @@ -215,14 +281,16 @@ docker run --rm --pull always -p 8069:8069 --name odoo -e "HOST=host.docker.inte
```

The server is fully ready to use when this log line appears
(v13 could take longer than v14 to reach this line) :
(Odoo v13 could take longer than upper version to reach this line) :

```log
2021-01-01 00:00:00,000 1 INFO odoo-master odoo.modules.loading: Modules loaded.
```

Generate the model classes based on the docker Odoo instance :

> This script will use env vars to gather info about (see info [here](#object-models-generation))
```shell
bin/odoo-model-classes-generator \
"./tests/TestModel/Object" \
Expand All @@ -232,6 +300,8 @@ bin/odoo-model-classes-generator \
Test the code against the generated classes from your own Odoo instance

```shell
vendor/bin/ecs check tests
vendor/bin/psalm
vendor/bin/phpunit
````

Expand Down
2 changes: 1 addition & 1 deletion bin/odoo-model-classes-generator
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ $command = new GeneratorCommand(
$application->add($command);

$application->setDefaultCommand($command->getName(), true);
$application->run();
$application->run();
24 changes: 15 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,37 @@
}
],
"require": {
"php": "^7.4|^8.0",
"ext-xmlrpc": "*",
"php": "^8.0",
"php-http/httplug": "^1.0|^2.0",
"php-http/client-implementation": "^1.0",
"php-http/client-common": "^1.3|^2.1",
"php-http/discovery": "^1.7",
"psr/http-factory-implementation": "^1.0",
"symfony/console": "^5.4|^6.0",
"symfony/console": "^5.4|^6.3",
"symfony/serializer": "^5.4",
"symfony/property-access": "^5.4|^6.0",
"symfony/property-info": "^5.4|^6.0",
"symfony/string": "^5.4|^6.0",
"symfony/http-kernel": "^5.4|^6.0",
"symfony/property-access": "^5.4|^6.3",
"symfony/property-info": "^5.4|^6.3",
"symfony/string": "^5.4|^6.3",
"symfony/http-kernel": "^5.4|^6.3",
"php-http/logger-plugin": "^1.1",
"prometee/php-class-generator": "^1.0",
"doctrine/annotations": "^1.13",
"webmozart/assert": "^1"
},
"require-dev": {
"ext-xmlrpc": "*",
"ext-json": "*",
"phpunit/phpunit": "^9",
"php-http/guzzle6-adapter": "^2.0",
"php-http/guzzle7-adapter": "^1.0",
"http-interop/http-factory-guzzle": "^1.0",
"symplify/easy-coding-standard": "^11",
"phpstan/phpstan": "^1",
"vimeo/psalm": "^4.18"
"vimeo/psalm": "^4.18",
"rector/rector": "^0.17.10"
},
"suggest": {
"ext-xmlrpc": "Needed to support XML-RPC.",
"ext-json": "Needed to support JSON-RPC."
},
"bin": [
"bin/odoo-model-classes-generator"
Expand Down
16 changes: 8 additions & 8 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
parameters:
reportUnmatchedIgnoredErrors: false
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false

paths:
- src
- tests

excludePaths:
- tests/Manager/ModelManagerTest.php

ignoreErrors:
- '#Method FluxSE\\OdooApiClient\\Command\\GeneratorCommand::getStringOption\(\) should return string but returns array<string>\|bool\|string\|null.#'
- '#Method FluxSE\\OdooApiClient\\Command\\GeneratorCommand::getStringArgument\(\) should return string but returns array<string>\|string\|null.#'
- '#Method FluxSE\\OdooApiClient\\Serializer\\NullOdooRelationDenormalizer::denormalize\(\) should return array\|object but returns null.#'
- '#Method FluxSE\\OdooApiClient\\Manager\\ModelListManager::(find|findBy)\(\) should return (array<|\()T of FluxSE\\OdooApiClient\\Model\\BaseInterface(>|\)\|null) but returns mixed\.#'
- '#Method FluxSE\\OdooApiClient\\Serializer\\XmlRpcSerializerHelper::deserializeResponseBody\(\) should return T of object but returns mixed\.#'
- '#Method FluxSE\\OdooApiClient\\Serializer\\XmlRpcSerializerHelper::decodeResponseBody\(\) should return array\|bool\|int\|string but returns mixed\.#'
- '/Method FluxSE\\OdooApiClient\\Manager\\ModelListManager::(find|findBy)\(\) should return (array<|\()T of FluxSE\\OdooApiClient\\Model\\BaseInterface(>|\)\|null) but returns mixed\./'
- '/Method FluxSE\\OdooApiClient\\Serializer\\(Json|Xml)Rpc\\(Json|Xml)RpcSerializerHelper::deserializeResponseBody\(\) should return T of object but returns mixed\./'
- '/Method FluxSE\\OdooApiClient\\Serializer\\(Json|Xml)Rpc\\(Json|Xml)RpcSerializerHelper::decodeResponseBody\(\) should return array\|bool\|int\|string but returns mixed\./'

2 changes: 1 addition & 1 deletion psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<directory name="tests" />
<ignoreFiles allowMissingFiles="true">
<directory name="vendor" />
<directory name="tests/TestModel" />
<directory name="tests" />
</ignoreFiles>
</projectFiles>

Expand Down
Loading

0 comments on commit 9d6043b

Please sign in to comment.