I have extended my CI_Controller like this:
// base extend
class MY_Controller extends CI_Controller {
public $CI = array();
public function __construct() {
parent::__construct();
$this->CI = & get_instance();
}
public function isUser(){
// for example
}
}
// admin extended
class MY_AdminController extends MY_Controller {
public $admin = array();
public function __construct() {
parent::__construct();
$this->CI->lang->load('admin');
$this->admin['lang'] = $this->CI->lang->line('admin');
$this->CI->load->vars($this->admin);
}
public function isAdmin(){
//for example
}
}
// extends for modules
class MY_AdminModuleController extends MY_AdminController {
public function __construct() {
parent::__construct();
$this->CI->load->view('_header');
}
public function isAllowedModule(){
// example
}
public function pseudoDestruct(){
$this->CI->load->view('_footer');
}
}
So it works fine. But I try to hook post_controllerevent and add my MY_AdminModuleController->pseudoDestruct(), so I enabled hooks in config.php and added next lines to hooks:
$hook['post_controller'] = array(
'class' => 'MY_AdminModuleController',
'function' => 'pseudoDestruct',
'filename' => 'MY_Controller.php',
'filepath' => 'core'
);
But I got a problem at loading lang-file in MY_AdminController's constructor. It returns null when called from hook (true when I use it normaly) and I have Notice about undefined index at frontend. No, I don't want to disable notices, I want to fix the problem. Also I have config loadings in MY_AdminController's constructor and them loading good.
You can't do that, not in that particular way at least. CodeIgniter is designed to only have one controller instance, while the hooks create new instances and your lang files are not loaded in that new instance.
Also, you don't need to call get_instance() from your controller class - the class IS what get_instance() returns.
Anyway, you can declare a regular function to use as a hook, there's no problem putting it in your MY_Controller.php file as well:
function pseudo_destruct()
{
get_instance()->load->view('_footer');
}
Then use this hook:
$hook['post_controller'] = array(
'function' => 'pseudo_destruct',
'filename' => 'MY_Controller.php',
'filepath' => 'core'
);
Related
How to make a global variable that always changing?
I want to create something like protected $global_data; in controller Global_data.php that can be called by a lot of controller, and return variable $global_data value to whenever controller that has $this->load->library('../controllers/Global_data').
But when I tried to call it, it gives me this error Unable to locate the specified class: Session.php, so I think CodeIgniter 3.1.8 not allowed me to do this.
So how to achieve what I'm looking for? do I need to put it on model instead, library file or is there another way to do it?
Thank you.
Here is Global_data.php content
protected $global_data;
public function __construct()
{
parent::__construct();
$this->global_data = array(
'can_be_anything' => 'can_be_anything',
'can_be_anything' => 'can_be_anything',
'can_be_anything' => 'can_be_anything',
'can_be_anything' => 'can_be_anything',
);
}
Can_be_anything_controller.php content
class Can_be_anything_controller extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->library('../controllers/Global_data');
}
public function index()
{
$data = $this->global_data;
$data['page_title'] = 'Dashboard';
$data['page_directory'] = 'pages/dashboard';
$this->load->view('template', $data);
}
}
You may create a library for that in libraries directory
Global_data.php file
class Global_data{
public $global_data;
protected $CI;
public function __construct() {
$this->CI = & get_instance();
}
public function common_data()
{
$this->global_data= array(
'can_be_anything' => 'can_be_anything',
'can_be_anything' => 'can_be_anything',
'can_be_anything' => 'can_be_anything',
'can_be_anything' => 'can_be_anything',
);
return $this->global_data;
}
public function any_method(){
$query = $this->CI->db->get('table_name');
}
}
Now you can load it in any controller like
$this->load->library('Global_data')
Then use data
$data = $this->Global_data->common_data();
Also you may use HMVC model to use any method in any controller
https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc
Make a MY_Controller in application/core/MY_Controller.php
class MY_Controller extends CI_Controller {
public $global_data;
public function __construct() {
parent::__construct();
$this->global_data = 'whateveryouwant';
}
public function somemethod() {
return '123';
}
}
then any other controllers in your application/controllers that need to access global_data should extend it like so:
class Somecontroller extends MY_Controller {
public function index() {
echo $this->global_data;
echo $this->somemethod(); // works with methods too
}
}
If you need to run more complex code just put everything into a library or model and autoload it. All public methods and properties are globally available. HMVC seems overkill for what you want.
This kind of data can also be handled very nicely by config files.
/application/config/global_data.php
<php
$config['foo'] = "some foo";
$config['bar'] = 42;
$config['baz'] = array('one', 'two', 'three');
In a controller load the config file with
$this->config->load('global_data');
The access the items using
echo $this->config->item('foo');
echo $this->config->item('bar') * 2; //outputs 84
$data = $this->config->item('baz');
Config documentation
I have two layout templates in my project and always loading first template. How to load second template also.
In main Usercontroller how to differentiate them. They are,
Learncontroller.php
class Learncontroller extends Usercontroller{
public function __construct(){
parent::__construct();
$this->load->model("Usermodel","",true);
}
public function index(){
$id=$this->session->userdata('cp_userid');
$menuActive= "learning";
$data['menuActive'] = $menuActive;
$userdetails=$this->Usermodel->getuserdetails($id);
$data['userdetails']=$userdetails;
$result=$this->Usermodel->currentlearningcourses($id);
$data['details']=$result;
$data['content']=$this->load->view("user/currentlearningcourses",$data,true);
$data['title']='My Courses';
//$this->load->view("user/layout",$data);
$headerContent = $this->load->view("user/layout",$data,true);
$this->render($headerContent);
}
}
Unitcontroller.php
class Unitcontroller extends Usercontroller{
public function __construct(){
parent::__construct();
$this->load->model("Usermodel","",true);
}
public function courselearn($id){
$r=$this->Usermodel->getsectiontopic($id);
$data['topicId']=$id;
$data['topicQ']=$r;
$data['video']=$this->input->post("id");
$data['id']=$id;
$data['content']=$this->load->view("user/unit_content",$data, true);
$courselearnheaderContent = $this->load->view("user/courselearn_layout",$data,true);
$this->render($courselearnheaderContent);
}
}
Learncontroller and Unitcontroller has separate layouts but always loading protected $layout = 'user/layout';. How to load this 'user/courselearn_layout'; when control comes from Unitcontroller.
Usercontroller.php
protected $layout = 'user/layout';
protected $courselearn_layout = 'user/courselearn_layout';
protected function render($headerContent) {
$view_data = array( 'headerContent' => $headerContent);
$this->load->view($this->layout);
}
Always loading first page. How to make load the second page also please help me.
I am attempting to access the parent class __construct properties within a child class that extends this, however not sure how to do this as I have tried multiple methods and didn't give me the expected result.
So I have a baseController and a indexController which extends it, I want to be able to have direct access to the properties of the parent within the child controller.
$config = ['site' => 'test.com'];
class baseController {
public function __construct($config){
$this->config = $config;
}
}
class indexController extends baseController {
public function __construct(){
parent::__construct(); // doesnt seem to give any outcome
}
public static function index() {
var_dump($this->config); // need to access within this method
}
}
$app->route('/',array('indexController','index')); // the route / would call this controller and method to return a response
There are several issues with code you have there. You are setting up config as a global, it should be inside your BaseController and set it to public or protected:
class BaseController {
protected $config = ...
Just like #mhvvzmak1 mentioned, your child constructor is calling the parent properly. for example you can do it like so:
class IndexController extends BaseController {
public function __construct(){
$config = [];
parent::__construct($config);
}
and finally just like dan08 mentioned, you can't reference $this from a static method, change your index function:
public function index() {
Update
If you really want the child function to remain static as required by your framework, you make config a static function on the BaseController and call it in the child.
class BaseController {
protected static function config() {
return ['site' => 'mySite'];
}
}
class Child extends BaseController {
public static function index() {
$config = BaseController::config();
}
}
I started topic on codereview and got nice answer. This answer is here.
All tips are looking nice and now I am trying to follow them in my code.
Author of this answer said, that I am getting object manager in all actions (somewhere 2 times). He suggested to do it in init() method of my controller and assign object manager to $this->objectManager. I tried this:
In that case, that there are no init() method in zf2, I used init:
public function __construct() {
$this->objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
On other actions I am using this:
public function listAction() {
$news = $this->objectManager
->getRepository('\News\Entity\Item')
->findBy(array(), array('created' => 'DESC'));
// some more code
}
When I am trying load the page I am getting this:
Fatal error: Call to a member function get() on a non-object in F:\Server\domains\zf2-skeleton\module\News\src\News\Controller\NewsController.php on line 12
Line 12 is a line in __construct:
$this->objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
In old version I was using similar:
public function indexAction() {
$objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
// how I use $objectManager?
$news = $objectManager
->getRepository('\News\Entity\Item')
->findBy($options, array('created'=>'DESC'));
// some more code
}
Why approach with __construct is not working? What I am doing wrong?
Files on the github:
Old and monstrous controller code, but working one
New and pretty controller code, but not working :(
Update
File MODULE/src/MODULE/Factory/NewsControllerFactory.php contents:
<?
namespace News\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use News\Controller\NewsController;
class NewsControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
var_dump("bob");
$objectManager = $serviceLocator->getServiceLocator()->get('Doctrine\ORM\EntityManager');
return new NewsController($objectManager);
}
}
I tried to var_dump(); something there and realized, that createService function is not called during execution. Why?
This is because the service locator has not been set yet. When you're referencing it in your constructor, the $this->getServiceLocator() is still returning null.
If you want to setup objectManager for use in your controller, I'd recommend using a factory. It makes it easier to test your objects;
class NewsControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$objectManager = $serviceLocator->getServiceLocator()->get('Doctrine\ORM\EntityManager');
return new NewsController($objectManager);
}
}
and then your controller would look like this
class NewsController extends AbstractActionController
{
protected $objectManager;
public function __construct($objectManager)
{
$this->objectManager = $objectManager;
}
}
and the necessary addition to your module.config.php
'controllers' => array(
'factories' => array(
'News\Controller\News' => 'News\Factory\NewsControllerFactory',
)
)
This should work -
use Zend\Mvc\Controller\AbstractActionController;
use Zend\EventManager\EventManagerInterface;
class IndexController extends AbstractActionController {
protected $objectManager;
public function setEventManager(EventManagerInterface $events) {
parent::setEventManager($events);
$this->objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
[......]
}`
Then just use $this->objectManager in any actions or simple functions in that whole controller -
public function listAction() {
$news = $this->objectManager
->getRepository('\News\Entity\Item')
->findBy(array(), array('created' => 'DESC'));
// some more code
}
I am creating one login authentication app in CakePHP
and getting this Fatal error: Call to a member function allow() on a non-object in /var/www/cakephp1/app/Controller/users_controller.php on line 5
and this is my controller code
users_controller.php
<?php
class UsersController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add');
}
public function add() {
if (!empty($this->data)) {
$this->User->create();
if ($this->User->save($this->data)) {
$this->Session->setFlash('User created!');
$this->redirect(array('action'=>'login'));
} else {
$this->Session->setFlash('Please correct the errors');
}
}
$this->set('groups', $this->User->Group->find('list'));
}
public function login() {
}
public function logout() {
$this->redirect($this->Auth->logout());
}
public function dashboard() {
$groupName = $this->User->Group->field('name',
array('Group.id'=>$this->Auth->user('group_id'))
);
$this->redirect(array('action'=>strtolower($groupName)));
}
public function user() {
}
public function administrator() {
}
public function manager() {
}
}
?>
app_controller.php
<?php
class AppController extends Controller {
public $components = array(
'Acl',
'Auth' => array(
'authorize' => 'actions',
'loginRedirect' => array(
'admin' => false,
'controller' => 'users',
'action' => 'dashboard'
)
),
'Session'
);
}
?>
View login.ctp
<?php
echo $this->Form->create(array('action'=>'login'));
echo $this->Form->inputs(array(
'legend' => 'Login',
'username',
'password',
'remember' => array('type' => 'checkbox', 'label' => 'Remember me')
));
echo $this->Form->end('Login');
?>
I am using CakePHP version 1.3
1.Solution: All what you need to do is to add this line in your UsersController:
public $components = array('Auth');
Or
2.Soluton: In UsersController:
App::uses('AppController', 'Controller');
class UsersController extends AppController {
}
and then in AppController:
public $components = array('Auth');
There are two common causes for this type of error:
The App controller file is not being loaded
If the AppController class doesn't exist - Cake will use a fallback for it taken from the core - it's just an empty class. For the error in the question to occur - the Auth component hasn't been loaded, the most likely reason for that is that the file app/app_controller.php either doesn't exist or a different AppController class file was loaded before looking for it.
This can be confirmed using get_included_files, e.g.:
class UsersController extends AppController {
public function beforeFilter() {
if (!isset($$this->Auth)) {
debug(get_included_files());
die;
}
Look for which app_controller.php file has been loaded - if it's not the file containing the class in the question, that's the problem.
Overridden constructor, not calling parent
Good children always call their parents :)
If the constructor (or any method) is overridden and does not call the parent function, then e.g. the components property won't get merged/set correctly or component classes won't be initialised.
If the right app_controller.php file is being loaded focus on the methods defined within the controller classes and check they are calling parent::methodname (for the users controller, and the app controller). Specifically verify that the Controller::__construct is being called since that's where most of the class initialization logic is in 1.3.
The error sounds like the loading of the Auth-component failed. Have you tried removing the settings from the $components array and see if the error persists?