According to the Codeignitor docs here: http://ellislab.com/codeigniter/user-guide/general/hooks.html it states:
pre_controller
Called immediately prior to any of your controllers being called. All base classes, routing, and security checks have been done.
However, if I create a hook pre_controller hook with:
$hook['pre_controller'][] = array(
'class' => 'tester',
'function' => 'test',
'filename' => 'tester.php',
'filepath' => 'models',
//'params' => array('beer', 'wine', 'snacks')
);
and the file tester.php is:
class tester extends CI_Model
{
public function __construct()
{
parent::__construct();
$this->load->library('migration');
}
public function test()
{
echo "hi";
exit;
}
}
I get this error:
Fatal error: Class 'CI_Model' not found in ******.php
Why is it not loading CI_Model? If I put a require_once('system/core/Model.php'); in the hooks.php file above the pre_controller definition, I get this error:
Fatal error: Call to a member function library() on a non-object in ****.php
Since it's not actually loading the CI_Model, functions such as library() would not work. How can I force it to bootstrap the CI_Model.
The first person that says "Use post_controller_constructor" will be shot on sight as that does not answer the question. I need it to load BEFORE it runs any constructor functions from the controller classes. I need access to extend the CI_Model class from the pre_controller hook.
The short answer is that CodeIgniter doesn't work the way you want it to. At the stage that you're trying to access a model, CodeIgniter hasn't loaded the required classes and it isn't available. Depending on exactly what you're trying to achieve, there may be another way to achieve this - without using a hook/using a later hook?
Viewing /system/core/CodeIgniter.php will show when each hook is called and when other tasks are performed; loading routing, loading global functions etc.
If you insist on using this hook, then you could add this: load_class('Model', 'core'); at the top of your model file (before you declare the class), but this would be a very dirty fix.
Make sure your class names follow the correct naming convention - tester should be Tester.
Edit: as you want to run the same code on every call (assuming every controller call), this is a possible solution:
Extend the core controller, and use this new controller as a base controller for all other controllers (as they will be sharing the same functionality). In the constructor of this new base controller, add the functionality that you want to run on every call. The code in this constructor will be called before any other code in any of your controllers.
Create the following file, application/core/MY_Controller.php.
class MY_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
// Do whatever you want - load a model, call a function...
}
}
Extend every controller in application/controllers, with MY_Controller, rather than CI_Controller.
class Welcome extends MY_Controller {
function __construct()
{
parent::__construct();
}
// Your controllers other functions...
}
/*application/config/hooks.php*/
$hook['pre_controller'][] =
array(
'class' => 'MyClass',
'function' => 'Myfunction',
'filename' => 'Myclass.php',
'filepath' => 'hooks',
'params' => array('beer', 'wine', 'snacks')
);
/*application/config/config.php*/
$config['enable_hooks'] = TRUE;
/hooks/Myclass.php/
Related
In my Laravel application, i have several policies working, but one will not work.
Controller
public function store(Project $project, CreateActionRequest $request)
{
$this->authorize('store', $project);
Action::create([
'name' => $request->name,
]);
return redirect()->route('projects.show', $project->id)->withSuccess('Massnahme erfolgreich gespeichert');
}
Policy
namespace App\Policies\Project;
use App\Models\Project\Project;
use App\Models\User;
use App\Models\Project\Action;
use Illuminate\Auth\Access\HandlesAuthorization;
class ActionPolicy
{
use HandlesAuthorization;
public function store(User $user, Project $project)
{
return $user->company_id === $project->company_id;
}
}
AuthServiceProvider
protected $policies = [
'App\Models\User' => 'App\Policies\CompanyAdmin\UserPolicy',
'App\Models\Company' => 'App\Policies\CompanyAdmin\CompanyPolicy',
'App\Models\Team' => 'App\Policies\CompanyAdmin\TeamPolicy',
'App\Models\Department' => 'App\Policies\CompanyAdmin\DepartmentPolicy',
'App\Models\Location' => 'App\Policies\CompanyAdmin\LocationPolicy',
'App\Models\Division' => 'App\Policies\CompanyAdmin\DivisionPolicy',
'App\Models\Costcenter' => 'App\Policies\CompanyAdmin\CostcenterPolicy',
'App\Models\Workplace' => 'App\Policies\CompanyAdmin\WorkplacePolicy',
'App\Models\Product' => 'App\Policies\CompanyAdmin\ProductPolicy',
'App\Models\Project\Action' => 'App\Policies\Project\ActionPolicy',
'App\Models\Project\Project' => 'App\Policies\Project\ProjectPolicy',
];
CreateActionRequest
namespace App\Http\Requests\Project;
use Illuminate\Foundation\Http\FormRequest;
class CreateActionRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|min:3',
];
}
}
All policies are working except ActionPolicy and ProjectPolicy.
I added in the policy a __construct() method to check if the policy is called. But ActionPolicy and ProjectPolicy are not working.
How can i search the error? I tried with dd() but i got only allways the message: This action is unauthorized
Since you are injecting CreateActionRequest instead of Request that means you are defining your own set of rules to authorize the FormRequest which comes inside of your method. Further it means that you gotta define a few rules which the "FormRequest" has to pass in order to EVEN reach your controller, this is a nice concept that I like about Laravel since the code is not centralized, but rather spread and every layer has it's own responsibility. Now, you don't have to call any method from your CreateActionRequest nor you have to write any code regarding that class in your controller, because Laravel runs authorize method by default before allowing the Request to reach your controller, before running authorizemethod in your CreateActionRequest it runs rules method which verifies that all the given fields pass the expressions you assigned them, so the execution is something like this CreateActionRequest => rules => authorize => IF(authorized) Controller ELSE Not authorized, hope that makes sense. In order to fix your code:
1.) Remove $this->authorize('store', $project);
This will allow you to pass not authorized error in case your name passes the truth test inside of rules method inside of your CreateActionRequest. If you wish to utilize your Action Policy you will need to hook up your custom Request(CreateActionRequest) with it and this is how:
public function authorize()
{
$store = $this->route('project');
//The above line will return Project object if your mapping is correct
//If it's not it will return the value you passed to your route for {project}
return $this->user() && $this->user()->can('store', $store);
}
EDIT:
Here is the link where you can see how to properly authorize and connect policy with CreateActionRequest
Do you have all your controller methods defined with the Request object last?
public function store(Project $project, CreateActionRequest $request)
The Request object should be the first parameter in the methods signature:
public function store(CreateActionRequest $request, Project $project)
Dependency Injection & Route Parameters
If your controller method is also expecting input from a route parameter you should list your route parameters after your other dependencies.
Most Laravel authorization mechanisms have identical method signatures allowing them to work across varying classes.
I am trying to extend the CI_Controller class to load my global page header file so I don't have to load it at the beginning of every single controller method. It doesn't seem to be working. I know the Controller extension itself works... if I remove the call of the model method from the constructor and load it from my controller method, the rest of the controller extension works fine. But when I load the model method from within the constructor of the controller extension, I get a blank page(I haven't generated the main content yet).
Any ideas?
application/core/MY_Controller.php
<?php
class MY_Controller extends CI_Controller {
var $user = array();
function __construct(){
parent::__construct();
$this->load->model('member');
if($this->session->userdata('member_id')){
$this->member->get_info($this->session->userdata('member_id'));
$this->user = $this->member->info;
$this->member->update_activity($this->session->userdata('member_id'));
} else {
$this->load->helper('cookie');
if(get_cookie('Teacher Tools Member Cookie')){
$this->member->auto_login(get_cookie('Teacher Tools Member Cookie'));
} else {
$this->user = $this->member->default_info();
}
}
$this->load->model('template');
$this->template->overall_header();
}
}
application/models/template.php
<?php
class Template extends MY_Model {
function __construct(){
parent::__construct();
}
function overall_header($title = 'Home'){
$data = array(
'BASE_URL' => base_url(),
'MAIN_NAVIGATION' => $this->main_navigation(),
'TOOLBAR' => $this->toolbar()
);
return $this->parser->parse('overall_header.tpl', $data);
}
MY_Model is an extension of the CI_Model class to load member information into $this->user.
I think response generation is done in Controller's method and all HTML pieces that you might have gets glued there. So if you are calling /controller/method_a then method_a will be responsible for returning response whereas in constructor you cannot set response.
I agree with you on setting important data in Constructor once so that you don't have to do this again and again in each method. I think you should assign output to some Controller level variable and then use that variable in your Controller's method.
I' am sure you got my point.
For this reason there is a config/autoload.php:
$autoload['model'] = array('YourModel');
Normally, extending CI_Controller lets you use the function _output for rendering html outputs.
I'm using HMVC. MX_Controller doesn't load _output function.
I've tested it and run a couple of times.
Questions:
1 - Does MX_Controller inherits CI_Controller?
2 - How can I implement _output?
It seems like codeigniter-modular-extensions-hmvc does indeed break the _output() functionality. I can't figure out how to submit the bug on bitbucket: https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc
My workaround involved overriding the Output class & adding a hook to fire a custom output method. Here's what I did.
Overwrite the main Output class:
class MY_Output extends CI_Output
{
function __construct()
{
parent::__construct();
}
// Overwrite the output
public function my_output()
{
$content = $this->get_output();
// do stuff to $content here
$this->set_output($content);
$this->_display();
}
}
Then enable hooks in your config.
$config['enable_hooks'] = TRUE;
Then add this to your hooks config.
$hook['display_override'][] = array(
'class' => '',
'function' => 'custom_output',
'filename' => 'custom_output.php',
'filepath' => 'hooks'
);
Finally add the "custom_output.php" file to your hooks directory and add this.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
* Customize the output
*/
function custom_output()
{
$CI =& get_instance();
$CI->output->my_output();
}
If you don't need to access any class variables, you can just edit the output right in the custom_output() function and not worry about overriding the Output class.
Very hacky, but it works. :)
I just want to know on how to pass parameters in module
constructor?
Here is the code that is wrote but its not functioning well.
//Here is the main controller
class Main extends MX_Controller
{
public function _construct()
{
parent::_construct();
}
public function index()
{
// sample parameter
$aparam = array(
'param1' => 'param value1',
'param2' => 'param value2'
);
$this->load->module('dashboard',$aparam);
}
}
// Here is "dashboard" module controller
class Dashboard extends MX_Controller
{
public function __construct($aparam)
{
//output param value
// want to get this value
echo $aparam['param1'];
echo $aparam['param2'];
}
}
Please help. thanks.
Ok, so just to clarify, I don't know what "HMVC" stands for but I did notice that if you are trying to use the codeigniter framework then when you create a controller class you must extend the "CI_Controller" class not the "MX_Controller".
Here is a reference page in the codeigniter manual:
http://codeigniter.com/user_guide/general/controllers.html
If you are trying to create a stand alone class that interacts with your code somehow, Codeigniter allows for this via "libraries". A library is just a class.
Here is the reference page in the codeigniter manual:
http://codeigniter.com/user_guide/general/creating_libraries.html
The problem:
I've defined a few constants in my hook but I can't access them inside my sub-classed controller constructor.
The code:
A - the hook class:
class Settings extends CI_Hooks {
public function load_settings() {
$CI =& get_instance();
$CI->load->model('hooks/settings_model');
$data = $CI->settings_model->load_settings();
define('MEMBERS_PER_PAGE', $data['members_per_page']);
define('REGISTER_ENABLED', $data['register']);
define('SITE_ACCESS_ENABLED', $data['site_access']);
define('ADMIN_EMAIL', $data['admin_email']);
}
}
B - the hook config:
$hook['post_controller_constructor'] = array(
'class' => 'settings',
'function' => 'load_settings',
'filename' => 'settings.php',
'filepath' => 'hooks'
);
C - the controller
class MY_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
defined('SITE_ACCESS_ENABLED') ? print SITE_ACCESS_ENABLED : print "NULL";
}
}
The way I understand *post_controller_constructor* is that it loads after the controller is initialized but before the constructor is executed. Apparently my defined constants don't work in any constructor while constants from config/constants.php do work.
Any help and insights are greatly appreciated as hooks are totally new to me.
Well, post_controller_constructor happens just then. After the constructor has finished constructing the controller :-).
You need to have it fire at pre_controller and manage the instantiation of the model on your own, or you will have to wait until the controller's method is called before you can access the values. Sorry.