Thanks to visit codestin.com
Credit goes to github.com

Skip to content

added support for glob loaders in Config #21635

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 18, 2017
Merged

Conversation

fabpot
Copy link
Member

@fabpot fabpot commented Feb 16, 2017

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets n/a
License MIT
Doc PR not yet

In #21270, we added the possibility to use glob patterns to import (not load) config files, but it was restricted to the container. The same feature could be useful (and I actually have a use case) for the routing.

So, this PR moves the logic to the Config component. It also adds a new GlobFileLoader class that allows to load glob patterns (not just import them as in #21270).

Last, but not least, the new glob file loader is registered in both the routing and the container default loaders.

Here is a simple, but powerful example, using the Symfony micro kernel (actually, this is a snippet from the Kernel used in Symfony Flex :)):

<?php

namespace Symfony\Flex;

use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
{
    use MicroKernelTrait;

    const CONFIG_EXTS = '.{php,xml,yaml,yml}';

    // ...

    protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
    {
        $confDir = dirname($this->getRootDir()).'/etc';
        $loader->import($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob');
        $loader->import($confDir.'/packages/'.$this->getEnvironment().'/**/*'.self::CONFIG_EXTS, 'glob');
        $loader->import($confDir.'/container'.self::CONFIG_EXTS, 'glob');
    }

    protected function configureRoutes(RouteCollectionBuilder $routes)
    {
        $confDir = dirname($this->getRootDir()).'/etc';
        $routes->import($confDir.'/routing/*'.self::CONFIG_EXTS, '/', 'glob');
        $routes->import($confDir.'/routing/'.$this->getEnvironment().'/**/*'.self::CONFIG_EXTS, '/', 'glob');
        $routes->import($confDir.'/routing'.self::CONFIG_EXTS, '/', 'glob');
    }
}

$ret[] = $this->doImport($resource, $type, $ignoreErrors, $sourceResource);
}

return $ct > 1 ? $ret : $ret[0] ?? null;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ugly as load and import are not supposed to return anything, but the routing loaders do expect some return value (something that should probably be fixed at some point).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if already ugly enough as is, do we really want this to require php 7+ for such syntactic sugar ???

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -88,8 +68,12 @@ private function findClasses($namespace, $resource)
{
$classes = array();
$extRegexp = defined('HHVM_VERSION') ? '/\\.(?:php|hh)$/' : '/\\.php$/';
$prefixLen = null;
foreach ($this->glob($resource, true, $prefix) as $path => $info) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you call glob outside of the loop, you can compute prefixLen outside of the foreach

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that does not work

$ret[] = $this->doImport($resource, $type, $ignoreErrors, $sourceResource);
}

return $ct > 1 ? $ret : isset($ret[0]) ? $ret[0] : null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop $ct then:
isset($ret[1]) ? $ret : ($ret ? $ret[0] : null) or
$ret ? (isset($ret[1]) ? $ret : $ret[0]) : null ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which would be less readable

{
if (strlen($resource) === $i = strcspn($resource, '*?{[')) {
if (!$recursive) {
yield $resource => new \SplFileInfo($resource);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just in case, $prefix should be set to null here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

*/
public function supports($resource, $type = null)
{
return 'glob' === $type;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a check on $resource, like false === strpbrk($resource, '*?{[')?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed as we force $type to be glob

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolas-grekas could the check be done at some other place, see #22160
Actually just a check if a glob pattern is used but not the correct type (type: glob) is configured to return a meaningful errormessage?

@@ -61,21 +61,28 @@ public function __construct(LoaderInterface $loader = null)
*/
public function import($resource, $prefix = '/', $type = null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case of a glob, this is missing tracking of the directory prefixing the pattern - see "$this->container->fileExists($resourcePrefix, '/^$/');" in DI.
Should we do it inline here? Would be like a leak but do we have a better choice?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not about the "leak", as routing resources are tracked in a different file, so we cannot reused the same logic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, we have the same issue with the container.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is nothing to fix here. Calling import does not imply that you were using a glob. However, the previous implementation made this assumption and always added the direction as a resource, even for non-globs, I don't think this is something we want.

@fabpot fabpot force-pushed the glob-loader branch 2 times, most recently from a183027 to ce72d21 Compare February 16, 2017 21:53
@nicolas-grekas nicolas-grekas added this to the 3.3 milestone Feb 18, 2017
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 after rebase

@fabpot fabpot merged commit 025585d into symfony:master Feb 18, 2017
fabpot added a commit that referenced this pull request Feb 18, 2017
This PR was merged into the 3.3-dev branch.

Discussion
----------

added support for glob loaders in Config

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | not yet

In #21270, we added the possibility to use glob patterns to import (not load) config files, but it was restricted to the container. The same feature could be useful (and I actually have a use case) for the routing.

So, this PR moves the logic to the Config component. It also adds a new `GlobFileLoader` class that allows to load glob patterns (not just import them as in #21270).

Last, but not least, the new glob file loader is registered in both the routing and the container default loaders.

Here is a simple, but powerful example, using the Symfony micro kernel (actually, this is a snippet from the Kernel used in Symfony Flex :)):

```php
<?php

namespace Symfony\Flex;

use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
{
    use MicroKernelTrait;

    const CONFIG_EXTS = '.{php,xml,yaml,yml}';

    // ...

    protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
    {
        $confDir = dirname($this->getRootDir()).'/etc';
        $loader->import($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob');
        $loader->import($confDir.'/packages/'.$this->getEnvironment().'/**/*'.self::CONFIG_EXTS, 'glob');
        $loader->import($confDir.'/container'.self::CONFIG_EXTS, 'glob');
    }

    protected function configureRoutes(RouteCollectionBuilder $routes)
    {
        $confDir = dirname($this->getRootDir()).'/etc';
        $routes->import($confDir.'/routing/*'.self::CONFIG_EXTS, '/', 'glob');
        $routes->import($confDir.'/routing/'.$this->getEnvironment().'/**/*'.self::CONFIG_EXTS, '/', 'glob');
        $routes->import($confDir.'/routing'.self::CONFIG_EXTS, '/', 'glob');
    }
}
```

Commits
-------

025585d added support for glob loaders in Config
@fabpot fabpot deleted the glob-loader branch April 7, 2017 17:17
@fabpot fabpot mentioned this pull request May 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants