baks-dev/avito-products
Avito product module for BaksDev: install via Composer, run grouped PHPUnit tests, and manage Avito catalog products within your Laravel/PHP application. Requires PHP 8.4+, MIT licensed.
This is a Symfony bundle from the BaksDev platform, not a Laravel package. composer require gets the code onto disk; it does not make it boot in a Laravel app. The README is a single install line, so your first real step is reading the source:
composer require baks-dev/avito-products
composer show baks-dev/avito-products # read the requires block first
ls vendor/baks-dev/avito-products/src # Bundle class, DI config, entities, DTOs, repositories
cat vendor/baks-dev/avito-products/composer.json
Look in this order:
src/*Bundle.php (or *Extension.php) — what gets registered and what services are exposed.src/Resources/config/ — Symfony DI service definitions; this is your de-facto API map (class names, constructor dependencies, tags).src/Entity/ and src/DTO/ — the data shapes for an Avito product.src/Repository/, src/Client/, src/Message/ (whichever exist) — where the actual Avito API/DB interaction lives.tests/ — the only executable documentation in the repo; run it in a checkout of the package, not in your Laravel app:git clone https://github.com/baks-dev/avito-products && cd avito-products
composer install
php bin/phpunit --group=avito-products
Prerequisites you must verify before committing: PHP 8.4+ (so Laravel 11/12, not Laravel 10), baks-dev/core:^7.x, and whatever Doctrine/Symfony components the module drags in. If composer why-not laravel/framework shows conflicts, stop here.
First use case: do not try to wire the bundle into Laravel's container. Instead pick the integration mode up front:
Http client, and use this repo's src/ purely as a reference for payload shapes and edge cases.A concrete first milestone: take one Avito product payload from tests/, define a matching Eloquent model/migration, and get a queued sync job running against Avito's sandbox — regardless of which mode you chose. That validates auth and payload shape before you invest in bridging.
Mode A — service isolation (cleanest fit). Keep the Symfony stack out of your Laravel app entirely:
// Laravel side: a thin client around your BaksDev service
class AvitoBridge
{
public function __construct(private Http $http) {}
public function product(int $avitoId): array
{
return $this->http->baseUrl(config('services.avito_bridge.url'))
->withToken(config('services.avito_bridge.token'))
->get("/products/{$avitoId}")
->throw()
->json();
}
}
Wrap calls in a queued job so a slow Avito response never blocks a request.
Mode B — provider bridge for framework-free pieces. If the DTOs/mappers are plain PHP classes, bind them yourself:
// app/Providers/AvitoProductsServiceProvider.php
public function register(): void
{
$this->app->bind(
\BaksDev\AvitoProducts\Product\ProductMapper::class, // confirm the real FQCN in src/
fn () => new \BaksDev\AvitoProducts\Product\ProductMapper()
);
}
public function boot(): void
{
// Do NOT call $this->loadMigrationsFrom(...) on Doctrine entities.
// Mirror Avito product fields into your own Eloquent migration instead.
}
Then translate the package DTO into your model:
$dto = app(ProductMapper::class)->map($avitoPayload);
Product::updateOrCreate(
['avito_id' => $dto->getId()],
['title' => $dto->getTitle(), 'price' => $dto->getPrice(), 'status' => $dto->getStatus()],
);
Mode C — HTTP-native client. If the package adds no logic beyond request/response shapes, mirror it:
class AvitoClient
{
public function __construct(private Http $http) {}
public function products(array $filters = []): array
{
return $this->http->baseUrl('https://api.avito.ru')
->withToken(Cache::remember('avito_token', 3500, fn () => $this->token()))
->get('/autoload/v2/items', $filters)
->throw()
->json('resources', []);
}
}
Sync workflow (all modes).
SyncAvitoProducts to a queue.SyncAvitoProduct per ID.failed_jobs with the raw Avito error.json column for debugging — you will need it when field mappings drift.Configuration. There is no Laravel vendor:publish tag here. Put credentials in .env and expose them through config/services.php, then map to whatever Symfony parameters the bundle expects (AVITO_CLIENT_ID, AVITO_CLIENT_SECRET) only in the isolated service:
// config/services.php
'avito' => [
'client_id' => env('AVITO_CLIENT_ID'),
'client_secret' => env('AVITO_CLIENT_SECRET'),
'account_id' => env('AVITO_ACCOUNT_ID'),
],
Testing. Use the package's tests/ as a behaviour spec even if you never run the bundle — copy representative payloads into your own fixtures and assert your mapper handles them. Mock the HTTP boundary, not the package:
Http::fake(['api.avito.ru/*' => Http::response(['resources' => []], 200)]);
AvitoProducts::products() style pseudo-API you have seen elsewhere as unverified until you grep the actual src/.extra.laravel in composer.json; a Symfony bundle declares extra.symfony (flex recipe). The package will be installed and completely inert in a Laravel app. There is no facade, no publish tag, no Eloquent trait.baks-dev/core is a platform, not a helper library. It will pull Doctrine and Symfony components. Check composer why-not before installing and expect psr/*, symfony/*, and Doctrine version constraints to be the flashpoints.loadMigrationsFrom() Doctrine metadata. Mirror the fields into Eloquent tables and treat the entities purely as a field reference.composer install fails before you see any code.v7.4.x. Pin an exact version ("baks-dev/avito-products": "7.4.15") and diff src/ between bumps; there is no changelog to rely on.throttle middleware or RateLimiter::for('avito'), and handle 429 by releasing the job back onto the queue with delay rather than sleep() in a worker.Http::withMiddleware() tap or a global client macro; without it a mapping failure is invisible.src/. Prefer decorating an interface (bind your class in a Laravel provider) over editing vendor code. If the class you need to change is final or has a hardcoded client, that is your signal to switch to Mode C.How can I help you explore Laravel packages today?