ZF2 MVC global function - php

What is best practice for making a function/method global to the application for several controllers?
For example lets say we have a controller. This controller is using a function, but instead of copy pasting it to another controller, we just want to make a call to that function.
class ControllerName extends AbstractActionController {
// Your actions
// Has to become a call,
// instead of copy pasting this function to several controllers
public function GlobalFunction ($parameter) {
//Use parameter and return something
}
}
Creating ControllerPlugins is one solution, I've also read about creating and setting up a StdLib. So what is the best practice for a function which will only be called at the controllers?
Two other related questions:
The plugin that is described in the accepted answer will do the job. But in what case you do NOT want to use a plugin and will go for another solution? I just want to brighten it up, since I did not find enough documentation about it.
Another point of interrest. What if this plugin has to be available to several modules aswell? Setting up the plugin within the application and setting it up in the module\Application\Config\module.config.php or within the Config\Autoload\Global.php of theZend App?

You probably want to look at the several Zend\Mvc\Controller\Plugin-Classes provided. Ultimately it all depends on what your "global function" is supposed to do. It may either be suited to do it as a ControllerPlugin or it may better be suited as a functionality provided by one of your Services.
To write your own ControllerPlugin, do it like the following:
namespace Yournamespace\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class YourPlugin extends AbstractPlugin
{
public function doSomething()
{
// ...
}
}
Register your plugin at configuration, either inside getConfig() with the top-level-array-key or inside your Modules getControllerPluginConfig() without the top-level:
'controller_plugins' => array(
'invokables' => array(
'yourPlugin' => 'Yournamespace\Controller\Plugin\YourPlugin',
)
),
And simply use it:
public function indexAction()
{
$plugin = $this->yourPlugin();
$plugin->doSomething();
return new ViewModel();
}
If you just want to call $this->yourPlugin($paramX, $paramY), then you have to define a __invoke() method to your ControllerPlugin.
Hope this helps.

Related

making a helper like laravel defaullt request helper

i want to make a helper function that i use it widely in my project almost any where or some other helper functions that maybe used now as an example i have laravel request helper in mind like below :
request()->get('name);
now i know that any where in blade or controller or elsewhere if i use it it works .
now i have 2 questions .
1-how to make a helper like this that does something and can be used easily and widely
2-is that wise to make some helper like that ???
Create a helper class in app\Helpers\GlobalHelper.php
<?php
namespace App\Helpers;
class GlobalHelper
{
public static function helloWorld()
{
return "Hello World"
}
}
Then in your config\app.php in the aliases array add
'Helper' => App\Helpers\GlobalHelper::class,
Then in a blade file you can use {{ Helper::helloWorld() }} or in a controller you can use \Helper::helloWorld();
To make global helpers, you can do it like so.
Add a php file (not class) to the following the following path app/Helpers/helper.php.
if (! function_exists('helper')) {
function helper() {
return new Helper();
}
}
To make it similar to Laravels, the approach is to make an object you can call methods on the initial helper call will return.
class Helper {
public function getHelp() {
return 'did this help?';
}
}
Now get composer to autoload your file with the helper function.
"autoload": {
"files": [
"app/Helpers/helper.php"
]
}
This will enable you to call the following.
helper()->getHelp(); // returns: did this help?
For your last question.
Is is wise to make some helper like that?
In object oriented design this is an anti pattern as it deals with global functions and should be either static namespaced calls or objects. However in the context of Laravel i really enjoy what you can do with these helpers and right now, in my current project, we have global functions dealing with formatting floats to our locale money string representation that have helped a lot and is very pleasant to use.

Global helper function capable of accessing Zend objects

Currently I'm using a view-helper to help my debugging process. Basically I call this function and it checks if 1: I'm logged in as a developer by checking a Zend_Session_Namespace variable and 2: if the application is run in debug_mode using Zend_Registry. If both of them are true I show a number of different debug variables and any parameters I give the helper as input.
Originally this function was only intended to check that I got the right info in the objects assigned to the view, but I quickly discovered that it was useful in other places as well. At the moment the function works in controllers using $this->view, and I guess I could technically use something along new Zend_View(); or Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); to get a view-object in my models, but that is just plain ugly even if it's only for debugging.
So my question is: How can I rebuild this helper into a global function (usable in models, views and Controllers) and still be able to use the Zend_Session_Namespace and Zend_Registry objects, while (as far as possible) maintaining the MVC structure.
I think if you made a static class or a singleton class, you could have all of the desired functionality without breaking your MVC structure at all.
Consider the following simple class with one static function:
<?php
class My_DebugHelper
{
public static function dump()
{
$ns = new Zend_Session_Namespace('the_namespace'); // the namespace you refer to with the developer flag
$debug_mode = Zend_Registry::get('debug_mode');
if (!isset($ns->isDeveloper) || !$ns->isDeveloper || !$debug_mode) {
return;
}
foreach(func_get_args() as $arg) {
Zend_Debug::dump($arg);
}
}
protected function __construct() {}
protected function __clone() {}
}
This code gives you:
The ability to call from anywhere in your application (model, controller, helper, view etc)
All of the protections to prevent it from being executed when called out of context
A simple base that you can expand upon
Depending on your needs, at least one thing you could do is make it static so it could store some of the information rather than access it each call, or add additional methods or specialized parameters so you could pass a Zend_View object to it if necessary and have data injected into the view.
You could call it from anywhere in your application and pass one or more values to dump:
My_DebugHelper::dump($someVar, $this->view, $model->getCustId());
I'm not sure how/what your view helper displays data currently, but hopefully that will help you merge your view helper into the generic class that you can call anywhere.

