PHP conventions
- PSR-12 formatting and PSR-4 autoloading.
- Every file starts with
declare(strict_types=1);after the opening tag. - Type every property, parameter and return value. Use union and nullable types instead of untyped values.
- Add
#[Override]when you implement or override a method, and importOverride. - Use constructor property promotion for dependencies.
- Keep classes final-ish in spirit: prefer composition and small services over deep inheritance.
src/Services/RateFetcher.php
Naming
Domain modeling
Core code keeps domain rules inside the domain layer, and you should do the same in a plugin:- Value objects validate their input in the constructor and throw
Shared\Domain\Exceptions\InvalidValueExceptionwhen it’s wrong. They’re immutable. - Entities expose behavior, not setters for every field. They take value objects, not raw scalars.
- Commands are simple data holders that convert scalars into value objects, and they’re tagged with
#[Handler(...)]. - Handlers do the work, persist through a repository, and dispatch a domain event.
src/Application/Commands/CreateNoteCommand.php
Twig conventions
- Use
{% extends "/layouts/main.twig" %}for app and admin pages, and put your markup in the blocks that layout defines. - Register your own namespace and reference templates as
@acme-hello/.... - Guard optional variables with
is defined, because debug mode enables strict variables. - Wrap every user-facing string in a translation function:
__(),p__()with a context,n__()for plurals. Themes use thethemedomain, so they calld__('theme', ...)anddp__('theme', ...).
JavaScript conventions
- Alpine.js drives interactivity. Register components with
Alpine.data('name', () => ({ ... })). - Call the JSON API through the
window.apiclient so authentication headers are handled for you. - Reuse the built-in web components, such as
x-formandmodal-element, instead of reimplementing them.
Quality tools
The installation ships with its own tooling and Composer scripts:
Configuration lives in
phpstan.neon.dist, phpcs.xml.dist, phpmd.xml and phpunit.xml. Point the tools at your own package to check it:
Testing your extension
The bundled PHPUnit configuration loadsbootstrap/autoload.php and runs the suite in tests/. For a plugin, test the parts you can isolate: value objects, services, mappers and API clients, using a PSR-18 client double instead of live HTTP calls. Verify integration points, such as routes, settings pages and webhooks, against a local installation with DEBUG=true.
Documentation and versioning
- Ship a
README.mdwith installation and configuration steps. - Use semantic versioning in your package’s
versionfield, and raise it with every release, because the installer passes it to Composer. - Record which Aikeedo versions you support.
- Translate your strings and ship the catalogs. See Plugin localization and Theme localization.