athwari/laravel-odoo-api
Composer 安装命令:
composer require athwari/laravel-odoo-api
包简介
PHP Odoo JSON-RPC connector with an attribute-based model layer, prepared for Laravel integration
README 文档
README
PHP Odoo JSON-RPC connector with an attribute-based model layer, prepared for laravel-odoo-api integration.
Installation
composer require athwari/laravel-odoo-api-odoo-api
Publish the config:
php artisan vendor:publish --tag=odoo-api-config
Configuration
.env keys:
ODOO_DATABASE=mycompany ODOO_HOST=https://mycompany.odoo.com ODOO_USERNAME=admin@mycompany.com ODOO_PASSWORD=secret # Optional: API key instead of password (takes precedence when set, Odoo 14+) ODOO_API_KEY= # Optional: skip the authenticate() RPC call with a known static UID ODOO_FIXED_USER_ID= ODOO_TIMEOUT=30 # SSL certificate verification. Set to false ONLY for local dev with # self-signed certificates — never disable in production. ODOO_SSL_VERIFY=true ODOO_LANG=en_US ODOO_TIMEZONE=UTC ODOO_COMPANY_ID=
Basic usage
use Athwari\laravel-odoo-apiOdooApi\Odoo; $odoo = app(Odoo::class); // resolved from the container in laravel-odoo-api $partners = $odoo->model('res.partner') ->where('active', '=', true) ->orderBy('name') ->limit(20) ->get(); $id = $odoo->create('res.partner', ['name' => 'Acme Corp']); $odoo->model('res.partner') ->where('id', '=', $id) ->write(['phone' => '+1-555-0100']);
Or via the Facade:
use Athwari\laravel-odoo-apiOdooApi\Facades\Odoo; Odoo::model('res.partner')->where('active', '=', true)->get();
Custom / arbitrary Odoo methods
$odoo->executeKw('sale.order', 'action_confirm', [[$orderId]]);
Unscoped update/delete protection
// Throws ValidationException — no where() means "every record in the model". $odoo->model('res.partner')->delete(); // Correct: $odoo->model('res.partner')->where('active', '=', false)->delete();
If you genuinely need to operate on all records, pass explicit IDs to the
underlying endpoint methods ($odoo->unlink('res.partner', $ids)), which
are not subject to this guard.
Models
use Athwari\laravel-odoo-apiOdooApi\Attributes\BelongsTo; use Athwari\laravel-odoo-apiOdooApi\Attributes\Field; use Athwari\laravel-odoo-apiOdooApi\Attributes\HasMany; use Athwari\laravel-odoo-apiOdooApi\Attributes\Key; use Athwari\laravel-odoo-apiOdooApi\Attributes\Model; use Athwari\laravel-odoo-apiOdooApi\Odoo\Models\LazyHasMany; use Athwari\laravel-odoo-apiOdooApi\Odoo\OdooModel; #[Model('res.partner')] class Partner extends OdooModel { #[Field] public string $name; #[Field('email')] public ?string $email; #[Field('parent_id'), Key] public ?int $parentId; // BelongsTo resolves the related model eagerly at hydration time. #[Field('parent_id')] #[BelongsTo('parent_id', Partner::class)] public ?Partner $parent; // HasMany loads related records lazily on first access. #[Field('child_ids')] #[HasMany(Partner::class, 'child_ids')] public LazyHasMany $children; }
$partner = Partner::find(42); $partner->parent?->name; // eager BelongsTo count($partner->children); // lazy HasMany — fetched on first access $partner->children->isLoaded(); // bool $partner->children->reload(); // force re-fetch next access $matches = Partner::query()->where('active', '=', true)->get(); $first = Partner::query()->where('name', '=', 'Acme')->first(); $partner = new Partner(); $partner->name = 'New Co'; $partner->save(); // creates; $partner->id is set after $partner->name = 'Renamed Co'; $partner->save(); // updates
OdooModel::boot($odoo) binds the Odoo client used by all model subclasses.
The service provider calls this automatically in laravel-odoo-api. For standalone use:
$odoo = new Odoo(new Config($db, $host, $user, $pass)); OdooModel::boot($odoo);
BelongsTo and recursion: eager resolution is capped at a depth of 3 for
self-referential/cyclic relations (e.g. Partner → parent Partner). If you need
to walk a deep hierarchy, do it with explicit find() calls.
Casts
Cast Odoo's raw field values to and from PHP types:
use Athwari\laravel-odoo-apiOdooApi\Odoo\Casts\DateTimeCast; use Athwari\laravel-odoo-apiOdooApi\Odoo\Casts\DateTimeImmutableCast; // Basic UTC datetime cast Odoo::registerCast(new DateTimeCast()); // DateTime shifted to a specific timezone on read Odoo::registerCast(new DateTimeCast('Europe/Berlin')); Odoo::registerCast(new DateTimeCast(new DateTimeZone('Asia/Dubai'))); // Immutable variant (DateTimeImmutable instead of DateTime) Odoo::registerCast(new DateTimeImmutableCast()); Odoo::registerCast(new DateTimeImmutableCast('America/New_York'));
Once registered, the cast is applied automatically to every model property
type-hinted with the matching PHP type. Register casts before first use —
typically in a service provider's boot() method.
Custom casts
use Athwari\laravel-odoo-apiOdooApi\Odoo\Casts\Cast; class MoneyCast extends Cast { public function getType(): string { return Money::class; } public function cast(mixed $raw): ?Money { return $raw ? new Money($raw) : null; } public function uncast(mixed $value): mixed { return $value instanceof Money ? $value->amount : $value; } } Odoo::registerCast(new MoneyCast());
Testing
composer test
To generate code coverage, Xdebug must be enabled for CLI. Run:
composer test-coverage
If Xdebug is installed but coverage still fails, ensure CLI mode is enabled:
php -d xdebug.mode=coverage vendor/bin/pest --coverage
The suite is fully offline — no Odoo instance is required. HTTP responses
are stubbed via Guzzle MockHandler injected through Endpoint::setClient()
and Odoo::setObjectEndpoint().
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-24