zf2 : module with pluggable plugins approach - php

I have some basic ZF2 knowledge for creating normal projects. Now I want to create a module which is extendable by user community by creating plugins for its features.
I have created basic architecture like
ModuleName
src
Service
MyService.php
Factory
Fun1Factory.php
Fun2Factory.php
Plugins
Fun1Plugins
PluginA.php
PluginB.php
Fun2Plugins
PluginC.php
PluginD.php
I have created two factory classes ( not from zf2 factoryinterface) for handling each type of functionality like Fun1Factory.php & Fun2Factory.php. They both are registered in module.config.php through invokables.
'invokables' => array (
'Fun1Factory' => 'ModuleName\Factory\Fun1Factory',
'Fun2Factory' => 'ModuleName\Factory\Fun2Factory',
)
Now MyService actually calling them with arguments for specific plugins. Like below.
$fun1Factory = $this->getServiceLocator()->get('Fun1Factory');
$fun1Factory->setSettings($settings['fun1']);
$this->fun1Plugin = $fun1Factory->getPlugin();
$this->fun1Plugin->init();
$fun2Factory = $this->getServiceLocator()->get('Fun2Factory');
$fun2Factory->setSettings($settings['fun2']);
$this->fun2Plugin = $fun2Factory->getPlugin();
$this->fun2Plugin->init();
So code can be called like that
$service = $this->getServiceLocator()->get('ModuleName\Service\MyService');
$service->init(array('fun1' => 'pluginA', 'fun2' => 'pluginD'));
I earlier built similar using basic MVC + Factory Pattern. But I don't know how it should be build into ZF2. ZF2 give factory interface, but that look like a very similar to autoload some service/controllers. If their are any guide how to create a such module ?
UPDATE : I can do factory code also in MyService class. But I am thinking of "ZF2 WAY" to doing this.
MORE DETAILS : I have update question wtih more details. The closest I found at https://samsonasik.wordpress.com/2014/01/29/zend-framework-2-getting-closer-with-pluginmanager/ . But I still need to dynamically register plugin to factory instead of statically in there like below.
protected $invokableClasses = array(
//represent invokables key
'xls' => 'Tutorial\Plugin\Xls',
'pdf' => 'Tutorial\Plugin\Pdf'
);

If you do not want plugin creators having to modify the service_manager at the module.config.php then you have two options:
An option is creating a Factory for MyService that will look for its dependencies in those plugin folders.
Other option would be creating an invoke method for MyService passing the plugin as an argument and then you create the plugin instance.
But the way zf2 works is using module.config.php to register instances in the service_manager. So if the plugin creators can use the service_manager will be better.
[UPDATE]
Zend FactoryInterface is used for creating instances which have dependencies, so those dependencies are created or extracted from the ServiceManager and then they are injected via constructor to the instance the factory has been created for.
In your case your plugin developers would have to create factories for their plugins and register those factories in the service_manager. If they didn't then you need a way to know if a plugin has dependencies.
Hope this helps
Ismael Trascastro

Related

php - Conflicting view helper names in Zend Framework

I am using a module called Facebook which has a view helper called shareUrl. This view helper gets the Facebook share URL for any URL.
However, I have recently added another module called Twitter which also has a view helper called shareUrl.
In Zend Framework version 2 or 3, within views, how can I call one shareUrl view helper versus the other?
Just to clarify, the code in my view looks like the following:
$facebookShareUrl = $this->shareUrl('https://www.example.com/');
$twitterShareUrl = $this->shareUrl('https://www.example.com/');
I would like $facebookShareUrl and $twitterShareUrl to store the return values of two different view helpers.
If you've got two helpers with the same name, only one is available as it is registered under the given name within the servicemanager (viewhelpermanager). If you switch them around with loading the modules in your application.config.php you can change the default. But that is not a real solution to your problem.
So there are multiple ways to get the right viewhelper you need.
1) The best way is to setup an alias for the registered viewhelpers using their FQCN. See some example code where we create aliases that can be used in the viewherlpers like $this->facebookShareUrl('exmaple.com')
return [
'view_helpers' => [
'aliases' => [
'facebookShareUrl' => FacebookModule\Helper\ShareUrlHelper::class,
'twitterShareUrl' => TwitterModule\Helper\ShareUrlHelper::class,
],
]
]
2) Get the helper by its FQCN using the viewhelpermanager in the view itself, using the PhpRenderer instance. Within a view.phtml file
$viewHelperManager = $this->getHelperPluginManager();
$facebookShareUrlHelper = $viewHelperManager->get(FacebookModule\Helper\ShareUrl::class);
$twitterShareUrlHelper = $viewHelperManager->get(TwitterModule\Helper\ShareUrl::class);

