Using Composer Packages
Trongate works perfectly without Composer. It also works perfectly with it. The previous page covers why and when - this one covers how. The recipe itself is three steps and one line of code; most of what follows is the detail that stops those three steps going wrong.
Composer, Packagist And PSR-4
Three names that get treated as one - and none of them is PHP itself:
- Composer - a dependency manager for PHP. A command-line tool that fetches the packages you ask for, records them in
composer.json, and generates an autoloader for their classes. - Packagist - the public repository that Composer installs from (packagist.org). It's a catalogue, not a technology.
- PSR-4 - a PHP-FIG standard describing how a namespace maps onto a folder, so a class can be found from its name alone. Most modern packages are PSR-4; Composer's autoloader is what turns those mappings into working
requires.
They are related, but they are not the same thing - and you can use Composer without ever thinking about PSR-4.
Composer Is Optional
Nothing in Trongate requires Composer, and the framework - which ships with no dependencies and no vendor/ folder - won't complain if you add one:
- Trongate itself - no Composer required.
- Trongate's core - no PSR-4 required.
- Your application - Composer is there if you want it.
- Your packages - free to use whatever their own architecture calls for.
So reach for Composer only when it earns its place - a payment SDK, a PDF library, a mature date library. Otherwise write it yourself. That's the Native PHP way!
Install and Load a Package
For a normal web request, three steps and you're done.
-
Install the package. If Composer isn't on your machine yet, get it from getcomposer.org/download - it's a one-line installer, and
composer --versionconfirms it's working.Now
cdinto the root of your application and run:composer require dompdf/dompdfComposer creates
vendor/, pluscomposer.jsonandcomposer.lockif you don't already have them.Which root? The folder that contains
public/,engine/andmodules/- notpublic/itself. The autoloader line in the next step starts withAPPPATH, which points at that root, so that's wherevendor/needs to be. -
Add Composer's autoloader to
public/index.php. This file already exists in every Trongate v2 installation - you're editing it, not creating it. Add one line, so that the whole file reads as follows:PHP<?php require_once '../engine/ignition.php'; require_once APPPATH . 'vendor/autoload.php'; // <- add this line! //Init Core Library $init = new Core;Look before you edit. If
public/index.phpalready contains the autoloader line, skip to step 3.Trongate does not load Composer's autoloader for you, so this line is what wakes it up. Miss it and the package's classes simply aren't available - typically a
Class not founderror. -
Use the package in your module. Add a
usestatement - such asuse Dompdf\Dompdf;- and call the package's methods as though its classes lived in your own module. The next section has a working example.
Two Autoloaders, One Application
Composer's autoloader does not replace Trongate's. Both can run at once, and neither needs to know the other exists:
- Trongate's own loader only ever looks inside
engine/andmodules/. - Composer's loader only ever looks inside
vendor/.
That matters, because there is a tendency to assume that supporting Composer means adopting Composer throughout the framework. It doesn't. You do not have to rebuild Trongate, restructure your modules or change a single framework file in order to use a package.
Use It In Your Module
Create a module and add a use statement at the top of it. The example below is a new controller file at modules/invoices/Invoices.php - you're creating both the folder and the file:
<?php
use Dompdf\Dompdf;
class Invoices extends Trongate {
public function test(): void {
$dompdf = new Dompdf();
$dompdf->loadHtml('<h1>Hello from Trongate v2</h1>');
$dompdf->render();
header('Content-Type: application/pdf');
echo $dompdf->output();
}
}Visit /invoices/test and you get a real PDF from a Composer-installed package. Everything else is whatever the package's own documentation says. The same use statement works in models and views alike.
One rule remains: the class declared in a Trongate module file must stay global (class Invoices extends Trongate). Trongate resolves it by file name, so it can't live inside a namespace. Imported classes can.
That is your whole PSR-4 obligation. Trongate's core doesn't use PSR-4, and your modules don't have to either - but that is not incompatibility. A package that ships PSR-4 mappings - or a classmap, or plain includes - still works, because Composer's autoloader resolves the package's classes, not yours.
Package Assets: CSS And JavaScript
Some packages ship stylesheets or scripts as well as PHP. Trongate serves files from /vendor/ for you, so a package's CSS can be linked straight from there:
<link rel="stylesheet" href="vendor/acme/widget/widget.css">CSS comes back as text/css. Anything that isn't CSS is served as text/plain, which browsers may refuse to execute - so don't point a <script> tag at /vendor/. Copy the package's JavaScript into your module's own assets instead, where it's served with the correct MIME type:
<script src="invoices_module/js/widget.js"></script>See Module Assets for how those _module URLs work. And note that everything under /vendor/ is web-readable, so treat it as public - package code, never secrets.
Two Other Places That Line Goes
At the top of a module file
If you're giving a module to somebody else, put require_once APPPATH . 'vendor/autoload.php'; at the top of its controller file, straight after <?php and before your use statements. The module then works on a pristine copy of Trongate - a fresh public/index.php never breaks it.
In a CLI or cron script
Scripts bootstrap themselves, and Trongate's requires are path-relative - so chdir() into public/ first:
<?php
chdir(__DIR__ . '/../public');
require_once '../engine/ignition.php';
require_once APPPATH . 'vendor/autoload.php';
Modules::run('invoices/test');If your script complains about $_SERVER keys, give it the basics: REQUEST_METHOD, HTTP_HOST, REQUEST_URI.
Housekeeping
Add /vendor/ to your .gitignore, but commit composer.json and composer.lock. The lock file is what makes everyone else's install identical to yours - a fresh clone runs composer install and rebuilds vendor/ from it. Do the same on your server, and never edit anything inside vendor/: it's generated code, and the next install will overwrite you.
Installed packages also become part of your application's supply chain, so get comfortable with composer audit. It's now part of your maintenance routine, and that's the honest price of inviting in third-party code.
When Things Go Wrong
A handful of failures account for most confused afternoons:
Class "..." not foundmeans Composer's autoloader was never loaded. The lookup fails before Trongate gets a chance to do anything, so check that line inpublic/index.phpfirst. With error display off, it looks like a bare 500.Access denied: assets must be in subdirectoriesmeans your module folder name contains_module, a string reserved by the framework. Call itInvoices, notInvoices_module.Vendor file not found.means the/vendor/URL doesn't match a real file. Installed packages rarely put assets at the top of their own folder - check the package's layout before linking to it.composer requirerefuses to install usually means a platform problem rather than a Trongate one: the package wants a newer PHP than you're running, or an extension that isn't loaded.
The Trongate Position
Trongate isn't trying to dictate how PHP developers work, and it isn't trying to shield you from the wider PHP ecosystem either. The position is simpler than that: keep the framework lean, keep the architecture explicit, use third-party packages when they provide genuine value, and don't take on dependencies just because everybody else does.
That gives you choice. A completely dependency-free Trongate application is a perfectly good outcome. So is one that pulls in five Composer packages. Neither requires the core architecture to change.
Advanced: you can also ship an entire module as a Composer package, so that composer require drops it straight into modules/. It needs a small installer plugin and it's strictly optional - copying the folder is still the simpler way to share a module.
We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.
Share your thoughts in the Documentation Feedback.