Zend Framework: Pass by reference to view helper not working

Here is a simple view helper (notice the pass-by-reference argument):
class Zend_View_Helper_MyViewHelper extends Zend_View_Helper_Abstract
{
public function MyViewHelper(&$array)
{
unset($array['someExistingKey']);
}
}
This does not work in the view. $array['someExistingKey'] is still set (except within the immediate context of the method). Zend must be doing something to prevent the array from being passed in by reference. Any ideas on a solution?
When you call $this->MyViewHelper($array) from your templates you are not actually calling the helper class directly, Zend_View is instantiating the class and calling it for you. So I think you might have trouble getting this working. Your best bet is probably to use Zend_Registry, or refactor to take a different approach not requiring a global.
I just thought of a workaround. You just have to call the helper manually, instead of letting ZF call it through call_user_func_array.
Ref.php
class Zend_View_Helper_Ref extends Zend_View_Helper_Abstract
{
public function removeFromRef(&$ref)
{
// change your var value here
unset($ref['key']);
}
/**
* ZF calls this for us, but we'll call what we want, so you can skip this.
*/
// public function ref()
// {}
}
As you can see, you can skip the convention of having to name your main method as the filename, but I still recommend it.
Now, you can pass references in views/controllers:
// in view:
$this->getHelper('Ref')->removeFromRef($someVar2Change);
// in controller
$this->view->getHelper('Ref')->removeFromRef($someVar2Change);
Basically, this is what $this->ref() does: gets the helper, then calls call_user_func_array.
Some people may have problems using $this->getHelper('Ref')->ref() instead of $this->ref() though, but it works.

Do _initX() functions get called in sequence

