Exposing resources: from Symfony bundles to packages

Posted by Unknown on Friday, September 26, 2014

Syfony bundles: providing services and exposing resources


When you look at the source code of the Symfony framework, it becomes clear that bundles play two distinct and very different roles: in the first place a bundle is a service container extension: it offers ways to add, modify or remove service definitions and parameters, optionally by means of bundle configuration. This role is represented by the following methods of BundleInterface:



namespace Symfony\Component\HttpKernel\Bundle;

interface BundleInterface extends ContainerAwareInterface
{
/** Boots the Bundle. */
public function boot();

/** Shutdowns the Bundle. */
public function shutdown();

/** Builds the bundle. */
public function build(ContainerBuilder $container);

/** Returns the container extension that should be implicitly loaded. */
public function getContainerExtension();

...
}


The second role of a bundle is that of a resource provider. When a bundle is registered in the application kernel, it automatically starts to expose all kinds of resources to the application. Think of routing files, controllers, entities, templates, translation files, etc.


The "resource-providing" role of bundles is represented by the following methods of BundleInterface:



interface BundleInterface extends ContainerAwareInterface
{
...

/** Returns the bundle name that this bundle overrides. */
public function getParent();

/** Returns the bundle name (the class short name). */
public function getName();

/** Gets the Bundle namespace. */
public function getNamespace();

/** Gets the Bundle directory path. */
public function getPath();
}


As far as I know, only getName() serves both purposes, since it is also used to calculate the configuration key that is used for the bundle's configuration (e.g. the configuration for the DoctrineBundle is to be found under the doctrine key in config.yml).


There are several framework classes that use the bundle name and its root directory (which is returned by the bundle's getPath() method) to locate resources in a bundle. For instance the ControllerResolver from the FrameworkBundle allows you to use the Bundle:Controller:action notation to point to methods of controller classes in the Controller directory of your bundle. And the TemplateNameParser from the FrameworkBundle resolves shorthand notation of templates (e.g. Bundle:Controller:action.html.twig) to their actual locations.


It's actually quite a clever idea to use the location of the bundle class as the root directory for the resources which a bundle exposes. By doing so, it doesn't matter anymore whether a bundle is part of a package that is installed in the vendor directory using Composer, or if it's part of your project's source code in the src directory; the actual location of resources is always derived based on the location of the bundle class itself.


Towards a better situation for resources


Let me first say, I think the BundleInterface ought to be separated in two different "role interfaces", based on the different roles they play. I was thinking of ProvidesServices and a ExposesResources interface. That would clearly communicate the two different things that a bundle can do for you.


Puli: uniform resource location


Much more important than splitting the BundleInterface is to have a better way of exposing resources located inside a library (or bundle, it wouldn't make a difference actually). This is something Bernhard Schüssek has been working on. He has created a nice library called Puli. It basically provides a way to locate and discover resources from all parts of the application, be it your own project or a package that you pulled in using Composer.


The core class of Puli is the ResourceRepository. It works like a registry of resource locations. For every resource or collection of resources that you want to expose, you call the add() method and provide as a first argument a prefix, and as a second argument an absolute path to a directory:



use Webmozart\Puli\Repository\ResourceRepository;

$repo = new ResourceRepository();
$repo->add('/matthias/package-name/templates', '/path/to/Resources/views');


Now if you ask the repository to get the absolute path of a particular resource, you can do it by using the prefix you just


Truncated by Planet PHP, read more at the original (another 4623 bytes)




more

{ 0 comments... » Exposing resources: from Symfony bundles to packages read them below or add one }

Post a Comment

Popular Posts