[READ-ONLY] Forget manual registration of Doctrine entities, Twig templates and routes. Let autodiscovery handle that for you
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin
config
src
tests
.gitattributes
.gitignore
.travis.yml
LICENSE
README.md
composer.json
phpunit.xml

README.md

Load Entities, Twig paths and Routes once and for All

Build Status Downloads total

For every

  • new Entity namespace,
  • new Twig path
  • new Translation catalogue path
  • and new routes files,

you need to modify your config. Why do it, when your application can do it for you? Do you autoload each Controller manually? :)

Another feature is YAML convertor - from old pre-Symfony 3.3 to new autodiscovery, autowire and autoconfigure format.

Install

composer require symplify/autodiscovery

Usage

1. Register Doctrine Annotation Mapping

When you create a new package with entities, you need to register them:

# app/config/doctrine.yml
doctrine:
    orm:
        mappings:
            # new set for each new namespace
            ShopsysFrameworkBundle:
                type: annotation
                dir: '%shopsys.framework.root_dir%/src/Model'
                alias: ShopsysFrameworkBundle
                prefix: Shopsys\FrameworkBundle\Model
                is_bundle: false
            # new set for each new namespace
            ShopsysFrameworkBundleComponent:
                type: annotation
                dir: '%shopsys.framework.root_dir%/src/Component'
                alias: ShopsysFrameworkBundleComponent
                prefix: Shopsys\FrameworkBundle\Component
                is_bundle: false

It's called memory lock and it nicely opens doors for "I forgot that..." bugs.

How can we avoid that?

With Autodiscovery

 # app/config/twig.yml
 doctrine:
     orm:
-        mappings:
-            # new set for each new namespace
-            ShopsysFrameworkBundle:
-                type: annotation
-                dir: '%shopsys.framework.root_dir%/src/Model'
-                alias: ShopsysFrameworkBundle
-                prefix: Shopsys\FrameworkBundle\Model
-                is_bundle: false
-            # new set for each new namespace
-            ShopsysFrameworkBundleComponent:
-                type: annotation
-                dir: '%shopsys.framework.root_dir%/src/Component'
-                alias: ShopsysFrameworkBundleComponent
-                prefix: Shopsys\FrameworkBundle\Component
-                is_bundle: false
<?php declare(strict_types=1);

namespace App;

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symplify\Autodiscovery\Discovery;

final class MyProjectKernel extends Kernel
{
    use MicroKernelTrait;

    /**
     * @var Discovery
     */
    private $discovery;

    public function __construct()
    {
        parent::__construct('dev', true);
        $this->discovery = new Discovery($this->getProjectDir());
    }

    protected function configureContainer(ContainerBuilder $containerBuilder, LoaderInterface $loader): void
    {
        $this->discovery->discoverEntityMappings($containerBuilder);
    }
}

2. Twig Paths

When you create a new package with templates, you need to register them:

# app/config/twig.yml
twig:
    paths:
        # new line for each new package
        - "%kernel.root_dir%/../package/Product/templates"
        # new line for each new package
        - "%kernel.root_dir%/../package/Social/templates"

With Autodiscovery

 # app/config/twig.yml
 twig:
-    paths:
-        - "%kernel.root_dir%/../package/Product/templates/views"
-        - "%kernel.root_dir%/../package/Social/templates/views"
<?php declare(strict_types=1);

namespace App;

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;

final class MyProjectKernel extends Kernel
{
    use MicroKernelTrait;

    // ...

    protected function configureContainer(ContainerBuilder $containerBuilder, LoaderInterface $loader): void
    {
        $this->discovery->discoverTemplates($containerBuilder);
    }
}

3. Translation Paths

When you create a new package with translations, you need to register them:

# app/config/packages/framework.yml
framework:
    translator:
        paths:
            # new line for each new package
            - "%kernel.root_dir%/../package/Product/translations"
            # new line for each new package
            - "%kernel.root_dir%/../package/Social/translations"

With Autodiscovery

 # app/config/packages/framework.yml
 framework:
     translator:
-        paths:
-            - "%kernel.root_dir%/../package/Product/translations"
-            - "%kernel.root_dir%/../package/Social/translations"
<?php declare(strict_types=1);

namespace App;

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;

final class MyProjectKernel extends Kernel
{
    use MicroKernelTrait;

    // ...

    protected function configureContainer(ContainerBuilder $containerBuilder, LoaderInterface $loader): void
    {
        $this->discovery->discoverTranslations($containerBuilder);
    }
}

4. Routing

# app/config/routes.yaml

# new set for each new package
product_annotations:
    resource: "../packages/Product/src/Controller/"
    type: "annotation"

# new set for each new package
social_annotations:
    resource: "../packages/Social/src/Controller/"
    type: "annotation"

With Autodiscovery

 # app/config/routes.yaml

-# new set for each new package
-product_annotations:
-    resource: "../packages/Product/src/Controller/"
-    type: "annotation"
-
-# new set for each new package
-social_annotations:
-    resource: "../packages/Social/src/Controller/"
-    type: "annotation"
<?php declare(strict_types=1);

namespace App;

use Symfony\Component\Routing\RouteCollectionBuilder;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symplify\Autodiscovery\Routing\AnnotationRoutesAutodiscoverer;

final class MyProjectKernel extends Kernel
{
    use MicroKernelTrait;

    protected function configureRoutes(RouteCollectionBuilder $routeCollectionBuilder): void
    {
        $this->discovery->discoverRoutes($routeCollectionBuilder);
    }
}

This works very well with local packages or monorepo architecture.

YAML Convertor

vendor/bin/autodiscovery convert-yaml /src

It will convert service definitions from (config|services).(yml|yaml) configs, to new Symfony 3.3 DI features described here.

In short, from this:

services:
    some_service:
        class: App\SomeService
        autowire: true

    some_controller:
        class: App\Controller\SomeController
        autowire: true

    first_repository:
        class: App\Repository\FirstRepository
        autowire: true
        calls:
            - ["setEntityManager", ["@entity_manager"]]
    second_repository:
        class: App\Repository\SecondRepository
        autowire: true
        calls:
            - ["setEntityManager", ["@entity_manager"]]

    first_command:
        class: App\Command\FirstCommand
        autowire: true
        tags:
            - { name: console.command }
    second_command:
        class: App\Command\SecondCommand
        autowire: true
        tags:
            - { name: console.command }

    first_subscriber:
        class: App\EventSubscriber\FirstSubscriber
        autowire: true
        tags:
            - { name: kernel.event_subscriber }
    second_subscriber:
        class: App\EventSubscriber\SecondSubscriber
        autowire: true
        tags:
            - { name: kernel.event_subscriber }

To this:

services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\Repository\FirstRepository:
        calls:
            - ["setEntityManager", ["@entity_manager"]]
    App\Repository\SecondRepository:
        calls:
            - ["setEntityManager", ["@entity_manager"]]

    App\:
        resource: '../../../src'