Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/thelia/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "thelia",
"description": "Develop Thelia 3 with Claude Code: skills and agents for modules, Propel ORM, the API Platform bridge, the Flexy front-office, the default-twig back-office, and Thelia 2 to 3 migration.",
"version": "0.2.0",
"version": "0.3.0",
"author": {
"name": "Thelia"
},
Expand Down
21 changes: 12 additions & 9 deletions plugins/thelia/skills/fresh-install-test/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ description: >
Validates a fresh Thelia 3 install from an empty directory and empty database.
Use after a version bump, a merge, or any change to bin/install, bin/test-prepare,
bootstrap.php, or DatabaseSetup. Covers two scenarios: the thelia/thelia dev repo
(with core/ as a path repository) and the thelia-project skeleton
(simulating a new developer install via composer create-project).
(with core/ as a path repository) and the thelia-project skeleton installed the way
a new developer installs it, with composer create-project from the tagged releases.
---

# Skill: Fresh Install Test
Expand All @@ -22,9 +22,11 @@ Reusable validation protocol for a clean Thelia 3 installation. Run it after any
## Prerequisites

- DDEV installed and running
- SSH access to the GitHub repos under `thelia/*`
- SSH access to the GitHub repos under `thelia/*` for the dev-repo scenario
- The target workspace directory must be empty (the protocol deletes and recreates it)

Thelia 3 ships as tagged releases; there is no development branch to install from. Test 1 clones the development repository, whose default branch is `main`. Test 2 installs the published packages. While `3.0.0-beta1` is the newest tag, the skeleton needs `--stability=beta` (or an explicit `thelia/thelia-project:^3.0.0-beta1`), and a project's own `composer.json` needs `"minimum-stability": "beta"` with `"prefer-stable": true`.

---

## Test 1: thelia/thelia (dev repo with core/ as a path repository)
Expand All @@ -35,7 +37,7 @@ Reusable validation protocol for a clean Thelia 3 installation. Run it after any
WORKSPACE=<path-to-your-workspace>

PROJECT=thelia-3
BRANCH=twig # replace with the branch you want to test
BRANCH=main # replace with the branch or tag you want to test

# 1. Full cleanup
ddev stop --unlist $PROJECT 2>/dev/null
Expand Down Expand Up @@ -116,28 +118,28 @@ ddev exec php bin/console debug:container --deprecations | head -3
## Test 2: thelia/thelia-project (simulates a new developer install)

