Michaël Garrez
02/2016
Composer is a dependency management
solution for PHP
It allows a project to specify which packages and version it depends on
Packagist (official composer packages repository) contains multiple types of packages :
At the moment, PHP Frameworks have their own package management system.
Puli provides a framework agnostic packages management system.
A Puli package is a PHP directory that contains a puli.json file.
Puli provides a framework agnostic way to access resources in your project and in your composer packages.
For Puli, resources are all type of files except PHP files.
Take an example with Symfony
<?php
...
public function blogIndexAction()
{
return $this->render('blog/index.html.twig');
}
app/Resources/views/blog/index.html.twig
Symfony provides its own way to load templates from the application / bundles
How do you load a twig template which is in composer package ?
<?php
...
public function blogIndexAction()
{
return $this->render(__DIR__ . ' ????? ');
}
vendor/test/test-library/template/test.html.twig
Puli provides a Repository system which provides makes resources accessible through a Puli path.
A repository is an implementation of
Puli's ResourceRepository interface.
Same example using Puli :
<?php
...
public function blogIndexAction()
{
$factoryClass = PULI_FACTORY_CLASS;
$factory = new $factoryClass();
$repo = $factory->createRepository();
return $this->render($repo->get('/test/template/test.html.twig')->getBody());
}
vendor/test/test-library/template/test.html.twig
php puli.phar map /test /
Puli-Cli
Puli composer plugin
Puli composer plugin builds a Repository and a Discovery based on the puli.json files from all your composer packages
(including your project).
Natively Puli will build a Repository and a Discovery based on your project puli.json file.
Puli provides a way to connect Composer packages that consume resources with other packages that provides resources
Let's take as example a project where you have among others 2 composer packages :
Your batman/blog package provides several translation files :
Your thor/translator package provides a way to inject YAML translation files :
<?php
$translator = new Translator([
'vendor/batman/blog/translations/messages.fr.yml',
'vendor/batman/blog/translations/messages.en.yml'
]);
This works but require you to work to plug them together.
Plus, this is hardly scalable.
Puli provides a system of binding to resolve this issue.
The owner of batman/blog will bind his translations files to thor/translations and thor/translator will fetch them :
All the owner of batman/blog has to do is to bind his
translation files to the correct binding :
php puli.phar bind /translations/*.yml thor/translations
This will update the puli.json file contained in the package.
The owner of thor/translator has to require an
instance of ResourceDiscovery to be provided :
<?php
class Translator
{
public function __construct(ResourceDiscovery $discovery)
{
$this->discovery = $discovery;
}
protected function getTranslationFiles()
{
$bindings = $this->discovery->findByType('thor/translations');
foreach ($bindings as $binding) {
foreach ($binding->getResources() as $resource) {
$this->translationFiles[] = $resource->getPath();
}
}
}
}
As a user all you have to do is to provide a ResourceDiscovery
for your Translator package :
<?php
$factoryClass = PULI_FACTORY_CLASS;
$factory = new $factoryClass();
$repo = $factory->createRepository();
$discovery = $factory->createDiscovery($repo);
$translator = new Translator($discovery);
You can also bind classes :
<?php
$plugins = [];
foreach ($discovery->findBindings('test/plugin') as $binding) {
$className = $binding->getClassName();
$plugin = new $className($discovery);
$plugins[] = $plugin;
}