I know how to pass parameters to a normal action helper that's called in the action itself. But this time I'm doing it in the Bootstrap using HelperBroker::getStaticHelper
$hooks = Zend_Controller_Action_HelperBroker::getStaticHelper('Test');
Zend_Controller_Action_HelperBroker::addHelper($hooks);
I want to pass a parameter so I added the middle line
$hooks = Zend_Controller_Action_HelperBroker::getStaticHelper('Test');
$hooks->preDispatch($input);
Zend_Controller_Action_HelperBroker::addHelper($hooks);
and the preDispatch is this
public function preDispatch($input){
var_dump($input);
}
The strange thing is that var_dump shows me the input, but I also get this error
Warning: Missing argument 1 for Test::preDispatch(),
Notice: Undefined variable: input
preDispatch() is a hook called in dispatch loop. You shouldn't use it like this.
Zend_Controller_Action:
/**
* Dispatch the requested action
*
* #param string $action Method name of action
* #return void
*/
public function dispatch($action)
{
// Notify helpers of action preDispatch state
$this->_helper->notifyPreDispatch();
...
$this->_helper->notifyPostDispatch();
}
Also this code is ambiguous:
Zend_Controller_Action_HelperBroker::addHelper($hooks);
Action helper was registered within helper broker by getStaticHelper() method call
You should make it like this:
class MyHelper extends Zend_Controller_Action_Helper
{
const BAR = false;
public function preDispatch($request)
{
$this->ifBarExit(self::BAR);
}
public function ifBarExit($barValue)
{
if ($barValue) {
exit('Bar was true!');
}
}
}
The preDispatch thinks it's first variable is request object - it's how it'S wired in the ZF's internals.
But now with the new function you can do:
$helper = Zend_Controller_Action_HelperBroker::getStaticHelper('MyHelper');
$variable = true;
$helper->ifBarExit($variable); //won't exit
You shouldn't mess with the internal methods (i.e. call them) for your own vilain plans. If you want to inject something in the helper, don't pass it directly. Add member variable and sth like $helper->setImportantThing($thing); which will save it into protected $_thing; and then inside the method echo $this->_thing;
Related
I have made my own class
<?php
namespace App\Çonsole;
use App\KernelSetting;
class Setting
{
/**
* #param $setting
* #return
*/
function KS($setting)
{
return KernelSetting::where('setting', $setting)->first()->value;
}
}
Now I am calling it like this Setting::KS('review_time_limit')
How do I return the value from the database entry I get?
I get this
Non-static method App\Console\Setting::KS() should not be called statically
The error message is pretty clear, you need to make the method static in order to call it like that.
static function KS($setting)
{
return KernelSetting::where('setting', $setting)->first()->value;
}
You can read more about static here :
https://www.php.net/manual/en/language.oop5.static.php
I get an error:
Type error: Too few arguments
I thought Laravel do some magic to if arguments is not fully passed?
For example:
In the Controller I have:
public function create(CreateRequest $request)
{
return $this->todoService->createList($request);
}
In the todoService class:
use App\Plan
class todoService {
public function createList($request, Plan $plan)
{
//
}
}
As you can see I did not pass Plan class object. Do I have to bind or something?
If you are calling createList() by yourself so you will need to pass both parameters by yourself. You can bind something with Plan but still if you will call something not Laravel, then you will be responsible to pass that function parameters.
This type hinting only works if Laravel is calling that function. So you need to call these functions through Laravel.
If you are trying to automatically injecting in a class's constructor, you can simply do this:
$service = $this->app->make('App\Plan\todoservice');
or
$service = App::make('App\Plan\todoservice');
or
$service = resolve('App\Plan\todoservice');
But this will only work for Constructors. Please note that you can also provide parameters as next arguments of make() or resolve() function.
In fact, different methods can also be called that way.
You can simply do:
$service = App::make('App\Plan\todoservice');
$container->call([$service, 'createList'], ['request' => $request] );
Here $container is object of Illuminate\Contracts\Container\Container.
You have to bind classes only if they depend on interfaces. If you specify particular class, reflection will do the job for you. documentation
The only way this will work, is to set the default value of second parameter. In any other situation, syntax exception will be thrown.
use App\Plan
class todoService
{
public function createList($request, Plan $plan = null)
{
//
}
}
public function create(CreateRequest $request)
{
return $this->todoService->createList($request);
}
It will work, but will that make any sense?
Laravel cannot do any magic on this level as your coding error is simply a PHP syntax error. You're indicating that the second parameter is of type Plan, which makes it mandatory implicitly. Laravel cannot 'patch' simple function calls like this.
Your confusion is likely in that, depending on your routing, Laravel can inject the correct Plan parameter into the create controller method, thus allowing you to forward it into the service.
/**
* Create a new personal access token for the user.
*
* #param string $name
* #param array $scopes
* #return \Laravel\Passport\PersonalAccessTokenResult
*/
public function createToken($name, array $scopes = [])
{
return Container::getInstance()->make(PersonalAccessTokenFactory::class)->make(
$this->getKey(), $name, $scopes
);
}
/**
* Set the current access token for the user.
*
* #param \Laravel\Passport\Token $accessToken
* #return $this
In CakeDC comments plugin for CakePHP documentation states that:
Component callbacks
It is possible to override or extend the most comments component
methods in the controller. To do this we need to create method with
prefix callback_comments Examples:
callback_add will named as callback_commentsAdd in controller,
callback_fetchData will named as callback_commentsFetchData in
controller. ...
It works from the controller perfectly!:
public function callback_commentsInitType() {
return 'flat'; // threaded, tree and flat supported
}
I wonder, what is the new feature of cakephp-2.0 that allows you to do that? I need to understand how it was achieved to be able to implement such methodology in the future on my components.
In the code of the component, if you look at the following function in this file (starting from line number 622):
/**
* Call action from commponent or overriden action from controller.
*
* #param string $method
* #param array $args
* #return mixed
*/
protected function _call($method, $args = array()) {
$methodName = 'callback_comments' . Inflector::camelize(Inflector::underscore($method));
$localMethodName = 'callback_' . $method;
if (method_exists($this->Controller, $methodName)) {
return call_user_func_array(array(&$this->Controller, $methodName), $args);
} elseif (method_exists($this, $localMethodName)) {
return call_user_func_array(array(&$this, $localMethodName), $args);
} else {
throw new BadMethodCallException();
}
}
You can see that the variable $methodName is being defined with prefix callback_comments and then the passed $method is appended to it after being treated by the Inflector::underscore and then Inflector::camelize method. The working of these is as follows:
Inflector::underscore will convert initType to init_type. Check doc here.
Inflector::camelize will further convert init_type to InitType. Check doc here.
Now, if initType was passed in the argument, then the $methodName will be:
callback_comments + InitType = callback_commentsInitType
After this, a $localMethodName is also being generated. In our initType example, it will be:
callback_ + initType = callback_initType
After the names have been generated, it will simply search if the method exists in the attached controller and will execute it using call_user_func_array function by passing it and array with the object (in our case, the controller object (&$this->Controller) or the component object itself (&$this)) containing the method and the $methodName as first argument and then $args as second argument.
If the function was not found in the controller, then it will instead search in the component with $localMethodName. If it's found, then it is executed the same way.
Now how all this works is that the _call function is the single function used to call all the internal functions of the component, so that it will first check if the function has been overwritten in the controller, otherwise it will execute the function in the component itself.
You can check the component's beforeRender function here and you'll see how the initType function is called. In this case, if the controller contains a function named callback_commentsInitType, then it will be executed. Otherwise, the components callback_initType will be executed.
Hope this helps..
If you have a class that responds differently depending upon constructor arguments, how do you go about writing a spec for that class?
class Route
{
function __construct($url, array $methods = array())
{
// stores methods and url in private member variables
// creates a regex to match $url against incoming request URLs
}
public function isMatch($url)
{
// checks if the incoming request url matches against this url
}
}
Example use:
$a = new Route('/users/:id');
$a->isMatch('/users/1') // returns true;
$b = new Route('/users');
$b->isMatch('/users') // returns true
If I set up my spec for this class using the let function from phpspec:
class Route extends ObjectBehaviour
{
function let()
{
$this->beConstructedWith('/users/:id')
}
}
My spec can only check if the behaviour of this class works in one of the cases.
I've contemplated adding setter methods to allow me to test around this, but it seems like I'd be breaking encapsulation for the purpose of testing.
I'm struggling to find anything that touches upon this, so I'm started to think that maybe this is bad code smell situation.
beConstructedWith() doesn't always need to be called from the let() method. You can call it from the specs as well.
In my opinion there's nothing wrong in setting up an object in more than one way. However, you should avoid doing too much work in the constructor.
Constructor should be used only to obtain variables that will be set to a member properties here. No further logic should be done here...
Following the idea from point 1 there should be another logic that determines what happens next (e.g. if Object->hasProperty(X) then do x(), etc.)
Then a comment would be plain and straight forward.
Example:
class Route
{
private $url;
private $methods = array();
/**
* Constructor method, sets the attributes to private member variables
* #param string $url URL pattern
* #param array $methods Methods that should be used with given URL
*/
function __construct($url, $methods = array())
{
$this->url = $url;
$this->methods = $methods;
}
// ...
}
Hello I am trying to retrieve the values returned by a controller action in my own library abstract in one of the methods of dispatch of Zend Framework, I wonder if this feat possible and if so how do it.
My code is as follows:
IndexController
class IndexController extends My_Controller
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
// action body
return 'hello world';
}
}
My_Controller
abstract class My_Controller extends Zend_Controller_Action
{
/**
* Initialize Core_Controller
* #param Zend_Controller_Request_Abstract $request
* #param Zend_Controller_Response_Abstract $response
* #param array $invokeArgs
*/
public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array())
{
parent::__construct($request, $response, $invokeArgs);
$this->_helper->viewRenderer->setNoRender();
}
public function preDispatch()
{
//something here
}
public function postDispatch()
{
//something here
}
public function dispatch()
{
//something here
}
}
I need to get the value of what was returned in the controllador in this library in order to transform it into json and then print to screen.
Thnk
In ZF 1 there isn't a way to get the return value from the controller action. This value is never used or captured by Zend Framework itself.
Take a look at Zend/Controller/Action.php line 516 (ZF 1.11.11) and this is the point where ZF calls your controller action, and the return value is not captured or used.
public function dispatch($action)
{
// Notify helpers of action preDispatch state
$this->_helper->notifyPreDispatch();
$this->preDispatch();
if ($this->getRequest()->isDispatched()) {
if (null === $this->_classMethods) {
$this->_classMethods = get_class_methods($this);
}
// If pre-dispatch hooks introduced a redirect then stop dispatch
// #see ZF-7496
if (!($this->getResponse()->isRedirect())) {
// preDispatch() didn't change the action, so we can continue
if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) {
if ($this->getInvokeArg('useCaseSensitiveActions')) {
trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');
}
$this->$action(); // <--- line 516 - this calls your action
} else {
$this->__call($action, array());
}
}
$this->postDispatch();
}
// whats actually important here is that this action controller is
// shutting down, regardless of dispatching; notify the helpers of this
// state
$this->_helper->notifyPostDispatch();
}
As you can see, the value returned by the controller is never used. Also, in ZF2, they are changing the way controller actions work so the return values actually have meaning so you may want to think of a different approach.
The quickest thing I can think of at the moment would be instead of trying to return a value from the controller, just set a registry value that you can fetch later.
e.g.
public function returnAction()
{
// ...
Zend_Registry::set('controller_return_value', 'hello world');
}
and then later, in your plugin or wherever you are trying to get the value:
try {
$retval = Zend_Registry::get('controller_return_value');
} catch (Zend_Exception $ex) {
$retval = null; // no return value set by controller
}