| Component | 1.x | 2.0 |
|---|---|---|
| PHP | >=8.1 |
>=8.2 |
| Symfony | ^5.4 || ^6.0 |
^6.4 || ^7.4 |
| Sylius | ^1.0 |
^2.0 |
| Doctrine ORM | ^2.7 |
^3.0 |
| Package | Replacement |
|---|---|
friendsofsymfony/rest-bundle |
symfony/http-foundation (a plain JsonResponse) |
doctrine/event-manager |
Pulled transitively by Doctrine ORM 3 |
behat/transliterator |
Removed along with CachedProvider |
psr/cache, symfony/cache |
Removed along with CachedProvider |
symfony/messenger |
Removed along with LoadPickupPointsHandler |
symfony/console |
Removed along with LoadPickupPointsCommand |
sylius/resource-bundle |
Removed (no plugin-owned resource anymore) |
The plugin no longer depends on FOSRestBundle, JMS Serializer or the Symfony
Serializer. A single shop endpoint (PickupPointsAction) returns a plain
JsonResponse built directly: a map of shipping-method code → that method's
pickup points for the current cart. Each point carries display fields (name,
address, zipCode, city, latitude, longitude) plus a value token —
the whole point, base64url-encoded by PickupPointEncoder. The shipping page
fetches this asynchronously, after it has rendered (so a slow or down carrier
API never blocks the page), and the framework-free shop JS — a native ES module
(public/js/setono-pickup-point.js, loaded with <script type="module">) — builds
the chooser by cloning overridable Twig <template>s from
_pickup_point_templates.html.twig. It is extensible without forking: subclass the
exported PickupPointChooser, listen for the setono:pickup-point(s):* CustomEvents,
or set window.setonoSyliusPickupPointConfig — see docs/customizing-the-chooser.md.
The plugin moved from src/Resources/** to repo-root locations
(matches Sylius 2.x conventions / setono/sylius-plugin-skeleton):
| 1.x path | 2.0 path |
|---|---|
src/Resources/config/ |
config/ |
src/Resources/config/services/*.xml |
config/services/*.php (PHP DSL) |
src/Resources/config/services/providers/*.xml |
config/services/providers/*.php |
src/Resources/config/routing.yaml |
config/routes.yaml (imports config/routes/shop.yaml) |
src/Resources/config/routing_non_localized.yaml |
config/routes_no_locale.yaml |
src/Resources/config/doctrine/ |
(removed — no plugin-owned doctrine resource) |
src/Resources/config/validation/ |
config/validation/ |
src/Resources/config/routes/ |
config/routes/ |
src/Resources/config/app/config.yaml |
(removed — inlined via Extension::prepend()) |
src/Resources/config/app/fixtures.yaml |
(removed — example data, copy into your test app if needed) |
src/Resources/config/serializer/PickupPoint.yml |
(removed — the DTO has no serializer metadata; the endpoint builds its JSON directly) |
src/Resources/translations/ |
translations/ |
src/Resources/views/ |
templates/ |
src/Resources/public/ |
public/ |
Update any @SetonoSyliusPickupPointPlugin/Resources/... references in your
own templates and config to drop the Resources/ segment.
The routing now follows the setono/sylius-plugin-skeleton layout: a top-level
config/routes.yaml (localized, prefixed with /{_locale}) delegates to the
per-section files under config/routes/ (config/routes/shop.yaml). A
config/routes_no_locale.yaml variant is provided for stores with localized
URLs disabled.
# config/routes/setono_sylius_pickup_point.yaml
setono_sylius_pickup_point:
resource: "@SetonoSyliusPickupPointPlugin/config/routes.yaml"Previously: @SetonoSyliusPickupPointPlugin/Resources/config/routing.yaml.
The plugin now owns a single shop route:
setono_sylius_pickup_point_shop_pickup_points→/{_locale}/pickup-points— returns the pickup points of every pickup-capable shipping method for the current cart, keyed by method code (fetched asynchronously by the shop JS).
The two 1.x/early-2.x AJAX routes
(…_ajax_pickup_points_search_by_cart_address → /ajax/pickup-points/from-cart
and …_ajax_pickup_point_by_identifier → /ajax/pickup-points/from-identifier)
are gone. Drop any custom links or fetch calls to those URLs.
The plugin now wires its layout JS snippet and the pickup-point shipment label
automatically via sylius_twig_hooks. Consumers no longer need to:
- include
@SetonoSyliusPickupPointPlugin/_javascripts.html.twigmanually inlayout.html.twig; the plugin attaches it tosylius_shop.base#javascripts(the chooser is shop-only, so it is no longer attached to the admin layout). - include
@SetonoSyliusPickupPointPlugin/shop/label/shipment/pickupPoint.html.twigin admin order-show templates; the plugin attaches it tosylius_admin.order.show.content.sections.shipments.item.
Drop the matching {% include … pickupPoint.html.twig %} blocks from your
custom admin templates if you copied them from the 1.x README.
Services owned by the plugin now use FQCN service IDs (Sylius 2.x convention). Examples:
| 1.x ID | 2.0 ID |
|---|---|
setono_sylius_pickup_point.command.load_pickup_points |
(removed — see "Removed: local snapshot and message bus") |
setono_sylius_pickup_point.controller.action.pickup_point_by_id |
(removed — the chosen point is now self-contained; there is no per-identifier lookup) |
setono_sylius_pickup_point.controller.action.pickup_points_search_by_cart_address |
Setono\SyliusPickupPointPlugin\Controller\Action\PickupPointsAction (now returns every method's points in one call) |
setono_sylius_pickup_point.message.handler.load_pickup_points |
(removed — see "Removed: local snapshot and message bus") |
setono_sylius_pickup_point.validator.has_pickup_point_selected |
Setono\SyliusPickupPointPlugin\Validator\Constraints\HasPickupPointSelectedValidator |
setono_sylius_pickup_point.fixture.shipping_method |
Setono\SyliusPickupPointPlugin\Fixture\ShippingMethodFixture |
setono_sylius_pickup_point.fixture.example_factory.shipping_method |
Setono\SyliusPickupPointPlugin\Fixture\Factory\ShippingMethodExampleFactory |
setono_sylius_pickup_point.shipping.order_shipping_method_selection_requirement_checker |
Setono\SyliusPickupPointPlugin\Shipping\OrderShippingMethodSelectionRequirementChecker |
setono_sylius_pickup_point.block_event_listener.javascript |
(removed — JS layout snippet now wired through sylius_twig_hooks) |
setono_sylius_pickup_point.repository.pickup_point |
(removed — see "Removed: local snapshot and message bus") |
These IDs are still kept (compiler pass and bundle config reference them):
setono_sylius_pickup_point.registry.providersetono_sylius_pickup_point.provider.*(per-provider services taggedsetono_sylius_pickup_point.provider)
The opt-in PSR-cache decorator (Setono\SyliusPickupPointPlugin\Provider\CachedProvider)
has been removed in 2.0 along with the setono_sylius_pickup_point.cache configuration
key and the psr/cache / symfony/cache runtime dependencies. Pickup-point lookups
are now served directly by each provider. Drop the following from your application
configuration:
# Remove this — no longer supported
setono_sylius_pickup_point:
cache:
enabled: true
pool: setono_sylius_pickup_point.provider_cache_pool
framework:
cache:
pools:
setono_sylius_pickup_point.provider_cache_pool: ~The LocalProvider decorator (which fell back to a local DB snapshot of pickup
points when a third-party API timed out) has been removed in 2.0 along with the
infrastructure that populated that snapshot. Specifically the following have all
been removed:
Setono\SyliusPickupPointPlugin\Provider\LocalProviderSetono\SyliusPickupPointPlugin\Command\LoadPickupPointsCommandand thesetono-sylius-pickup-point:load-pickup-pointsconsole commandSetono\SyliusPickupPointPlugin\Message\Command\LoadPickupPoints/Setono\SyliusPickupPointPlugin\Message\Handler\LoadPickupPointsHandlerand thesetono_sylius_pickup_point.command_busmessenger busSetono\SyliusPickupPointPlugin\Doctrine\ORM\PickupPointRepositoryandSetono\SyliusPickupPointPlugin\Repository\PickupPointRepositoryInterfaceSetono\SyliusPickupPointPlugin\EventListener\AddIndicesSubscriberSetono\SyliusPickupPointPlugin\Exception\TimeoutException- The plugin-owned
PickupPointDoctrine resource and its tables (setono_sylius_pickup_point__pickup_point/..._pickup_point_code) - The
setono_sylius_pickup_point.localconfig key
Drop the following from your application configuration:
# Remove this — no longer supported
setono_sylius_pickup_point:
local: trueGenerate a migration with bin/console doctrine:migrations:diff to drop the
two plugin-owned tables. Each provider still implements findPickupPoints()
and findPickupPoint() directly against the carrier API.
Setono\SyliusPickupPointPlugin\Provider\ProviderInterface::findAllPickupPoints()
was the entry point used by the now-removed LoadPickupPointsHandler. Since
nothing in the plugin calls it anymore, it has been dropped from the interface
and from every shipped provider implementation. Custom providers that still
declare it should remove the method to match the interface.
Setono\SyliusPickupPointPlugin\Model\PickupPoint,
Setono\SyliusPickupPointPlugin\Model\PickupPointInterface and
Setono\SyliusPickupPointPlugin\Model\PickupPointCode are removed. The
replacement is Setono\SyliusPickupPointPlugin\DTO\PickupPoint — a final
class with public properties (scalars plus an open metadata map) and
fromArray() / jsonSerialize() helpers, but no #[Groups] /
#[SerializedName] attributes and no Sylius resource behaviour. It's populated
from the carrier API response by each provider, and emitted (with its
identifier token) by the AJAX endpoints.
The PickupPointCode value object has been inlined as plain provider,
id and country properties on the DTO, and the old provider---id---country
wire-format string is gone.
The checkout no longer round-trips a point identifier. Each pickup point in
the AJAX response carries a value token produced by
Setono\SyliusPickupPointPlugin\Encoder\PickupPointEncoder — base64url-encoded
JSON of the whole DTO. The shop JS uses that token as the chosen radio's value
and writes it into the hidden input; on submit
Setono\SyliusPickupPointPlugin\Form\DataTransformer\PickupPointTransformer
decodes it straight back into the PickupPoint. Nothing is re-resolved through
the provider, so a slow or down carrier never blocks the submit and the
persisted point is exactly what the shopper saw.
PickupPointIdentifier and PickupPointIdentifierEncoder still exist — they
back the findPickupPoint() metadata contract below — but no longer carry the
checkout's form value.
Provider implementations now resolve a point from its id plus an open metadata map (into which the well-known country is folded):
public function findPickupPoint(string $id, array $metadata = []): ?PickupPoint;Consumers that hand-built or type-hinted PickupPointInterface should
switch to the new DTO and replace setter calls with direct property
assignment:
// 1.x / early 2.x
$pickupPoint = new \Setono\SyliusPickupPointPlugin\Model\PickupPoint();
$pickupPoint->setCode(new \Setono\SyliusPickupPointPlugin\Model\PickupPointCode('abc', 'gls', 'DK'));
$pickupPoint->setName('Aalborg Centrum');
// 2.x
$pickupPoint = new \Setono\SyliusPickupPointPlugin\DTO\PickupPoint();
$pickupPoint->provider = 'gls';
$pickupPoint->id = 'abc';
$pickupPoint->country = 'DK';
$pickupPoint->name = 'Aalborg Centrum';PickupPointAwareInterface (and PickupPointAwareTrait) gained a new
pickup_point JSON column / ?PickupPoint $pickupPoint accessor. The
existing pickupPointId API stays for backwards compatibility but is now
deprecated:
| Deprecated (1.x / early 2.x) | 2.x replacement |
|---|---|
hasPickupPointId(): bool |
hasPickupPoint(): bool |
setPickupPointId(?string $pickupPointId) |
setPickupPoint(?\Setono\SyliusPickupPointPlugin\DTO\PickupPoint $pickupPoint) |
getPickupPointId(): ?string |
getPickupPoint(): ?\Setono\SyliusPickupPointPlugin\DTO\PickupPoint |
column pickup_point_id (STRING) |
column pickup_point (JSON) |
The trait ships both columns side-by-side. As of 2.0 the plugin reads
and writes only the new pickup_point JSON column: the checkout form
resolves the selected point and stores the full DTO, and the shipment label
template renders shipment.pickupPoint directly. The legacy
pickup_point_id string column is kept only for backwards compatibility and
is never written anymore. Migrate your data in two moves: (1) backfill the
JSON column from the legacy string, (2) when you're ready, drop the legacy
column and stop using the deprecated methods.
Doctrine migrations live in your application, not in this plugin. Below
is a Doctrine Migrations class that handles step (1) — it adds the
pickup_point JSON column (the trait expects it) and populates it from
the legacy pickup_point_id strings, splitting on the --- delimiter.
The table name follows whatever entity uses PickupPointAwareTrait — by
convention sylius_shipment for a Shipment customisation. Adjust both
the table name and the SQL dialect to match your setup.
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260520000000BackfillPickupPointJson extends AbstractMigration
{
public function getDescription(): string
{
return 'Backfill pickup_point JSON column from legacy pickup_point_id strings';
}
public function up(Schema $schema): void
{
// 1. Add the new JSON column (skip this statement if a schema diff
// already created it via PickupPointAwareTrait's #[ORM\Column]).
$this->addSql('ALTER TABLE sylius_shipment ADD pickup_point JSON DEFAULT NULL');
// 2. Split "<provider>---<id>---<country>" into a JSON object.
// MySQL / MariaDB:
$this->addSql(<<<'SQL'
UPDATE sylius_shipment
SET pickup_point = JSON_OBJECT(
'provider', SUBSTRING_INDEX(pickup_point_id, '---', 1),
'id', SUBSTRING_INDEX(SUBSTRING_INDEX(pickup_point_id, '---', 2), '---', -1),
'country', SUBSTRING_INDEX(pickup_point_id, '---', -1)
)
WHERE pickup_point_id IS NOT NULL
AND pickup_point IS NULL
SQL);
// PostgreSQL equivalent (use one or the other, not both):
//
// $this->addSql(<<<'SQL'
// UPDATE sylius_shipment
// SET pickup_point = jsonb_build_object(
// 'provider', split_part(pickup_point_id, '---', 1),
// 'id', split_part(pickup_point_id, '---', 2),
// 'country', split_part(pickup_point_id, '---', 3)
// )
// WHERE pickup_point_id IS NOT NULL
// AND pickup_point IS NULL
// SQL);
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE sylius_shipment DROP pickup_point');
}
}The backfill only fills in provider, id and country — the only data
present in the legacy string. The remaining DTO fields (name,
address, zipCode, city, latitude, longitude) stay null until
the next time a fresh pickup point is selected. If you need them
populated for historical orders, run an additional pass that fetches each
shipment through the provider registry and re-stores the full DTO.
Once your reads are switched to getPickupPoint(), a follow-up migration
can drop the legacy column:
$this->addSql('ALTER TABLE sylius_shipment DROP pickup_point_id');The traits PickupPointAwareTrait and PickupPointProviderAwareTrait now use
PHP 8 attribute mappings (#[ORM\Column]) instead of PHPDoc annotations.
Doctrine ORM 3 silently ignores PHPDoc-mapped associations, so any class that
re-declares these columns via PHPDoc on the consumer side must be converted to
attributes.
The third-party carrier bundles (setono/dao-bundle,
setono/gls-webservice-bundle, setono/post-nord-bundle) moved from
require-dev to suggest. Each provider is enabled only when:
- The matching bundle is installed in your application.
- The provider is set to
truein your plugin configuration.
The plugin runtime continues to throw a configuration error if you enable a provider without the matching bundle.
The Budbee (Setono\SyliusPickupPointPlugin\Provider\BudbeeProvider) and
CoolRunner (Setono\SyliusPickupPointPlugin\Provider\CoolRunnerProvider)
providers — along with their service definitions and configuration nodes
— have been removed in 2.0. If you depended on either, switch to one of
the remaining providers (DAO, GLS, PostNord, Faker) or implement your own
ProviderInterface and tag it with setono_sylius_pickup_point.provider.
Drop these keys from your application configuration:
# Remove these — no longer supported
setono_sylius_pickup_point:
providers:
budbee: true
coolrunner: truephpspec/phpspec,phpspec/prophecy-phpunit(old)psalm/*,weirdan/doctrine-psalm-pluginsetono/code-quality-pack,setono/sylius-behat-packbehat/behatjms/serializer-bundle,kriswallsmith/buzz,nyholm/psr7polishsymfonycommunity/symfony-mocker-containermatthiasnoback/symfony-config-test
All testing now uses PHPUnit + Prophecy via setono/sylius-plugin: ^2.0
which bundles PHPStan, PHPUnit, Rector, ECS and CI composite actions.
No keys were removed. The async chooser adds three UI strings under
setono_sylius_pickup_point.ui — loading_pickup_points, no_pickup_points
and error_loading_pickup_points (its loading/empty/error states). The bundled
en and da catalogs cover them; translate them if you ship other locales.