Skip to content

[WIP][HttpKernel] Expose bundle hierarchy/metadata as a service #19594

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
wants to merge 3 commits into from
Closed

[WIP][HttpKernel] Expose bundle hierarchy/metadata as a service #19594

wants to merge 3 commits into from

Conversation

ro0NL
Copy link
Contributor

@ro0NL ro0NL commented Aug 10, 2016

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

This is a proof of concept to expose the bundle hierarchy and metadata in a early phase. For example when needed in a bundle extension. This makes the ecosystem a lot more flexible imho.

// SomeBundleExtension.php
public function load(array $configs, ContainerBuilder $container) {
    $bundles = $container->get('kernel.bundles');
    $someBundlePath = $bundles['SomeBundle']->getPath();
}
  • Useful?
  • Fix caching (service as a definition)
  • Tests
  • Profit.

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 10, 2016

@wesleylancel noted this could perhaps be enhanced using the bundleMap property.. however that works a bit counter-wise, as you get the childs per bundle rather then parents, which are needed to construct the root VO easily. I tend to keep it this way..

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 10, 2016

Besides that, to fix the caching this parameter needs to be converted some way, some how.

We can go serialization way, or maybe introduce a ParameterValueInterface that allows for converting object to array (and vice versa), not sure how we would identify the result in cache =/

@ro0NL ro0NL changed the title [HttpKernel] Expose bundle hierarchy via parameter [WIP][HttpKernel] Expose bundle hierarchy via parameter Aug 10, 2016
@ro0NL ro0NL changed the title [WIP][HttpKernel] Expose bundle hierarchy via parameter [WIP][HttpKernel] Expose bundle hierarchy/metadata via parameter Aug 10, 2016
*
* @author Roland Franssen <franssen.roland@gmail.com>
*/
final class BundleVO
Copy link
Contributor

Choose a reason for hiding this comment

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

BundleMetadata?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Will do.

@GuilhemN
Copy link
Contributor

Why do you need that ?
Isn't Kernel::locateResource() enough ?

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 11, 2016

Main problem is the kernel as a service is not yet available when building the container (ref).

So this approach is about exposing bundle info as a parameter, so it's available in a early phase. Ie when building the container, ie extensions. Besides that, i like the way this represents your bundle ecosystem, imho it's more useful then just kernel.bundles, or locateResource. (ie. imho the profiler should show them like this, as a hierarchy)

@ro0NL ro0NL changed the title [WIP][HttpKernel] Expose bundle hierarchy/metadata via parameter [WIP][HttpKernel] Expose bundle hierarchy/metadata as a service Aug 11, 2016
@GuilhemN
Copy link
Contributor

@ro0NL as you said i think the real problem here is that the kernel is not available during compilation, maybe we should try to do that at first ?

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 11, 2016

Good point. However, im not sure we should pass the kernel around, as is, in this phase. I can imagine reasons why it's currently added afterwards, ie you can really break the ecosystem as lots of stuff is publicly accessible, not frozen, etc. Hence i chose for a VO object, to avoid passing bundle instances around at all.

But maybe someone can advice why to, or why not. I just hope we can agree this needs to be available.

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 11, 2016

I like the idea of separating the kernel from metadata/utilities, and break it down to just booting/handling/terminating etc. For metadata/utility the real kernel just uses the "kernel as a service".

Eventually im not to sure about passing the real kernel as a service (like now after building), i think it's made available for the wrong reasons (ie exposing metadata/utilities).

@GuilhemN
Copy link
Contributor

@ro0NL many things can break an app, i don't think that because someone can misuse a feature we should not include it.

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 11, 2016

Im pretty sure this is the reason it's registered after building. If not, this is as easy as moving a few lines around, so im really curious here...

@GuilhemN
Copy link
Contributor

@ro0NL no that's not that easy because the ContainerBuilder removes definitions when you use set, so the kernel service would never exist.

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 11, 2016

I havent fully investigated this yet, im still a bit unaware of inner workings here. Could you perhaps explain "the ContainerBuilder removes definitions when you use set" / point me to it.

Eventually i would like the kernel metadata to be cached as a service definition.

@GuilhemN
Copy link
Contributor

GuilhemN commented Aug 11, 2016

That's very complicated to access services during the compilation, mostly due to this.
You can't have a definition of a service and its instance manually defined in the builder.

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 11, 2016

Got it. This is hard.. what about an object being a frozen definition and a real service at the same time...

@GuilhemN
Copy link
Contributor

GuilhemN commented Aug 11, 2016

@ro0NL it could be a solution but remember that we have to deal with bc :)
Maybe we can merge your solution and eventually make it @internal for now.

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 11, 2016

Of course, i'll have look at it this weekend to work on a better poc.

@ogizanagi
Copy link
Contributor

ogizanagi commented Aug 11, 2016

Not convinced by the use cases targeted by this feature, but what about something like:

$container->set('booting_kernel', new BootingKernel($this));

where BootingKernel is a simple kernel decorator, preventing from using unsafe methods by throwing a proper exception ?

However:

Calling ContainerBuilder::get() before compiling the container is deprecated since version 3.2 and will throw an exception in 4.0.

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 12, 2016

The usecase is to have a ecosystem that allows for bugs like #6919 and #18563 to be fixed, and not have to workaround each time.

Im aware of the container builder, and how it works. I tend to go with a ServiceAwareDefinitionInterface::getService that allows for get only if the corresponding definition implements that... it's an idea ;-)

Basically i want to write an extension that acts upon bundles and the kernel.

public function __toString()
{
return $this->className;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is a __toString really necessary? If you want the class name, you can just call it from the getter

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No.. i forgot to remove it. So ignore for now.

@linaori
Copy link
Contributor

linaori commented Aug 12, 2016

I'm not entirely sure what this does yet... But will this allow the addition of a "virtual" bundle? Basically hinting towards 2 things:

  • AppKernel/Bundle merge which removes the need of the AppBundle concept
  • Autogenerating bundle information to map specific vendor packages as bundle without having to do so to prevent recurring code duplication

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 12, 2016

Yes, it should allow for virtual bundles. I dont get your 2 points fully yet, but i try to show a better POC this afternoon.

@linaori
Copy link
Contributor

linaori commented Aug 12, 2016

I've taken some snapshots of how we've currently implemented it:

class EntityPackage
{
    public function __construct($name, $path, $namespace = '', $alias = '');
    public function getAlias();
    public function getName();
    public function getPath();
    public function getNamespace();
}

// ...
public static function load(&$bundles, $file = EntityInformation::CACHE_FILE)
{
    $packages = (new EntityInformation($file))->getEntityPackages();

    // Create and append HostnetEntityBundles for all entries.
    foreach ($packages as $package) {
        $bundles[] = new HostnetEntityBundle($package);
    }
    $bundles[] = new HostnetDoctrineBundle();
}

// and in the end of registerBundles() in AppKernel
HostnetEntityBundle::load($bundles);
return $bundles;

Basically comes down to having entity packages which feature no bundle concept/dependency while still registering all of them as bundle once in symfony and hooking up their repositories to the DIC by registering them as services.

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 12, 2016

Looks creative :-) no offense. Imho this looks more event related (ideally listening to kernel boot events that is). My need is to modify the containerbuilder from a bundle extension, based on the ecosystem (kernel info, bundle info, etc.). For exmple the twig issue which needs to act upon the bundle hierarchy. Having this available as a service would be so convenient :-)

edit:

Yes, it should allow for virtual bundles.

In a way, it solves #18563 pretty easy.

Maybe to get my bigger picture, i want to decouple the way we (ab)use the KernelInterface and probably also BundleInterface classes by using/getting them as/from a service. Basically you can violate the entire boot domain logic. However i understand this could be a bridge too far, or at least should be deprecated first (use the new service instead).

See master...ro0NL:http-kernel/kernel-as-a-service to get an idea how i want to solve this. Eventually the kernel can be passed to a compiler pass, which registers/builds the kernel as a definition+service object (hence service aware definition). In early phase we have a useful kernel service object, later on, from cache we have the same service object. Via the kernel service you can get bundle vo's/metadata (anything but the real bundle interface).

@ogizanagi
Copy link
Contributor

ogizanagi commented Aug 12, 2016

@ro0NL: Why not simply allow to use (undeprecate) ContainerBuilder::get() for services set through the ContainerInterface::set() method ?
Those services are safe to use during building phase anyway, so the deprecation doesn't make much sense for them, only resolving service's definitions does, right ?

@ro0NL
Copy link
Contributor Author

ro0NL commented Aug 12, 2016

Im not sure.. i can imagine this is a design choice. There are 2 phases (building and runtime), where there's only 1 container per phase (respectively ContainerBuilder and Container) available. Basically in between compiling happens...

However due the 1st phase we cant use it as a container throughout as it cant guarantee safe services yet (not fully built) when getting. Why setting direct (fully built) services is not allowed, im not sure.. like i said i guess it's a design choice:

The ContainerBuilder can be used as is (the instance you have) as a Container only after compiling (to ensure safe services), the role of set() is that it must match with an existing definition. I cant fully explain the latter, but it makes sense in a way. I guess technically we need another container that is ready.

Anyway, to adhere to all this, i chose for true service objects representing the ecosystem (ie they have a corresponding definition), which allows it to work in both phases (it introcudes a design change though to do that, so im curious about it). Eventually this allows also for separation of concerns (the kernel (functional), and kernel-service (informational/util)). To clarify, Kernel::locateResource is not used by the kernel itself..

edit: master...ro0NL:http-kernel/kernel-as-a-service is a better poc now, so i guess im gonna close this one in favor of a new PR.

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.

6 participants