Future Proofing Changes to Validation of Username/Password Field in ZFCUser

I've been looking around at how to change the actual validation process of the registration fields in the ZFCUser module in Zend Framework 2.
There is a lot about extending and adding new fields etc. to the form but not validating these fields or extending the existing validation.
I have taken a look inside the code and found the RegistrationForm.php file and added my customer Regular Expression filters.
This works well and as expected but I am worried about this being over-written on any future upgrade.
How would I go about doing this so it is upgrade safe? Is it a case of extending a specific class or adding it as a local file in my custom modules as I have done with the view files.
I've same problem as you, and also do not find proper solution. But IMHO better way than change original source code is to override one of the ZfcUser services.
There is a service called 'zfcuser_change_password_form' defined in zfc-user Module.php. If you create own service with same name - the original one will be overriden. So, first you need to define your own filter / validator class (YourFilter), then in your Module.php add:
public function getServiceConfig()
{
return array(
// ...
'factories' => array(
// ...
'zfcuser_change_password_form' => function ($sm) {
$options = $sm->get('zfcuser_module_options');
$form = new \ZfcUser\Form\ChangePassword(
null, $sm->get('zfcuser_module_options')
);
$form->setInputFilter(
new \YourModule\Form\YourFilter($options)
);
return $form;
},
),
);
}
Such solution allows to update zfcuser without overriding your changes.

Laravel authentication bundle

I'm pretty new to Laravel, I've spent some time reading about it and doing some tutorials. Lately, I've been following this tutorial about creating an authentication bundle:
http://net.tutsplus.com/tutorials/php/build-your-first-admin-bundle-for-laravel/
Basically, it's creating a simple custom auth driver extending the default auth one. Everything works quite nicely.. inside the bundle. My problem is more about how to use/access this admin/login bundle in my main application. I feel a bit ashamed asking this, I guess it has something to do with loading/starting the admin bundle in my application controller(s), but i can't get it to work.
Thank you
You have a couple of options, you can either start the bundle manually from within your application controllers each time by calling:
Bundle::start("<Your Bundle Name>");
Or when you register the bundle with Laravel (when you add it to /application/bundles.php) you can also choose to autoload it:
return array(
// ... other bundles
"<Your Bundle Name>" => array("auto" => true),
);
From looking at the tutorial this might look something like:
'admin' => array('handles' => 'admin', 'auto' => true)
Once you have either started the bundle manually, or autoloaded it, you can then call the bundle classes directly (make sure you use the proper namespace when calling the class).
You can also check out Laravel's documentation.

Where do I save Zend_Form files?

