I'm going to structure this as best I can. Basically I have a Hook class that works by adding supplied hooks.
An example of this would be:
$this->registry->hook->add('HOOK_NAME', 'CLASS_NAME||METHOD_NAME')
The hook adding, calling, removing functions work great, now the issue resides when I set the hook in a separate method in a completely different class.
An example of this would be when a user logs in.
The path they take is User Controller -> Form Class -> Login Process Function
Now within this login process function, I'd like to set a hook to be called later to end the session. (Would be added as stated above)
The issue seems to be that it gets set but doesn't stay persistently, if that makes sense?
If anyone is interested, this is what the hook add function looks like:
function add($hook, $callback, $params = '') {
//make sure the hook is defined
if (!isset($this->hooks[$hook])) {
$this->hooks[$hook] = array();
}
//add the callback to the hook
$this->hooks[$hook]['callback'] = $callback;
// add the params if supplied
if (!empty($params)) {
$this->hooks[$hook]['params'] = $params;
}
}
Should I be using magic methods __set() and __get() ?
Any help would be appreciated! :)
Related
Some add_action() statements that i see now and then are provided with an array in which the first argument is $this, and the second one, the function.
As far as i know, $this stands as the current instance in POO, but what about in this particular case? Let's say for the sake of example that we have a newsletter system that registers your email adress, except if it still exists in the database.
<?php
public function save_email()
{
if (isset($_POST['zero_newsletter_email']) && !empty($_POST['zero_newsletter_email'])) {
global $wpdb;
$email = $_POST['zero_newsletter_email'];
$row = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}zero_newsletter_email WHERE email = '$email'");
if (is_null($row)) {
$wpdb->insert("{$wpdb->prefix}zero_newsletter_email", array('email' => $email));
}
}
}
Now we need to declare it as an available action. why should we need an array like this one?
add_action('wp_loaded', array($this, 'save_email'));
And why couldn't we simply do as followed?
add_action('wp_loaded','save_email');
Because save_email is a class method and we're adding the action from $this class instance (i.e. from within the class owning the method).
The array represents a PHP callable, see type 3 in the example: http://php.net/manual/en/language.types.callable.php
This is too long for a comment.
$this is the current instance of the current class. So it would be the instance invoking the hook. Or the class the action is being added in.
add_action('wp_loaded', array($this, 'save_email'));
So this is the save email in the current class.
And why couldn't we simply do as followed?
add_action('wp_loaded','save_email');
Because you can't ... Just kidding.
this is due to using call_user_func_array
http://php.net/manual/en/function.call-user-func-array.php
Which is the built in way of doing it. I am sure it also has to do with how functions are called, because without the class it would be ambiguous if this was a function or a method of a class.
In the case you present, PHP would think that was a function. Even if there was a way to tell it, it wasn't, how would you tell it what class that method is in. So it's easier and safer to just put the class in...
Hi I have a class which includes two methods.
One of which is to initialize session , another one is for redirect the web page
I ve written the class such that it can be called repeatedly.
$obj->setSession(key,value)->redirect(url);
In this mode , the session is firstly initialized and then it redirects to the next page.
But if it's written like this
$obj->redirect(url)->setSession(key,value);
It just redirects to the defined location qnd the session is not initialized anymore ..
It s cuz when the resirect method is called, the page changes promptly and it causes the second method not to be called ..
Is there any way to be able to call methods repeatedly without the need of considering their order ?
When I usually face that issue, I add a method in the $obj object called render() or done() or something to that effect that checks all the flags I might have defined previously. One of those flags might be a header flag, which is what a redirect method usually does header(Location: $yourDestUrl).
So you end up with something like:
$obj->redirect(url)->setSession(key,value)->render();
When you call a method such as redirect or setSession, put those actions in a "stack" as a property of you class.
Then, when all your methods are called, call a method called exec (for example) that will execute all the actions in the "stack".
Here is a base class based on this idea using magic methods:
class Stack {
private $_stack = array();
public function __call($method, $args) {
// Adding method to stack
$this->_stack[$method] = $args;
return $this;
}
public function __isset($name) {
// Checks if method is in stack
return isset($this->_stack[$name];
}
public function exec() {
// setSession is executed first
if (isset($this->setSession))
call_user_func_array('setSessionMethod', $this->_stack['setSession']);
// redirect is executed second
if (isset($this->redirect))
call_user_func_array('redirectMethod', $this->_stack['redirect']);
}
}
To use this class, you would do:
$stack = new Stack;
$stack->redirect('arg')
->setSession('arg1', 'arg2')
->exec();
I am creating a simple website in cakephp.
I have kept header and footer in "element" but my problem is that menu of header is coming from database and it will not be available until I call a function.
I want as soon as controller is called function of menu should be called by own.
In your AppController add this:
function beforeFilter(){
$this->set('menu', $this->YourModel->findById('Id of your menu data row in database'));
}
Then, in the view, the menu will be accessible by calling echo $menu['yourModel']['menu'];
TLDR:
Instead of calling the function every time the entire controller (or all controllers) is loaded, it's better practice to just call the function when the element itself is loaded. This allows you much more flexibility moving forward. Eg, maybe the log-in screen doesn't need the menu - or maybe you eventually add an admin tool that has a different menu...etc etc.
CakePHP makes this VERY easy using requestAction() - read more here: http://book.cakephp.org/2.0/en/views.html#passing-variables-into-an-element
Side Note: It's also ideal (MVC pattern and many other reasons) to keep ALL queries in a model, instead of calling them directly from a controller.
Example Code:
/**
* MenusController (or any other controller you want)
*/
public function get_menu_main() {
$this->set('menu', $this->Menu->getMenuMain());
}
public function get_menu_footer() {
$this->set('menu', $this->Menu->getMenuFooter());
}
/**
* Menu model
*/
public function getMenuMain() {
return $this->findById('12345');
}
public function getMenuFooter() {
return $this->findById('67891');
}
Then, in your element, just use a requestAction to retrieve the data you need for that specific element:
/**
* MainMenu element
*/
$menu = $this->requestAction('menus/get_menu_main/');
/**
* FooterMenu element
*/
$menu = $this->requestAction('menus/get_menu_footer/');
Side note: to be a little more proper, you can use $this->Html->url() instead of hard-coding the URLs to the actions.
Side note: Some of this code might seem like adding extra code when you don't "need" it, but by breaking things up into their correct MVC spot, your code will be much cleaner, more flexible/upgradable...etc etc etc. Getting into a habit of doing things like this will make your life MUCH easier when things start to get even slightly more complicated. (And in all reality, the code above adds a few lines, but as far as complexity is concerned, I think it's easier to understand than having a query in the AppController that loads variables for an element(s). /endrant
Are functions inside of models directly accessible by users?
Can a user pass arguments directly to a function in a model? Or, do arguments have to be passed through php?
In otherwords:
I have a model called notifications and in there a function called get_notifs($user)... I use the controller to call the function like the get_notifs($_SESSION['user_id']) (which is encrypted). I don't want someone to be able to call get_notifs() with anything but their $_session as a argument. What is the best solution?
Am I already okay?
Should I rename get_notifs() to
_get_notifs()?
Should I check the
$_SESSION['user_id'] in the method
itself?
Or, is there another better solution
than any of these?
I have a controller: ajax.php which loads the model notification
function __construct()
{
parent::__construct();
$this->load->helper('url');
$this->load->library('tank_auth');
$this->load->model('notification');
$this->load->model('search');
}
function get_notifs()
{
$me = $this->session->userdata('user_id');
if ($e = $this->notification->get_notif($me))
{
...........
}
else{
echo "nothing was found wtf?";
}
.........................................................
model: notification.php
function get_notifs($user){
......
}
Your code is perfectly fine!
Am I already okay?
I Think so
Should I rename get_notifs() to _get_notifs()?
No, it's a public method so no need to make it look private.
Should I check the $_SESSION['user_id'] in the method itself?
No, this is the controller's job
Or, is there another better solution than any of these?
You only need a solution to a problem, and i don't see a problem here
it sounds liek your application may be used by people other then yourself, i.e the public developers, why would you want enforce developers to code things your way, that's going to make them upset at your application.
CI Only routes requests to a controller, the user cannot access a model or library or any other class, the route goes like so: /controller/method/param
the first segment will only ever load a controller file, the second will call the method in the param, passing any other variables such as param to that method.
Source: http://codeigniter.com/user_guide/overview/appflow.html
As you can see from the flow chart above, only the controller has access to the model's
If you'll only use it while in a session the best way would be this:
function get_notifs(){
if(!isset($_SESSION['user_id'])){
return false;
}
$user = $_SESSION['user_id'];
/* Your code here */
}
There's no point of requiring an argument when you'll only use the function with one specific variable which is also available globaly.
Edit: I don't know why you're using functions in your models. Doesn't make any sense, do you mean methods?
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.