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

Skip to content

[RFC] Enhance Kernel to allow removal of AppBundle concept (Advanced Usages) #20099

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

Closed
linaori opened this issue Sep 30, 2016 · 8 comments
Closed
Labels
RFC RFC = Request For Comments (proposals about features that you want to be discussed)

Comments

@linaori
Copy link
Contributor

linaori commented Sep 30, 2016

While the AppBundle concept is already a big improvement, it's still a bundle. I have done some digging and I hope I've come up with a solution.

What is the AppBundle good for?

  • Registering of compiler passes, can add some application specific features
  • Prepend configuration of other bundles
  • Adding (annotated 3.2+) classes to compile
  • Manipulating the container

What additional stuff does it do under the hood?
Provides a basic entry point for:

  • Bundle Alias (Used most often when calling controllers, templates and entities)
  • Register Commands
  • Provide a default location for things like Doctrine
  • Annotation routes
  • All based on the namespace and file location of the bundle
  • Assetics

What features does it have that are useless to applications as AppBundle?

  • Registering an extension point for Configurations
  • The container Extension class (unless you prepend) is useless because you can already load everything in your kernel and you can load a whole directory of service/config files now
  • boot/shutdown/build methods are useless as they can all be in the kernel
  • getParent is not needed

My personal use-case

  • I use controller as a service (no alias required)
  • I use command as a service (no registerCommands required)
  • I have Entities in packages outside of the App(Bundle) so I don't need the default doctrine behavior
  • I don't use Assetics (no alias required)
  • My templates are in app/Resources/views so I don't need the alias for templates either
  • I have annotated routes but I can use a path relative to my kernel dir for this
  • I do manipulate the container but all of those can be in the kernel as well when building the container
    • Registering several compiler passes
    • I prepend some config
    • I add classes to compile

Of course this is based on my needs, but could be expanded on. Doctrine for example allows you to configure your AppBundle manually as well. If you look at it like this, the whole AppBundle concept is actually overhead, but it requires quite a bit more effort to get it to work using just the Kernel.

When looking at the list, there's only 3 things my application really needs from the bundle: Classes to compile, compiler passes and prepending extension config. I would like to add an extension point for those 3 points in the kernel (4 if you count the new 3.2 annotated class cache) to make it easier to use a bundle-less setup of Symfony.

Is this something people are interested in? Did I forget any cases? Should Symfony provide a default "fake bundle" entry point in a directory and namespace of your choosing, e.g. registering a virtual bundle?

@sh4ka
Copy link

sh4ka commented Sep 30, 2016

It is a very interesting approach, and, in my humble opinion, deserves a good talk or article with details and delicacies. I am particularly in favor of having entities outside of the AppBundle and controller as a service, however, the use-case for that is not in the reach of the newcomer who probably is more suited to a standard MVC layout.
I would really love to see a fork of the 3.x with this as a starting point and work from there.

@linaori
Copy link
Contributor Author

linaori commented Sep 30, 2016

@sh4ka Basically I want this to start out as a more advanced usage. Once something is standing as is, I would like to iterate over it with DX to make it easy to use for new developers (or maybe even do all at once). Having no bundles means a new-comer could actually skip having to be told about bundles (and what they are), they can just get going.

@stof
Copy link
Member

stof commented Sep 30, 2016

compiler passes can also be registered in the kernel, by overriding prepareContainer. Be careful to call the parent method at the beginning, otherwise you will break the usage of bundles.

