Getting started
The `ModularRouter` class combines the power of the Symfony router with the flexibility of the ModularRouting component. A router is an all-in-one package that simplifies the use the of routing in a project. The Symfony `Router` class was developed to handle static route definitions with a fixed set of metadata and is not suited for dynamically generated routes. The `ModularRouter` class uses instances of `ProdiverInterface` and `MetadataFactoryInterface` to map a request to a module and to load the relevant routing metadata respectively. In order to use the router you need to set up several dependencies: * A module class * A module manager, which interacts with instances of your module class * A metadata factory, which returns the metadata and routing data of the available modules * A provider, which provides the instance of your module class associated with a request # Creating the module class The goal of this component is to map similar requests to different `Route` definitions based on a `Module` instance associated with the request. The `Module` instance holds the reference to a set of routing metadata. Your first tasks are to create a `Module` class and to initialize a `ModuleManagerInterface` object. Your `Module` class can act however you want it to, so add any properties or methods you need for your project. To create a class that acts a module, it needs to implement `ModuleInterface`. You can also choose to extend the base `Module` class provided by this component. In the following section you'll see an example of how your `Module` class should look if you're using the Doctrine ORM. ## Doctrine ORM Module class <?php // src/Application/Entity/Module.php namespace Application\Entity; use Doctrine\ORM\Mapping as ORM; use Harmony\Component\ModularRouting\Model\Module as BaseModule; /** * @ORM\Entity * @ORM\Table(name="module") */ class Module extends BaseModule { /** * @var integer * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var string * * @ORM\Column(name="modular_type", type="string", length=255) */ protected $modularType; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Get modular identity * * @return mixed */ public function getModularIdentity() { return $this->getId(); } // custom methods... } ## Initializing a module manager To manage the modules in your project, a provider is encouraged to use an instance of `ModuleManagerInterface`. These are some examples of managers included in this component: // Doctrine ORM use Harmony\Component\ModularRouting\Doctrine\ModuleManager; $moduleManager = new ModuleManager($entityManager, 'Application\Entity\Module'); $moduleManager->setModularIdentifier('id'); // Static use Harmony\Component\ModularRouting\StaticModuleManager; $moduleManager = new StaticModuleManager; # Setting up a provider Providers are the backbone of the ModularRouting component and are responsible for matching the request to a module using the module manager. Each provider can define its own behaviour when matching for a module, this doesn't have to involve the This component currently includes a single provider: * The `SegmentProvider` matches a segment of the request path to the identity field of the module ! Note ! To learn how to create your own provider, check out the [[[6]]] section of this documentation. It is up to the provider to choose how to load the route definitions from the metadata it retrieves from the metadata factory. The providers included in this component use a loader from the Symfony Routing component as explained in the [Symfony documentation][symfony-routing-loader]. A prefix is added to the routes to accommodate for the matching strategy. This is an example of how to set up the `SegmentProvider` included in this component: use Harmony\Component\ModularRouting\Provider\SegmentProvider; $provider = new SegmentProvider($moduleManager); # Setting up a metadata factory The `MetadataFactory` class loads and returns `ModuleMetadata` objects from a resource using a loader instance. The ModularRouting component comes with a number of loader classes, each giving you the ability to load metadata from an external file of some format. Each loader expects a `FileLocator` instance as the constructor argument. If a file is found, the loader returns an array with the metadata. If you want to use YAML to define metadata about your modules, you can use the following code, assuming that your metadata file is in the same directory: use Symfony\Component\Config\FileLocator; use Harmony\Component\ModularRouting\Metadata\Loader\YamlFileLoader as MetadataYamlFileLoader; // look inside *this* directory $locator = new FileLocator([__DIR__]); $metadataLoader = new MetadataYamlFileLoader($locator); Now that you have a loader, you can create a file containing the metadata: # modules.yml module_foo: name: "Foo Module" type: "acme_foo" routing: - { resource: "app/config/routing/foo.yml", type: "yaml" } module_bar: name: "Bar Module" type: "acme_bar" routing: - { resource: "app/config/routing/bar.yml", type: "yaml" } ! Note ! More information on loaders included in this component is available in the [[[5]]] section. Since the metadata can be different depending on the request, the routing resources of a module are only loaded when the project requests the metadata for that specific module. To do this, the `MetadataFactory` uses a second loader to load the routing resources: use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\YamlFileLoader as RoutingYamlFileLoader; // look inside *this* directory $locator = new FileLocator([__DIR__]); $routingLoader = new RoutingYamlFileLoader($locator); With these loaders set up, you're ready to load the metadata defined in the metadata file: use Harmony\Component\ModularRouting\Metadata\MetadataFactory; $metadataFactory = new MetadataFactory($metadataLoader, $routingLoader, 'modules.yml', 'yaml'); # Using the router The `ModularRouter` class is similar to the `Router` class from the Symfony Routing component but delegates the loading of route definitions to a metadata factory as explained in the previous section. This allows the router to load a `RouteCollection` object based on the routing metadata of the module associated with the request path. In addition, an array of options is used to configure the router. This is what a basic implantation of the `ModularRouter` class would look like: use Harmony\Component\ModularRouting\ModularRouter; use Symfony\Component\Routing\RequestContext; $router = new ModularRouter( $provider, $metadataFactory, ['cache_dir' => __DIR__ . '/cache'], new RequestContext('/') ); $router->match('/1/'); With the `cache_dir` option you can enable route caching (if you provide a path) or disable caching (if it's set to `null`). The caching is done automatically in the background if you want to use it. ## Using a route prefix The `ModularRouter` class allows a route prefix to be set for all modular routes. This is useful if your project is configured with multiple routers. $router->setRoutePrefix('/module'); It's also possible to create a route prefix with placeholders: $router->setRoutePrefix( '/{prefix}/module', // path [], // default values ['prefix' => '[\w]{4}'] // requirements ); [symfony-routing-loader]:
Defining metadata
The Modular Routing component comes with a number of loader classes, each giving you the ability to load a collection of metadata defintions from an external file of some format. Each loader expects a `FileLocator` instance as the constructor argument. You can use the `FileLocator` instance to define an array of paths in which the loader will look for the requested files. If the file is found, the loader returns an array of metadata definitions that the `MetadataFactory` will convert into `ModuleMetadata` objects. These are the loaders available in this component under the `Harmony\Component\ModularRouting\Metadata\Loader` namespace: * `XmlFileLoader` * `YamlFileLoader` These are some examples of module definitions to be used with the loaders: # XML <!-- modular_routing.xml --> <?xml version="1.0" encoding="UTF-8" ?> <modules> <module id="module_foo" name="Foo Module" type="acme_foo"> <resource type="xml">app/config/routing/foo.xml</resource> </module> <module id="module_bar" name="Bar Module" type="acme_bar"> <resource type="xml">app/config/routing/bar.xml</resource> </module> </modules> # YAML # modular_routing.yml module_foo: name: "Foo Module" type: "acme_foo" routing: - { resource: "app/config/routing/foo.yml", type: "yaml" } module_bar: name: "Bar Module" type: "acme_bar" routing: - { resource: "app/config/routing/bar.yml", type: "yaml" }
Creating a custom provider
The `ProviderInterface` interface can be implemented in different ways and is not limited to the providers included in this component. If you'd like to create a custom provider, we suggest taking a look at the `SegmentProvider` class which covers all the basics of a provider and the relation it has with `ModuleManager`.
Associating modules with entities
There are several helper classes available in the Modular Routing component that make it easier to associate module-based entities to the `Module` entity without forcing the project to use modular routing. Currently only support for the Doctrine ORM is built into this component.