```bash
# Set WORKSPACE to the directory that will contain the cloned project.
# Set WORKSPACE to the directory that will contain the project.
WORKSPACE=<path-to-your-workspace>

PROJECT=thelia-project-test
BRANCH=twig

# 1. Full cleanup
ddev stop --unlist $PROJECT 2>/dev/null
ddev delete -Oy $PROJECT 2>/dev/null
rm -rf "$WORKSPACE/$PROJECT"

# 2. Clone
# 2. Create the project from the tagged release
cd "$WORKSPACE"
git clone -b $BRANCH git@github.com:thelia/thelia-project.git $PROJECT
composer create-project --stability=beta thelia/thelia-project $PROJECT
# Equivalent, pinned: composer create-project thelia/thelia-project:^3.0.0-beta1 $PROJECT
cd $PROJECT

# 3. Configure DDEV (MariaDB version can vary by host)
ddev config --project-name=$PROJECT --project-type=symfony --docroot=public \
--php-version=8.3 --webserver-type=nginx-fpm --database=mariadb:11.8
ddev start

# 4. Install PHP dependencies
# 4. Install PHP dependencies inside the container
ddev exec composer install

# 5. Install Thelia with demo data and admin account
Expand Down Expand Up @@ -168,6 +170,7 @@ ddev exec php -r 'require "vendor/autoload.php"; echo Symfony\Component\HttpKern
- `bootstrap.php` must NOT load `vendor/autoload.php` (doing so disables the Symfony Runtime via its `require_once` guard).
- `public/index.php` must load `bootstrap.php` first, then `vendor/autoload_runtime.php`.
- `bin/console` passes through `vendor/thelia/core/Thelia`, not the standard Symfony pattern.
- Constraints in the generated `composer.json`: `^3.0.0-beta1` for `thelia/core` and the skeleton, `^1.0.0-beta1` for the templates, the module's current major for `thelia/*-module`, plus `"minimum-stability": "beta"` and `"prefer-stable": true`.

---

Expand Down
5 changes: 4 additions & 1 deletion plugins/thelia/skills/propel-thelia/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,8 @@ public function setPassword($password) { ... }
public function setPassword(?string $password = null): static { ... }
```

Never widen a non-nullable Base signature: if the Base getter returns `string`, an override that returns `?string` is not a compatible signature and fails at load. Keep the Base contract and handle the empty case inside the method.

Common cases to align:
- `getValue(): ?string` on Config, MetaData
- `setPosition(?int $v = null): static` on Product, Content
Expand Down Expand Up @@ -633,7 +635,8 @@ Some methods that overrode Propel getters/setters with incompatible signatures w
- **Singletons** `Translator::$instance` and `URL::$instance` must stay `?self = null` (fatal error in tests otherwise).
- **`#[Ignore]` on `static` methods** crashes the Symfony Serializer. Never do this.
- **Propel subprocess:** `PropelInitService` crashes when Propel is launched in a cold subprocess. Always boot `App\Kernel` in-process.
- **`Base/` classes are regenerated.** Never edit them manually.
- **`Base/` classes are regenerated.** Never edit them manually. Module models are generated under `var/propel/{APP_ENV}/model/`: a `Class not found` on `MyModuleQuery` usually means that cache is stale or was never built, not that the class is missing. Regenerate (`module:generate:model`, or re-run the post-activation) before looking for a namespace bug.
- **Never widen a getter to nullable in a stub.** Overriding a non-nullable Base getter with a `?type` return is an incompatible signature and fails at load.
- **`Collection` is no longer an iterator:** use `getIterator()`; the `current()`/`next()` methods are `@deprecated`.
- **Strict setter typing:** setters now have native PHP types. Passing a `bool` to a `?int` setter (TINYINT) or a `float` to a `?string` setter (DECIMAL) raises a `TypeError`. Always cast explicitly.
- **ENUM/SET are untyped:** ENUM/SET getters and properties have no native type (the getter returns a string, but Propel maps ENUM to int internally). Do not attempt to type them.
Expand Down
4 changes: 2 additions & 2 deletions plugins/thelia/skills/thelia2/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
name: thelia2
description: "Thelia 2.6 e-commerce framework (branch main, Symfony 6.4, API Platform 3.4, PHP 8.2+, Propel ORM, Smarty front + back + email + pdf). Covers module creation: BaseModule lifecycle 8 methods (install/update/preActivation/postActivation/registerHooks/preDeactivation/postDeactivation/destroy), config.xml/module.xml/schema.xml (XSD module-2_2.xsd, thelia-1.0.xsd), Propel-AP Bridge (PropelResourceInterface, PropelResourceTrait, ResourceAddonInterface, ResourceAddonTrait, AbstractTranslatableResource, I18nCollection, Relation/Column/CompositeIdentifiers attributes), 7 custom Propel filters (SearchFilter/OrderFilter/BooleanFilter/RangeFilter/DateFilter/NotInFilter/AbstractFilter), JWT Lexik 2.x without refresh, Smarty back+front hooks (BaseHook + getSubscribedHooks(), HookRenderEvent .add() vs HookRenderBlockEvent fragments), loops (BaseLoop + PropelSearchLoopInterface vs ArraySearchLoopInterface mutex, BaseI18nLoop, SearchLoopInterface, ArgumentCollection 10 factories), forms (BaseForm + init() non-constructor + getName() auto-FQCN snake_case + ParserContext, success_url/error_url hidden fields), 175 events TheliaEvents (ORDER_BEFORE_PAYMENT, AFTER_CARTADDITEM, FORM_BEFORE_BUILD/AFTER_BUILD, MODULE_PAY, MODULE_DELIVERY_GET_POSTAGE), 20 Smarty plugins / ~85 tags ({loop}, {ifloop}, {elseloop}, {pageloop}, {hook}, {hookblock}, {form}, {form_field}, {form_hidden_fields}, {intl}, {url}, {token_url}, {theme}, {theme_url}, {flash}, {check_auth}, {format_money}, {format_date}, {encore_entry_script_tags}), payment/delivery modules (AbstractPaymentModule pay()/isValidPayment(), AbstractDeliveryModule getPostage()), TheliaSmarty local module + SmartyParser, RegisterHookListenersPass, RegisterLoopPass. Use when working on Thelia 2.6 projects, branch main repo thelia/thelia, creating modules in local/modules, building Smarty front+back+email+pdf templates, exposing API resources, writing hooks/loops/forms, integrating payment/delivery modules. Triggers on: thelia 2, thelia 2.6, branch main, BaseModule, config.xml, module.xml, schema.xml, postActivation, registerHooks, TheliaEvents, BaseHook, getSubscribedHooks, HookRenderEvent, HookRenderBlockEvent, BaseLoop, PropelSearchLoopInterface, ArraySearchLoopInterface, BaseI18nLoop, BaseForm, ParserContext, SmartyParser, TheliaSmarty, Smarty, {loop}, {hook}, {hookblock}, {form}, {intl}, {url}, {pageloop}, {ifloop}, {elseloop}, {form_field}, {form_hidden_fields}, {check_auth}, {format_money}, PropelResourceInterface, PropelResourceTrait, ResourceAddonInterface, ResourceAddonTrait, AbstractTranslatableResource, I18nCollection, ApiFilter SearchFilter OrderFilter BooleanFilter RangeFilter DateFilter NotInFilter, Relation Column CompositeIdentifiers, local/modules, AbstractPaymentModule, AbstractDeliveryModule, ORDER_BEFORE_PAYMENT, AFTER_CARTADDITEM, CART_ADDITEM, Api/Resource/, normalizationContext per operation, GROUP_ADMIN_READ_SINGLE, BankCoordinatesForm, IBAN normalization, setPostage save, module.configuration save Controller, routing.xml admin module, token_url CSRF, final readonly tests Reflection, BaseAdminController checkAuth, validateForm, generateSuccessRedirect, generateErrorRedirect. Do NOT trigger for Thelia 3 projects (look for Twig .html.twig templates, FlexyBundle, LiveComponent, TwigComponent, AP 4.3 standalone, branch twig, IntegrationTestCase, FixtureFactory, resources(), attr(), CartFacade)."
description: "Thelia 2.6 e-commerce framework (maintenance branch 2.6, Symfony 6.4, API Platform 3.4, PHP 8.2+, Propel ORM, Smarty front + back + email + pdf). Covers module creation: BaseModule lifecycle 8 methods (install/update/preActivation/postActivation/registerHooks/preDeactivation/postDeactivation/destroy), config.xml/module.xml/schema.xml (XSD module-2_2.xsd, thelia-1.0.xsd), Propel-AP Bridge (PropelResourceInterface, PropelResourceTrait, ResourceAddonInterface, ResourceAddonTrait, AbstractTranslatableResource, I18nCollection, Relation/Column/CompositeIdentifiers attributes), 7 custom Propel filters (SearchFilter/OrderFilter/BooleanFilter/RangeFilter/DateFilter/NotInFilter/AbstractFilter), JWT Lexik 2.x without refresh, Smarty back+front hooks (BaseHook + getSubscribedHooks(), HookRenderEvent .add() vs HookRenderBlockEvent fragments), loops (BaseLoop + PropelSearchLoopInterface vs ArraySearchLoopInterface mutex, BaseI18nLoop, SearchLoopInterface, ArgumentCollection 10 factories), forms (BaseForm + init() non-constructor + getName() auto-FQCN snake_case + ParserContext, success_url/error_url hidden fields), 175 events TheliaEvents (ORDER_BEFORE_PAYMENT, AFTER_CARTADDITEM, FORM_BEFORE_BUILD/AFTER_BUILD, MODULE_PAY, MODULE_DELIVERY_GET_POSTAGE), 20 Smarty plugins / ~85 tags ({loop}, {ifloop}, {elseloop}, {pageloop}, {hook}, {hookblock}, {form}, {form_field}, {form_hidden_fields}, {intl}, {url}, {token_url}, {theme}, {theme_url}, {flash}, {check_auth}, {format_money}, {format_date}, {encore_entry_script_tags}), payment/delivery modules (AbstractPaymentModule pay()/isValidPayment(), AbstractDeliveryModule getPostage()), TheliaSmarty local module + SmartyParser, RegisterHookListenersPass, RegisterLoopPass. Use when working on Thelia 2.6 projects, maintenance branch 2.6 of thelia/thelia, creating modules in local/modules, building Smarty front+back+email+pdf templates, exposing API resources, writing hooks/loops/forms, integrating payment/delivery modules. Triggers on: thelia 2, thelia 2.6, branch 2.6, thelia2 module branch, BaseModule, config.xml, module.xml, schema.xml, postActivation, registerHooks, TheliaEvents, BaseHook, getSubscribedHooks, HookRenderEvent, HookRenderBlockEvent, BaseLoop, PropelSearchLoopInterface, ArraySearchLoopInterface, BaseI18nLoop, BaseForm, ParserContext, SmartyParser, TheliaSmarty, Smarty, {loop}, {hook}, {hookblock}, {form}, {intl}, {url}, {pageloop}, {ifloop}, {elseloop}, {form_field}, {form_hidden_fields}, {check_auth}, {format_money}, PropelResourceInterface, PropelResourceTrait, ResourceAddonInterface, ResourceAddonTrait, AbstractTranslatableResource, I18nCollection, ApiFilter SearchFilter OrderFilter BooleanFilter RangeFilter DateFilter NotInFilter, Relation Column CompositeIdentifiers, local/modules, AbstractPaymentModule, AbstractDeliveryModule, ORDER_BEFORE_PAYMENT, AFTER_CARTADDITEM, CART_ADDITEM, Api/Resource/, normalizationContext per operation, GROUP_ADMIN_READ_SINGLE, BankCoordinatesForm, IBAN normalization, setPostage save, module.configuration save Controller, routing.xml admin module, token_url CSRF, final readonly tests Reflection, BaseAdminController checkAuth, validateForm, generateSuccessRedirect, generateErrorRedirect. Do NOT trigger for Thelia 3 projects (look for Twig .html.twig templates, FlexyBundle, LiveComponent, TwigComponent, AP 4.3 standalone, IntegrationTestCase, FixtureFactory, resources(), attr(), CartFacade)."
---

# Thelia 2.6: Module Development Guide

> Stack: Symfony 6.4, API Platform 3.4 (bundle), PHP 8.2+, Propel ORM, branch `main`. Front + back + email + pdf in Smarty exclusively (no Twig). API JSON-LD only. JWT Lexik 2.x without refresh. No Doctrine, no Messenger, no Turbo/Mercure, no LiveComponent.
> Stack: Symfony 6.4, API Platform 3.4 (bundle), PHP 8.2+, Propel ORM. Maintenance happens on the `2.6` branch of `thelia/thelia`; Thelia 2 module branches are named `thelia2`. Front + back + email + pdf in Smarty exclusively (no Twig). API JSON-LD only. JWT Lexik 2.x without refresh. No Doctrine, no Messenger, no Turbo/Mercure, no LiveComponent.

## 1. Decision router "I want X"

Expand Down
Loading
Loading