Prepending extension config is useless, as the kernel controls the main loading of the config. Just loads an extra config before the loading of the config_dev.yml file in your registerContainerConfiguration method. It will do the same (prepending config is a way to fake this when you don't have control on the loading)

so the only missing point is the possibility to inject extra classes in the class cache

@sh4ka having entities outside bundles is supported by DoctrineBundle since years. It requires a bit of config though, as DoctrineBundle cannot automatically discover them (there is no convention for finding entities outside bundles, as the convention is precisely based on bundles, so this goes into the configuration way)

@sh4ka
Copy link

sh4ka commented Sep 30, 2016

@stof I know about that functionality in Doctrine, is very handy. Just pointing out that the current docs (https://symfony.com/doc/current/doctrine.html#main) encourages newcomers to put them in the AppBundle.
I guess that the incredible versatility of SF allows many different work setups, but we should stick to one in the docs and the developer's own experience can evolve from that.

@stof
Copy link
Member

stof commented Sep 30, 2016

@sh4ka sure it does, as the recommended way in the Symfony doc is to use AppBundle. If the Symfony doc changes its recommendation, we will change the DoctrineBundle doc. The doc still shows how to configure mapping explicitly for people wanting it elsewhere.

@linaori
Copy link
Contributor Author

linaori commented Sep 30, 2016

@stof that works fine until you want dynamically calculated paths. For KNP Snappy we resolve a path based on the OS (not using images). However, this is simply done in the load method of the extension: $container->prependExtensionConfig('knp_snappy', $snappy_config); and could easily be moved to the kernel if required.

Regarding the class cache, this is simple a set method in the kernel that is being called from a compiler pass. So in theory a custom implementation could be added but is a bit of overhead.

So while all of this is already possible, it's not really clear. In Kernel::prepareContainer all bundles' build method is being called. I was thinking that something like a new build method could add the compiler passes and being called just before the bundle build methods are called. This would also allow a prepend config to be called (ContainerBuilder:"prependExtensionConfig)

// new method in Kernel
protected function build(ContainerBuilder $container)
{
    // register compiler passes in here like in the bundle build method
}

And for the (annotated) class cache Not going to be added, see #20668

// new method in Kernel
protected function getClassesToBeCached()
{
    return array();
}

public function setClassCache(array $classes)
{
    $classes = array_merge($this->getClassesToBeCached(), $classes);
    file_put_contents($this->getCacheDir().'/classes.map', sprintf('<?php return %s;', var_export($classes, true)));
}

This means the kernel will get 3 new extension points:

  • protected function build(ContainerBuilder $container);
  • protected function getClassesToBeCached()
  • protected function getAnnotatedClassesToBeCached()

of course names are up for discussion

I think this would lay a decent foundation for something that might eventually end up as a best practice. Even if it wouldn't, it would give people a decent method to start removing their AppBundle if they wish to.

@linaori
Copy link
Contributor Author

linaori commented Sep 30, 2016

See #20107

@javiereguiluz javiereguiluz added the RFC RFC = Request For Comments (proposals about features that you want to be discussed) label Oct 2, 2016
@fabpot fabpot closed this as completed Feb 22, 2017
fabpot added a commit that referenced this issue Feb 22, 2017
…build() (iltar)

This PR was merged into the 3.3-dev branch.

Discussion
----------

Added a build method to the kernel to replace Bundle::build()

| Q | A |
| --- | --- |
| Branch? | master |
| Bug fix? | no |
| New feature? | yes |
| BC breaks? | no |
| Deprecations? | no |
| Tests pass? | yes |
| Fixed tickets | #20099 |
| License | MIT |
| Doc PR | ~ |

Adds a DX method to make it easier to omit using an AppBundle in your application.

**Old situation**

``` php
// src/AppBundle.php
class AppBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        $container->addCompilerPass(new SomeCompilerPass());
        $container->addCompilerPass(new AnotherCompilerPass());
        $container->addCompilerPass(new YetAnotherCompilerPass());
    }
}

// src/DependencyInjection/AppExtension.php
class AppExtension extends Extension
{
    public function load(array $config, ContainerBuilder $container)
    {
        $binary = ExecutableResolver::getPath($container->getParameter('kernel.root_dir').'/../');
        $snappyConfig = ['pdf' => ['binary' => realpath($binary)]];

        $container->prependExtensionConfig('knp_snappy', $snappyConfig);
    }
}
```

**New situation**

``` php
// rm src/AppBundle.php
// rm src/DependencyInjection/AppExtension.php

// app/AppKernel.php
class AppKernel extends Kernel
{
    protected function build(ContainerBuilder $container)
    {
        $binary = ExecutableResolver::getPath($container->getParameter('kernel.root_dir').'/../');
        $snappyConfig = ['pdf' => ['binary' => realpath($binary)]];

        $container->prependExtensionConfig('knp_snappy', $snappyConfig);
        $container->addCompilerPass(new SomeCompilerPass());
        $container->addCompilerPass(new AnotherCompilerPass());
        $container->addCompilerPass(new YetAnotherCompilerPass());
    }
}
```

Still missing tests, wondering if worth adding in this state first.

Commits
-------

62e80fc Added build and class cache to kernel
@stof
Copy link
Member

stof commented Feb 22, 2017

you don't need prependConfiguration at all in the kernel, as you are in the place loading the configuration itself, so you can just load an extra one before the normal call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC RFC = Request For Comments (proposals about features that you want to be discussed)
Projects
None yet
Development

No branches or pull requests

5 participants