Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

[ZF3] Thinking component as module #5524

Closed
bakura10 opened this issue Nov 22, 2013 · 11 comments
Closed

[ZF3] Thinking component as module #5524

bakura10 opened this issue Nov 22, 2013 · 11 comments

Comments

@bakura10
Copy link
Contributor

Hi everyone,

This follows a discussion I had with @Ocramius yesterday.

Currently, the way plugin manager are configured inside the framework is a bit messy to my opinion. Most plugin manager factories are registered in the Mvc namespace (https://github.com/zendframework/zf2/tree/master/library/Zend/Mvc/Service). This introduces a soft dependency to each of those components in the Mvc namespace, and everyone that want to use those factories require the Mvc component.

The idea is to move each of those things to the given components. This make it REALLY easier to discover how plugin managers are constructed. The same apply for view helpers or filters (we already did that).

Now, the second problem is classes like that: https://github.com/zendframework/zf2/blob/master/library/Zend/Form/View/HelperConfig.php

Those are nothing more than view helpers. What would be good would be to allow each component to have a config that would be merged. Not sure about the syntax yet, but for instance, the Form component could have a config like that:

return array(
    'view_helpers' => array(
        'invokables' => array(
             // Add form specific helpers
        )
   )
);

This is usually what is done in third-party modules.

Next, ViewHelperPluginManagerFactory (which will be situated in the Zend\View component, and not in the Zend\Mvc namespace), will do something like that:

class ViewHelperPluginManagerFactory implements FactoryInterface
{
    public function createService($sl)
    {
        return new ViewHelperPluginManager($sl->get('Config')['view_helpers']);
    }
}

The beauty of this is that it will aggregate both ALL the view helpers specified inside the framework and in the ones specified by third-party modules.

What I'd like is to use inside the framework all the best practices we have accumulated in modules.

Now, the Zend\View would also define it's own config:

return array(
    'service_manager' => array(
        'factories' => array(
            'Zend\View\ViewHelperPluginManager' => 'Zend\View\Factory\ViewHelperPluginManagerFactory'
        )
    )
);

Drawbacks

If we consider each component as a module, it may have some performance drawbacks. But I think we could have a lighter way to handle ZF3 components.

@devosc
Copy link
Contributor

devosc commented Nov 24, 2013

With a ServiceRequest, it might be possible to make the PluginManager a factory instead?

class ViewHelperPluginFactory implements FactoryInterface
{
    public function createService($sl, $serviceRequest)
    {
        return //.. something
    }
}
public function plugin($name, array $options = null)
{
    $service_name = 'ViewHelperPluginFactory';

    $service_options = array(
       'name'    => $name,
       'options' => $options
    );

    $serviceRequest = new ServiceRequest($service_name, $service_options);
    $serviceRequest->notShared();

    return $this->getServiceManager()->get($serviceRequest);
}

@devosc
Copy link
Contributor

devosc commented Nov 24, 2013

@Ocramius, in this case ViewHelperPlugin is a ServiceRequest?

public function plugin($name, array $options = null)
{
    return $this->getServiceManager()->get( new ViewHelperPlugin($name, $options) );
}

@juriansluiman
Copy link
Contributor

The thing you're doing with this kind of flow is making all components based on the service locator. I am not sure if that's what we really want. Obviously, plugin managers can already depend on the SM (note, not all do! Some places use the more lightweight Zend\Loader\PluginClassLoader), but not every component has a plugin loader.

So if all components should rely on this pattern, you imply all components are using the SM in some sort of way. We really should consider the consequences this might cause. I am not against this per se (standardisation is a good thing), but we must check the negative impact as well.

@bakura10
Copy link
Contributor Author

Well... Not exactly. Service manager would indeed be a soft dependency for all components, but as you said, plugin managers ARE service managers, so if they want to use plugin managers, they will have a dependency to SL anyway.

@devosc
Copy link
Contributor

devosc commented Dec 1, 2013

Some quick thoughts; I ran into a similar issue with https://github.com/zendframework/zf2/blob/master/library/Zend/Mvc/Router/Http/TreeRouteStack.php where it seems as if it would be nicer if all those class mappings were just in the main application configuration of the service manager.

It also looks like the AbstractPluginManager is not much more than a factory, which makes things trickier since we'd want to know which factory to use and possibly which class to use (if it is not in the same namespace). Which suggests that it might be easier to specify the factory rather than the actual class, e.g

return array(
    'service_manager' => array(
        'factories' => array(
            'View\Helper\BasePath'    => 'Zend\View\Helper\Factory',
            'View\Helper\Cycle'       => 'Zend\View\Helper\Factory',
            'View\Helper\DeclareVars' => 'Zend\View\Helper\Factory',
        )
    )
);

Which could be simplified further by having a service manager config for the default factory to use unless one has been explicitly set for that plugin/helper.

@Ocramius Ocramius added this to the 3.0.0 milestone Apr 4, 2014
@bakura10
Copy link
Contributor Author

bakura10 commented Jan 1, 2015

For ZF3, what about creating a new component, called Zend\Application, whose task will be to only include a script that will automatically add the component as a module: https://getcomposer.org/doc/articles/scripts.md#defining-scripts

Each component will have its own scripts section so that it auto-registrate into the "modules" list. Each Zend component will have a name like "Zend\ServiceManager".

This way, we avoid any hack, we make everything consistent, and this will allow to cleanly solve the issue?

@bakura10
Copy link
Contributor Author

bakura10 commented Jan 1, 2015

Mmhhh nvm, this only apply to root composer.json, so this will likely does not work.

@gianarb
Copy link
Contributor

gianarb commented Jan 2, 2015

@bakura10 remove Mvc solf dependencies for my is very important task.. #6587 👍
But maybe we can create an ApplicationModule (not a component) to configure a base blob between a ZF2 base app and other components for example configuration of controller plugins and view helpers..

@weierophinney
Copy link
Member

The one big issue I see with the proposal to have each component as a module is performance. If we consider every component a module, then by default we have to load:

  • ~50 Module classes (one for each component; we have 50 in the current ZF2 distribution; we'll have more — hydrator, diactoros, possibly stratigility — in ZF3, though we'll also likely remove a number of them as "not core").
  • Dozens of configuration files (not all components would have a config file; some might have multiple).

which leads to a lot of memory and I/O overhead. I'd rather see this stuff defined in the skeleton application, to be honest, as we can then have use-case specific skeletons that selectively provide the configuration.

@gianarb
Copy link
Contributor

gianarb commented Jun 25, 2015

Maybe All is a wrong word..
We can start from this list
https://github.com/zendframework/zend-mvc/blob/master/composer.json#L22

        "zendframework/zend-authentication": "~2.5",
        "zendframework/zend-cache": "~2.5",
        "zendframework/zend-console": "~2.5",
        "zendframework/zend-di": "~2.5",
        "zendframework/zend-filter": "~2.5",
        "zendframework/zend-http": "~2.5",
        "zendframework/zend-i18n": "~2.5",
        "zendframework/zend-inputfilter": "~2.5",
        "zendframework/zend-json": "~2.5",
        "zendframework/zend-log": "~2.5",
        "zendframework/zend-modulemanager": "~2.5",
        "zendframework/zend-session": "~2.5",
        "zendframework/zend-serializer": "~2.5",
        "zendframework/zend-text": "~2.5",
        "zendframework/zend-uri": "~2.5",
        "zendframework/zend-validator": "~2.5",
        "zendframework/zend-version": "~2.5",
        "zendframework/zend-view": "~2.5",

There are a lot of type of dependencies.. IMO

## Required

  • zend-uri to manage routing
  • zend-view because is an M_V_C
  • zend-http to request and response management

Integration dependency

  • zend-authentication because an MVC will be unauthenticated
  • zend-session
  • zend-text
  • zend-i18n
  • zend-log
  • zend-cache
  • zend-filter
    ....

Out of date dependency

  • zend-version after split this package is unused

This is only a superficial analysis but the idea is "what is MVC pattern?"

  • Model with its dependencies (what??)
  • View with its dependencies (zend-view, zend-serializer)
  • Controller with its dependencies (Router, http)

Authentication, ModuleManager, Validator are a "doping"...

@GeeH
Copy link

GeeH commented Jun 27, 2016

This issue has been closed as part of the bug migration program as outlined here - http://framework.zend.com/blog/2016-04-11-issue-closures.html

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants