Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Prestashop Webservice Bundle Laravel Package

iq2i/prestashop-webservice-bundle

A Symfony bundle that provides a simple client for the PrestaShop Webservice API, letting you query and manage shops, products, orders, customers, and other resources from your Symfony application without writing raw HTTP requests.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: this is a Symfony bundle, not a Laravel package. Laravel does not have a bundle/kernel registration mechanism, so composer require iq2i/prestashop-webservice-bundle will pull in code you cannot boot the normal way. Treat the bundle as documentation of intent — a thin DI wrapper around PrestaShop's official PSWebServiceLibrary — and use the underlying library directly.

Minimal steps:

  1. Require the actual dependency, not the bundle:
    composer require prestashop/prestashop-webservice-lib
    
    If that package name doesn't resolve, grab the single-file PSWebServiceLibrary.php from PrestaShop's /webservice docs and drop it in app/Support/PrestaShop/.
  2. Configure credentials in config/services.php:
    'prestashop' => [
        'url'    => env('PS_SHOP_URL'),   // https://shop.example.com/
        'key'    => env('PS_WS_KEY'),
        'debug'  => env('APP_DEBUG', false),
    ],
    
    The WS key is generated in PrestaShop admin under Advanced Parameters → Webservice, per-key with per-resource permissions.
  3. Read the bundle's Resources/config/services.xml (or services.yml) once. It shows you exactly which parameters the bundle injects into the client — shop URL, key, debug flag — and that's the shape of the singleton you want to bind in a Laravel ServiceProvider.
  4. First use case: read-only order import. Fetch /api/orders?date=1&filter[date_upd]=[2024-01-01]&display=full, hydrate into your own orders table. Read-only is the safest way to prove connectivity, key scoping, and XML parsing before you attempt writes.

Implementation Patterns

Bind the client as a singleton. The library is a plain PHP object holding a cURL handle; recreating it per call wastes connections and complicates timeouts.

$this->app->singleton(\PrestaShopWebService::class, fn () => new \PrestaShopWebService(
    config('services.prestashop.url'),
    config('services.prestashop.key'),
    config('services.prestashop.debug')
));

Write a per-resource repository, not a god-service. One class per WS resource (ProductRepository, OrderRepository, StockRepository) wrapping the same client:

class ProductRepository
{
    public function __construct(private \PrestaShopWebService $ws) {}

    public function paginate(int $offset, int $limit, string $display = 'full')
    {
        return $this->ws->get([
            'resource' => 'products',
            'display'  => $display,
            'limit'    => "$offset,$limit",
            'sort'     => 'id_ASC',
        ]);
    }

    public function find(int $id) { /* resource + id */ }
    public function create(\SimpleXMLElement $xml) { /* ->add(['postXml' => $xml->asXML()]) */ }
    public function update(\SimpleXMLElement $xml) { /* ->edit([...]) */ }
}

Use the "blank schema" trick for writes. Never hand-craft XML from memory; PrestaShop tells you the exact node shape:

$blank = $ws->get(['url' => $url . '/api/products?schema=blank']);
$xml = $blank->product;
$xml->price = '19.99';
$xml->name->language[0] = 'Widget';        // multilingual: one node per lang id
$xml->name->language[0]['id'] = 1;
$xml->associations->categories->category->id = 2;
$ws->add(['resource' => 'products', 'postXml' => $xml->asXML()]);

Sync via queued jobs, one job per resource page. Long display=full fetches over a large catalogue will blow PHP's memory and hit the WS timeout. Chunk with limit=0,100, dispatch SyncProductsPage per offset, and use filter[date_upd]=[last_sync_at] for incrementals. Store last_sync_at per resource in a sync_checkpoints table.

Stock updates are the killer feature. For a Laravel storefront or ERP pushing stock into PrestaShop, the pattern is: stock_availables?filter[id_product]=[...], then edit with the quantity field only — but read the resource first, because PrestaShop silently discards partial XML if required nodes are missing.

Normalize on the way out. The library returns SimpleXMLElement, not arrays, and multilingual fields are nested by language id. Hydrate into DTOs or Eloquent models at the repository boundary; do not let SimpleXMLElement leak into controllers or jobs.

Gotchas and Tips

  • The bundle is archived. No PHP 8.x fixes, no security patches, no Symfony 6+ DI compatibility. Even if you were on Symfony, you'd be pinning old versions. Do not build new work on it; copy its service wiring into a Laravel provider instead.
  • GPL-2.0 is a real concern. A GPL-2.0 bundle in a proprietary Laravel app is a licensing question, not just a technical one. If you vendor this code, review with whoever owns your licensing. The underlying PrestaShop library itself has more permissive terms (MIT-ish / OSL depending on version) — prefer it.
  • XML only. There is no JSON endpoint. Everything is SimpleXMLElement, so ->asXML() before postXml, and (string) $node before casting to int/float.
  • display=full is expensive. Use narrowed displays where the PrestaShop version supports them: display=[id,name,price]. On PS 1.6 and older this syntax is unreliable — test against your shop's exact version before relying on it.
  • Default limit is tiny. Unset limit returns a small first page (10). Always pass limit=0,100 (or your chunk size) explicitly; otherwise you'll silently sync a fraction of the catalogue and wonder why.
  • Filter syntax is picky. filter[id]=[1|2|3] for OR, filter[date_upd]=>[2024-01-01] for ranges, date=1 to force date-typed comparisons. URL-encoding matters; let the client handle it or build the query string with http_build_query and PHP_QUERY_RFC3986.
  • Multilingual fields require explicit language ids. If you set $xml->name->language[0] without ['id'], PrestaShop may drop it or attach it to the wrong language. Map your languages in a config array, not magic indexes.
  • Errors are frequently HTML, not XML. PrestaShop often returns a 500 with an HTML error page when an override or module breaks the WS. The library throws PrestaShopWebserviceException — log the full response body alongside the HTTP status, or you'll debug blind.
  • WS key scoping fails as 401/403/404, not as a clear permission message. A 404 on products usually means the resource isn't enabled on the key, not that the product is missing. Check the key's resource list first before chasing code.
  • Associations are separate calls. Updating a product does not update its images, combinations, or stock — those are images/products/{id}, combinations, stock_availables. Plan your sync jobs as a graph, not a single fetch.
  • Reuse the cURL handle. One long-lived client per process; if you fan out into parallel jobs, respect PrestaShop's per-key rate limiting (it's low, and 429s are not always clearly surfaced). Add sleep() between pages in bulk syncs.
  • Extension point that actually matters: the bundle's only real value is the DI abstraction. Replicate it as a PrestaShopClient interface in your app so tests can swap in a fake repo — otherwise every unit test needs a live shop, which you don't have.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin