uvdesk/extension-framework
A PHP framework for building modular extensions for the UVdesk helpdesk platform. It provides package structure, integration hooks, and core services to register and manage reusable add-ons, helping developers extend helpdesk functionality with maintainable extension packages.
Before writing any code, confirm you are inside a working UVdesk application (the standalone helpdesk project, not just the bundle). The extension-framework is a Symfony bundle that manages the lifecycle of other bundles; it is not useful on its own.
Install the framework into the UVdesk app:
composer require uvdesk/extension-framework
Then register it in config/bundles.php if the recipe did not do so automatically.
Look first at the Uvdesk\ExtensionFrameworkBundle namespace — specifically:
ExtensionManager service, which orchestrates install, update, and uninstall.Console/Command (uvdesk:extension:install, uvdesk:extension:uninstall, and related subcommands).First use case: scaffold a minimal extension. Create a Composer package whose composer.json declares UVdesk metadata (typically an extra section with the extension name, description, and version), a Symfony bundle class extending the framework's abstract extension, and a services.yaml. Then run:
composer dump-autoload
bin/console uvdesk:extension:install <vendor/package>
bin/console cache:clear
The install command wires the bundle in, runs lifecycle hooks, and publishes assets/config.
Read one first-party or community extension end-to-end before building your own — the lifecycle contract is easier to absorb from a working example than from the base class alone.
Package layout. Treat an extension as a first-class Composer package: src/ for PHP, Resources/views for Twig, Resources/translations for locale files, Resources/public for assets, and migrations under migrations/. Keep the bundle class thin — its only job is to declare metadata and, when required, lifecycle behavior.
Extend the abstract extension rather than implementing the interface directly. Override package name, display name, version, and dependencies, and let the framework handle registration. If you implement ExtensionInterface manually you lose the built-in dependency ordering and update plumbing.
Lifecycle hooks. Put migrations, config publishing, and seed data into the install/uninstall/update methods provided by the base class. Prefer idempotent operations (CREATE TABLE IF NOT EXISTS, guarded config writes) because the install command can be re-run. Pair this with Doctrine migrations for schema so uninstall can be reasoned about.
Dependency declaration. When extension B needs extension A, declare it in B's metadata. The manager resolves ordering on install. Avoid implicit runtime dependencies that only show up as a missing-service ServiceNotFoundException at container compile.
Integration into the helpdesk UI. Do not edit UVdesk core templates. Contribute via:
Resources/views templates following UVdesk's existing naming so theme overrides still work.Local development loop. Use a Composer path repository pointing at your extension source, so edits are live without re-requiring:
"repositories": [{ "type": "path", "url": "../my-extension" }]
After changes to services or bundle registration, cache:clear is almost always required; after class or namespace changes, dump-autoload -o is.
Versioning workflow. Bump the extension version in its metadata on every release, and test install/update/uninstall in a throwaway UVdesk instance, not your working one. The framework's value is precisely that lifecycle, so an extension that installs but cannot be cleanly uninstalled is effectively broken.
bin/console cache:clear, and in dev check var/cache/dev) before debugging anything else.uvdesk:extension:install registers and runs lifecycle, it does not composer require for you.composer dump-autoload and only then re-install.composer.json can pass CI but fail on a customer's locked install. Mirror core's constraints.bin/console debug:container <service>, bin/console debug:router, bin/console debug:event-dispatcher — plus var/log/dev.log. The framework itself rarely logs loudly; failures usually surface as container compile errors or silent no-op hooks.How can I help you explore Laravel packages today?