I'm trying to learn Zend Framework! I'm quite interested in it but I can't find a tutorial which says where it's suppoused to be a Zend_Form class stored! Maybe it's something quite straightforward but I can't get it yet...
I've seen tutorials about this:
<?php
class Form_Example extends Zend_Form
{
public function init()
{
// Great code here
}
}
But none of them said where this code goes????? In a file in which folder in the directory tree?? I've read and I understand and I've done a little example with modules, controllers, actions, layouts and I know the importance about name conventions and the folder structure. So where does this form class must go and how can I call it from a view??
Thanks a lot, I know this must be easy for someone who already knows how to work well with Zend Framework =)
The best way to do this is to let ZF do it for you. ZF ships with a command line interface for both windows and *nix.
At the command line you can type zf create form Example, ZF will then create an empty form named Example.php at it's default application level location.
Typically this will be at application/forms/Example.php and the classname will be Application_Form_Example.
If you need to have a form constructed in a module the command would be similar:
zf create form Example -m admin where -m indicates you want the file created in a module and admin is name of the module.
Forms are one of the predefined resources in Zend Framework and as such have a default location. There are several other resources that are predefined and have defaults.
The Module Resource Autoloader
Zend Framework ships with a concrete implementation of
Zend_Loader_Autoloader_Resource that contains resource type mappings
that cover the default recommended directory structure for Zend
Framework MVC applications. This loader,
Zend_Application_Module_Autoloader, comes with the following mappings:
forms/ => Form
models/ => Model
models/DbTable/ => Model_DbTable
models/mappers/ => Model_Mapper
plugins/ => Plugin
services/ => Service views/
helpers => View_Helper
filters => View_Filter
As an example, if you have a module with the prefix of "Blog_", and attempted to instantiate the class
"Blog_Form_Entry", it would look in the resource directory's "forms/"
subdirectory for a file named "Entry.php". When using module
bootstraps with Zend_Application, an instance of
Zend_Application_Module_Autoloader will be created by default for each
discrete module, allowing you to autoload module resources.
I normally have all my forms in a forms folder, alongside the models, controllers, and views.
So, my file structure looks like:
application ->
configs
layouts
plugins
controllers
models
views
forms ->
form1.php
form2.php
Using them in your application isn't quite so simple. You must instantiate the form class in your controller, then pass the form to your view. So in your controller you want something like:
$form1 = new Application_Form_Form1($options);
$request = $this->getRequest();
if($request->isPost()) {
if($form1->isValid($post)) {
// form is valid, do form processing here
}
}
$this->view->form1 = $form1;
Then inside of your view file, you place the form:
<html>
<body>
<div id="body">
<?php echo $this->form1; ?>
</div>
</body>
</html>
At the heart of your question are the issues of:
autoloading
how the ZF autoloader works in general, and
how the ZF autoloader is configured by default in a standard ZF app
which are actually three distinct, though clearly-related, issues.
Assuming that you have the default ZF installation in which the appnamespace is set to "Application", then name your form class Application_Form_Example and store it in the file application/forms/Example.php.
Then you can instantiate (in a controller, for example) using:
$form = new Application_Form_Example().
Make sure that you have resources.modules[] = in application/configs/application.ini.
For additional discussion about autoloading, see https://stackoverflow.com/a/10933376/131824

zf2 resolve module view path

Starting from the skeleton application using beta3 how would you resolve the view path for a new module called Foo?
I have added below to the di config and now both modules action's render Foo's views.
'Zend\View\Resolver\TemplatePathStack' => array(
'parameters' => array(
'paths' => array(
'foo' => __DIR__ . '/../view',
),
),
),
I would expect Application\Controller\IndexController::indexAction() to render the views in Application and for Foo\Controller\IndexController::indexAction() to render Foo's views.
Note that questions like this help shape the direction of the stable framework. :)
One idea I've been toying with is to use the module as part of the view script resolution. Right now, the default used is "/"; my proposal is to use "//", as this would help prevent naming conflicts between modules; it also makes it much simpler to understand exactly what view script you are overriding if you use template maps.
You can use this approach today, but it will require manually setting the template on the view models you return from your controllers.
This doesn't currently work in ZF2 as there is no concept of taking the namespace into account when resolving view scripts. Discussions are currently ongoing on how best to tackle this.
For the time being, you have to name each controller differently. In general, we are recommending that you name the "primary" controller within a module after the module name. That is, the primary controller in the Foo module would be FooController.
You actually can do this; and it is not too bad....
Rob Allen himself had a blog post that basically makes this work... Notice you have to basically handle it as a module based loader that separates much of the work out so that we don't have controllers utilizing it: http://pastie.org/3824571

Categories