In my bootstrap.php I have many _initX() functions, and some of them may contain code that depends on code in the previous initX
protected function _initAutoloading() { }
protected function _initViewInitializer() { }
protected function _initVariables() { }
So my question, are these _init functions guaranteed to be executed in the exact order they've been declared?
EDIT - To provide a more direct answer to your question, I would say that they probably will be since the code uses ReflectionObjects::getmethods() or get_class_methods depending on your PHP version, so I believe those will return the function in order but there is nothing in the PHP docs or Zend docs that guarantee this will always be the case, so I would not consider this a supported feature.
You can pass the names of the resource functions you want/need to call as part of the bootstrap call: $bootstrap->bootstrap(array('foo', 'bar')); instead of not passing anything and let the Zend Application call them all automatically in which you are not sure of the order.
If you have dependencies in between your bootstrap resources however, I suggest you look at Resource plugins which will allow you to separate your code in different classes and easily call $bootstrap('foo') from within your 'bar' resource plugin code (though you can do so with the _init*() functions as well)
Another benefit of resource plugins is they can be shared with other bootstrap files if you need to and they are easier to test than _init*() functions.
Make sure you read theory of operation document from the Zend Application doc
If you really need them invoked in a particular order, you should use a helper list:
var $init_us = array(
"_initAutoloading",
"_initViewInitializer",
"_initVariables",
);
function __construct() {
foreach ($this->init_us as $fn) {
$this->{$fn}();
}
}
To use that construct in ZF you could rename the example __construct into _initOrderedList and your custom _initFunctions into _myinit... or something.
Read the manual. There are a section called Dependency Tracking :
If a resource depends on another resource, it should call bootstrap() within its code to ensure that resource has been executed. Subsequent calls to it will then be ignored.
Here is sample code :
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initRequest()
{
// Ensure the front controller is initialized
$this->bootstrap('FrontController');
// Retrieve the front controller from the bootstrap registry
$front = $this->getResource('FrontController');
$request = new Zend_Controller_Request_Http();
$request->setBaseUrl('/foo');
$front->setRequest($request);
// Ensure the request is stored in the bootstrap registry
return $request;
}
}
You don't have to rely on the order.

Class Plugins in PHP?

