agentsclimarketplace

Implement cqrs handlers

Skill jeffsenso/prestashop-skills/skills/prestashop-module-development/ps9-core-ai/Component/CQRS/skills/implement-cqrs-handlers

Prestashop Developer Skills

Install
npx -y skills add jeffsenso/prestashop-skills --skill implement-cqrs-handlers

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Implement all command and query handlers in the Adapter layer. Each handler delegates to the repository for persistence — no direct SQL or ObjectModel access. Handlers use #[AsCommandHandler] / #[AsQueryHandler] attributes for auto-registration. Trigger: "implement handlers for {Domain}".

SKILL.md

4.6 KB, as published. Nobody here has run it

implement-cqrs-handlers

Handlers live in src/Adapter/{Domain}/CommandHandler/ and QueryHandler/. See CQRS/CONTEXT.md for conventions (#[AsCommandHandler]/#[AsQueryHandler] attributes, no cross-handler calls, return types).

1. Add handler

Add{Domain}Handler.php implementing Add{Domain}HandlerInterface:

  • Inject {Domain}Repository
  • handle(Add{Domain}Command $command): {Domain}Id:
    • Construct the ObjectModel entity from command data
    • For multilingual fields, map $command->getLocalizedNames() to the lang array
    • Call $this->repository->create(...)
    • Return the new {Domain}Id
  • Catch persistence exceptions, rethrow as domain exceptions

Reference: src/Adapter/Tax/CommandHandler/AddTaxHandler.php (simple), src/Adapter/Manufacturer/CommandHandler/AddManufacturerHandler.php (with image)

2. Edit handler (partial-update)

Edit{Domain}Handler.php implementing Edit{Domain}HandlerInterface:

  • Load entity: $entity = $this->repository->get{Domain}($command->getId())
  • For each field: if ($command->getName() !== null) { $entity->name = $command->getName(); }
  • Apply only non-null fields — never overwrite with null
  • Call $this->repository->update($entity)
  • Sub-resource commands are dispatched independently, not composed here

Reference: src/Adapter/Tax/CommandHandler/EditTaxHandler.php (simple), src/Adapter/Carrier/CommandHandler/EditCarrierHandler.php (many fields)

3. Delete handler

Delete{Domain}Handler.php implementing Delete{Domain}HandlerInterface:

  • Load entity to verify existence (throws {Domain}NotFoundException)
  • Check business constraints: if entity is referenced by active orders/other entities, throw CannotDelete{Domain}Exception
  • Call $this->repository->delete($command->getId())

4. Toggle status handler

Toggle{Domain}StatusHandler.php:

  • Load entity by ID
  • Flip: $entity->active = !$entity->active
  • Call repository update
  • Return void — the controller reads back state from the grid

5. Sub-resource handler (if sub-resources exist)

Set{Domain}{SubResource}sHandler.php:

Two strategies depending on complexity:

Strategy A: Atomic replace (simpler, quicker)

Used when sub-resources have no identity of their own or when maintaining existing rows isn't important:

  • Begin a DB transaction
  • Delete all existing sub-resource rows for the entity
  • Insert new rows from $command->getItems()
  • Commit; on failure, rollback and throw domain exception
  • Empty array = delete all (valid use case)

Reference: src/Adapter/Carrier/CommandHandler/SetCarrierRangesHandler.php

Strategy B: Incremental update (cleaner, preserves existing sub-resources)

Preferred when sub-resources have their own identity or when preserving existing rows matters (e.g., to keep audit trails, auto-increment IDs, or related data):

  • Load existing sub-resources for the entity
  • Compare with the new collection: identify additions, updates, and removals
  • Apply only the necessary changes (insert new, update changed, delete removed)
  • Wrap in a transaction

Choose Strategy B when possible for cleaner data management. Use Strategy A when sub-resources are simple value-like collections without individual identity.

6. Get-for-editing handler

Get{Domain}ForEditingHandler.php in QueryHandler/:

  • Load entity via repository
  • Map ALL fields to the return DTO: scalars, multilingual (array keyed by langId), related IDs
  • Return typed Editable{Domain} DTO (with scalar types only — no VOs in the DTO)
  • No write side effects

Reference: src/Adapter/Tax/QueryHandler/GetTaxForEditingHandler.php (simple)

7. List query handler (if explicit query exists)

Most domains use the grid QueryBuilder pattern — no handler needed. Only create if the domain uses an explicit Get{Domain}sForListing query class.

Rules

Conventions (attributes, no SQL, no cross-handler calls, return types) are in CQRS/CONTEXT.md. Skill-specific reminders:

  • Check null before every field update in Edit handler (partial-update pattern)
  • Always verify existence before deletion — never delete blindly

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.