i just got some more questions while learning PHP, does php implement any built in plugin system?
so the plugin would be able to change the behavior of the core component.
for example something like this works:
include 'core.class.php';
include 'plugin1.class.php';
include 'plugin2.class.php';
new plugin2;
where
core.class.php contains
class core {
public function coremethod1(){
echo 'coremethod1';
}
public function coremethod2(){
echo 'coremethod2';
}
}
plugin1.class.php contains
class plugin1 extends core {
public function coremethod1(){
echo 'plugin1method1';
}
}
plugin2.class.php contains
class plugin2 extends plugin1 {
public function coremethod2(){
echo 'plugin2method2';
}
}
This would be ideal, if not for the problem that now the plugins are dependable on each other, and removing one of the plugins:
include 'core.class.php';
//include 'plugin1.class.php';
include 'plugin2.class.php';
new plugin2;
breaks the whole thing...
are there any proper methods to doing this?
if there are not, them i might consider moving to a different langauge that supports this...
thanks for any help.
edit:
obviously it is my understanding that is lacking, so here is a
attempt at a clarification.
core.class.php contains anything...
plugin1.class.php contains anything...
plugin2.class.php contains anything...
include 'core.class.php';
include 'plugin1.class.php';
include 'plugin2.class.php';
$core = new core;
$core->coremethod1();//outputs plugin2method1
whereas:
include 'core.class.php';
include 'plugin2.class.php';
$core = new core;
$core->coremethod1();//outputs plugin1method1
I'm interested in any implementation, even one not involving classes
for example
include 'core.php';
//does core stuff
include 'core.php';
include 'plugin1';
//does extended core stuff
include 'core.php';
include 'plugin2';
//does extended core stuff
include 'core.php';
include 'plugin2';
include 'plugin1';
//does very extended core stuff
including a file needs to change the application behavior. for it to have any meaning.
I do not know what this is called either, so point me at the proper naming if there is any.
You are misusing the term "plugin". A plugin is generally a package of code that extends or alters the base functionality of a system - to make actual PHP plugins (which in the PHP world are called extensions) you'd be writing C or C++.
What you're describing here is merely including classes or class trees into the current execution for usage. And there is a way to bring them into the current execution context 'automatically', and that's via the autoload system.
If, after you've read the documentation on autoloading, you are still unsure of how to move forward, comment here and I will help you along.
EDIT
Ok, I see what you're after. You can't do exactly what you're after. When you execute new core; an instance of the class core will be returned - you can't modify that at all.
However, if you are willing to modify how you create instances of core, then I think I have something that could work for you, and it might look something like this.
class core {
public function coremethod1(){
echo 'coremethod1';
}
public function coremethod2(){
echo 'coremethod2';
}
/**
* #return core
*/
final public static function create()
{
// listed in order of preference
$plugins = array( 'plugin2', 'plugin1' );
foreach ( $plugins as $plugin )
{
if ( class_exists( $plugin ) )
{
return new $plugin();
}
}
return new self;
}
}
class plugin1 extends core {
public function coremethod1(){
echo 'plugin1method1';
}
}
class plugin2 extends plugin1 {
public function coremethod2(){
echo 'plugin2method2';
}
}
$core = core::create();
// test what we have
echo get_class( $core ), '<br>'
, $core->coremethod1(), '<br>'
, $core->coremethod2()
;
If your only concern is that not including plugin1 will create an error, then you can resort to autoloading to have plugin2 load plugin1 automatically:
From the comments in the PHP Manual on spl_autoload
// Your custom class dir
define('CLASS_DIR', 'class/')
// Add your class dir to include path
set_include_path(get_include_path().PATH_SEPARATOR.CLASS_DIR);
// You can use this trick to make autoloader look
// for commonly used "My.class.php" type filenames
spl_autoload_extensions('.class.php');
// Use default autoload implementation
spl_autoload_register();
If, however, you are looking for a traits/mixin-like feature, then the answer is no. PHP does not support this as of now. At least not without patching the core or resorting to these two APIs you do not want to use in production code.
The proper way to change how an object behaves at runtime would be to use Decorators:
$class = new BasicCache( new BasicValidators ( new Basic ) );
or Strategy patterns:
$class = new Basic;
$class->setStrategy(function() { return 'foo'} );
echo $class->callStrategy(); // foo
$class->setStrategy(function() { return 'bar'} );
echo $class->callStrategy(); // bar
See http://sourcemaking.com/design_patterns for the most common patterns.
EDIT Here is an example of how to create plugins with decorators. Assume, we have a game of some sort where some non-player characters walk around in a virtual space and greet the main character from time to time. That's all they do right now. We want some variation on how they greet though, which is why we need our plugins/decorators in this scenario.
First we create an interface that defines some methods any object able to greet should have. We don't care about what it does when these methods are invoked on a specific object. We just want to make sure that the methods are available and that they are called with a clearly defined input:
interface GreetInterface
{
public function greet($name);
public function setGreeting($greeting);
}
An interface is basically a contract any implementing object must fulfill. In our case, the contract says, if you are an object that can greet, you have to have two methods. Implement them any way you like, but have these methods.
Let's build our non-player character classes now, implementing this interface
class Dude implements GreetInterface
{
protected $greeting = 'hello';
public function greet($name)
{
return sprintf('%s %s', $this->greeting, $name);
}
public function setGreeting($greeting)
{
$this->greeting = $greeting;
return $this;
}
}
That's pretty straigtforward I guess. The Dude class just defines the two methods from the interface. When greet() is called, it will fetch the string stored in greeting and prepend to the param passed to the greet method. The setGreeting method allows us to change the greeting at runtime. Note: you could add a getter as well (I was just lazy)
Now on to the plugins. We will create an abstract GreetPlugin class to contain some shared boilerplate code, simply because we don't want to duplicate code in our actual plugins. The abstract plugin class will implement the GreetInterface, so we can make sure all subclasses implement the interface too.
Since Dude already implements the interface as well, we could have the plugins extend Dude, but that would be conceptually wrong, because extending creates an is-a relationship, but a plugin is not a Dude.
abstract class GreetPluginAbstract implements GreetInterface
{
protected $inner;
public function __construct(GreetInterface $inner)
{
$this->inner = $inner;
}
public function setGreeting($greeting)
{
$this->inner->setGreeting($greeting);
return $this;
}
public function greet($name)
{
return $this->inner->greet($name);
}
}
The plugin class accepts one argument when initialized: any class implementing the GreetInterface. The TypeHint makes sure, the class fulfills the contract. That's required, because, as you can see in the code, our plugins will need to call the methods in the interface on the class passed through the constructor. If we had extended from Dude, we would now be able to wrap dudes into dudes, which is a bit odd. Another reason for not doing it.
Now on to the first plugin. We want some of our dudes to speak with a fancy french accent, which means they use âccénts all over the place, but cannot pronounce a proper h. Disclaimer: yes, I know that's a cliche. Please bear with my examples
class FrenchPlugin extends GreetPluginAbstract
{
public function greet($name) {
return str_replace(array('h', 'e'), array('', 'é'),
$this->inner->greet($name));
}
}
Since the Plugin extends the abstract plugin, we can now focus on the actual code that modifies how a regular dude would do his greeting. When greet() is called, we call greet() on the wrapped element and then remove all h characters and turn all es into és. Everything else is unmodified abstract behavior.
In another plugin, we want to change the wording of the greeting, so we have some dudes say Heya, instead of just Hello. Just to add some variation.
class EasyGoingPlugin extends GreetPluginAbstract
{
protected $inner;
public function __construct(GreetInterface $inner) {
$this->inner = $inner->setGreeting('heya');
parent::__construct($inner);
}
}
This way we only override the constructor, because the greet method should just return whatever it will be. So we call the setGreeting method on the object passed to this plugin. Because the object has to implement the GreetInterface, we can be sure this works.
Note that I am assigning the return value of setGreeting as the inner object. This is possible because I return $this, whenever setMethod is called. This cannot be enforced through the interface, so you cannot rely on this form the interface. I just added it to show another technique: method chaining.
With two plugins done, we feel we have enough variation. Now we only need a convenient way to create Dudes. For that we create a small class like this:
class DudeBuilder
{
public static function build()
{
$dude = new Dude();
$decorators = func_get_args();
foreach($decorators as $decorator) {
$decorator .= "Plugin";
// require_once $decorator;
$dude = new $decorator($dude);
}
return $dude;
}
}
Note: I always mix up Builder and AbstractFactory, so if the above is a Factory, well, then it's a factory. Check out the design patterns links I gave earlier on ;)
All this Builder does, is create a regular dude and then wrap/decorate it into/with whatever plugins we tell it to use and than return it. Because the builder encapsulates no own state, we make the build method static.
For this example I assume you used the autoloading code I gave right on top. If not, you can include the plugin files in the foreach loop. Lazy loading them only when they are needed will give you a few microseconds faster load times over including them all on top. Hopefully, this also explains what I meant in the various comments when I argued the behavior should not be controlled by a file inclusion. The file inclusion is just a necessity. You cannot use a class that is not know to PHP. But that the class is actually used, is controlled by our code alone, by passing in the plugin names to the build method.
Let's do this now
$regularDude = DudeBuilder::build();
$frenchDude = DudeBuilder::build('French');
$easygoingDude = DudeBuilder::build('EasyGoing');
$frenchEasyGoingDude = DudeBuilder::build('French', 'EasyGoing');
This is effectively the same as doing:
$regularDude = new Dude;
$frenchDude = new FrenchPlugin(new Dude);
$easygoingDude = new EasyGoingPlugin(new Dude);
$frenchEasyGoingDude = new FrenchPlugin(new EasyGoingPlugin(new Dude));
With just two plugins, we can now create three types of Dudes. Let's have them greet you:
echo $regularDude->greet('Yuri'), PHP_EOL,
$frenchDude->greet('Yuri'), PHP_EOL,
$easygoingDude->greet('Yuri'), PHP_EOL,
$frenchEasyGoingDude->greet('Yuri'), PHP_EOL;
// gives
hello Yuri
éllo Yuri
heya Yuri
éya Yuri
We can now create additional plugins to decorate our basic classes with. If for some reason, you decide your game should have talking horses or cars as well, you could also create a class Car or Horse and have it implement the greet interface too and add a Builder for them. You can then reuse the plugins to create French EasyGoing Cars or Horses.
PHP core can be extended with PECL extensions (which are C++, I believe).
Core functions can be overridden (if you have the APD PECL extension installed) with override_function
User functions can be executed with call_user_func.
Maybe if you could explain what you are planning, we'd be able to offer a better answer?
Your code is breaking because plugin2 extends plugin1, and you're not including the plugin1 class. Why not make class plugin2 extend core? That seems to be what you're going for.

Categories