cakephp global variable for controllers - php

I'm trying to change my database connection depending on who is trying to log in to my page.
What I need is a way to save the correct db name so its accessible by all my controllers.
Using a session would work, but I doubt its safe and/or good practice.
If I could set a variable in the AppController from my AccountsController that would be perfect. but basically any way that enables me to share a variable between all controllers.
In my AccountsController I query a standard database for the correct name. then I use configure::write('CompanyDB', $myDbVar). this work fine for this controller, but I cant use configure::read('CompanyDB') in any other controllers.
In my AppModel i have a construct fucntion that sets the db connection depending on the value inside configure::read('campanyDB') as mentioned before, I need to use configure::write('CompanyDB',$myDbVar) in all my controllers for this to work.
In my Account Model I set the $specific=true. this tells the AppModel that it should use the construct and change the db connection.
class AccountsController extends AppController {
public $helpers = array('Html', 'Form','Js');
public $components = array('RequestHandler');
var $uses = array('User', 'Company');
public $name = 'Accounts';
public $myDbVar='coolbeans';
public function beforeFilter() {
parent::beforeFilter();
Configure::write( 'companyDB',$this->myDbVar);
}
}
class AppModel extends Model {
var $specific = false;
function __construct($id = false, $table = null, $ds = null) {
if ($this->specific) {
// Get saved company/database name
$dbName = Configure::read('companyDB');
// Get common company-specific config (default settings in database.php)
$config = ConnectionManager::getDataSource('companySpecific')->config;
// Set correct database name
$config['database'] = $dbName;
// Add new config to registry
ConnectionManager::drop('companySpecific');
ConnectionManager::create('companySpecific', $config);
// Point model to new config
$this->useDbConfig = 'companySpecific';
}
parent::__construct($id, $table, $ds);
}
}
class Account extends AppModel {
public $primaryKey = '_id';
//var $useDbConfig = 'mongo';
var $specific = true;
.....
}

Probably best bet would be to go with a Configuration file:
Reading and Writing Configuration Files:
http://book.cakephp.org/2.0/en/development/configuration.html#reading-and-writing-configuration-files
The basic idea is, you create a file in your Config/ directory with settings for your app, then, in the bootstrap, you load that config file, which makes any of those variables available anywhere in the app.
Example file: Config/dbconnections.php
<?php
$config = array(
'MyAppDBs' => array(
'company1' => 'connectionName',
'company2' => 'differentConnectionName
)
);
In your bootstrap file:
Configure::load('dbconnections');
Anywhere in your App:
$whatever = Configure::read('MyAppDBs.companyDB');

I think if you do this
configure::write('CompanyDB', $myDbVar);
in your appController then you can access it in any controller using
configure::write('CompanyDB',$myDbVar);
since all controller inherits appController.

Related

$useDbConfig for all uses models at once in Controller for CakePHP v2.x.x

I am currently writing the separate lines for all the models defined in Public $uses = array('Lead', 'User', 'Source', ...) to use the $useDbConfig in Controller.
$this->Lead->useDbConfig = $newDbConfig['name'];
$this->User->useDbConfig = $newDbConfig['name'];
$this->Source->useDbConfig = $newDbConfig['name'];
But i want to set $useDbConfig for all $uses ->useDbConfig at once.
With foreach loop it isn't seems to achieve. Is there any way to achieve it?
Cake v2.5.7
Assuming you always want your Lead, User, etc. models to use the alternative db config the way I'd approach this is to create a new AppModel for these models that changes useDbConfig and extends AppModel:-
class AltAppModel extends AppModel {
public $useDbConfig = 'your-alt-db-config';
}
Then for your models that require the alternative config extend the new AppModel instead
class Lead extends AltAppModel {
}
Obviously use a better naming convention than AltAppModel that's more suited to your project. :-)
Update
Not sure if this would work or not, but based on your comments you could try something like this:-
class AppModel extends Model {
public function changeDbConfig($config) {
$this->useDbConfig = $config;
// Update the belongs to associates
foreach ($this->belongsTo as &$Model) {
$Model->useDbConfig = $config;
}
// Then repeat for hasOne and hasMany...
}
}
Then when you need to dynamically change $useDbConfig call:-
$this->Lead->changeDbConfig('your-alt-db-config');
I'm not 100% sure that this would work though as Cake may not let you update these in this way. Dynamically changing $useDbConfig feels a little quirky to me. If you're changing it based on the app setup it would be better to change this in bootstrap.
Yep, In your Controller you can iterate in the uses array, for example:
public $uses = ['Lead', 'User', 'Source'];
foreach ($this->uses as $model) {
$this->{$model}->setDataSource($newDbConfig['name']);
}

Yii 1.1: cross-controller variables (and even cross-view ones)

For each request I have to load or, at least, create instance of a MyUser, which contains username, some internal permissions info, link to avatar and so on.
The thing is that I need this info for each and every controller and, for most of the views (to render or not to render some controls depending on user status and permissions).
It sounds like the need for a global variable, created at the time request being handled. What is the best way to solve this problem?
Override CWebUser (which is what you call when you issue Yii::app()->user) with your custom class WebUser (placed in the components or other folder that has it's classes autoincluded), and define some getters like it is done with getRole() example below:
<?php
class WebUser extends CWebUser {
private $_model = null;
function getRole() {
if($user = $this->getModel()){
return $user->userRole->name;
}
}
private function getModel(){
if (!$this->isGuest && $this->_model === null){
$this->_model = User::model()->findByPk($this->id);
}
return $this->_model;
}
}
If you user the custom class instead of CWebUser, you have to explicitly tell which class to use in application's config:
'user'=>array(
'class' => 'WebUser',
// …
),
You can create (or inject) an instance of MyUser in the constructor of your base controller, and set it to a public property:
//i am not familiar with Yii naming conventions, so ignore class name etc
class BaseController
{
public $user;
//presuming you can inject, if not $user = new MyUser();
function __construct(MyUser $user){
$this->user = $user;
}
}
Then all controllers that inherit BaseController can access if they need to:
class HomeController extends BaseController
{
function someAction(){
$name = $this->user->name;
}
}
And regardless of whether an action accesses the instance, its available in all views, without passing as a parameter to render:
//someview
echo $this->user->name;

Rendering controller to a different view in CakePHP

Is there a way to render a controller to a different view then normal? I'm trying to pass some data from the controller to a non-default view. Meaning my controller is called:
class StocksRealtimeController extends AppController {
var $uses = 'StockRealtime';
function index(){
$action = '/TestView';
$this->set('stocksRT', $this->StockRealtime->find('all'));
//$this -> viewPath = 'Pages';
$this -> render('/TestView/index');
}
}
... and My view is in views->TestView->index.ctp
Another question I have is, how to pass that value to a PHP and not a ctp file outside of the CakePHP framework?
I have tried everything from here with no luck.
The right way:
$this -> render('TestView/index');
As the answer above mentions, you can use $this -> set to pass a variable to the View.
However, if that doesn't give you what you want. I'm guessing that you also want the action to display another layout (non-default layout). You can try doing $this -> layout = 'layoutname'; (Layouts are in the layout folder, default on is default.ctp).
Note: CakePHP's controller isn't designed to pass data to a non-view file (like .php). CakePHP's views should be ending with .ctp.
I would rather use:
$this->view = 'file';
because any $this->set('var', $val) you'll have after $this->render('file') will not reach your view.
In CakePHP 3.x use:
$this->viewBuilder()->template('file');
Deprecated in CakePHP 3.7.
Use this instead (as Kuldeep Choudhary suggested in comments)
ViewBuilder::setTemplate('file');
Try to put the name of the view without .ctp extension.
$this->render('file');
class StocksRealtimeController extends AppController
{
var $uses = 'StockRealtime';
function index( )
{
$this->layout = NULL;
$this->autoRender = false;
$this->set('stocksRT', $this->StockRealtime->find('all'));
return $this -> render('/TestView/index');
/*
$this -> render('/TestView/index');
Here 'TestView' must be a Folder named same as "public $name" variable value
in Controller and an "index.ctp" must be situated under TestView Folder.
'index'
*/
}
}
Give it a try, return 'KEYWORD' must be there to render view page successfully.
Sorry about 2nd question as i didn't get it.
According to CakePHP, variable [stocksTR] which is set using
$this -> set( ) , also will be available at manually render view page [ 'index.ctp' ].
$this->view = '/TestView/index';
$this->set('stocksRT', $this->StockRealtime->find('all'));
public function admin_index() {
$this->layout = 'admin/table';
$action = '/Vendors';
$this->Prg->commonProcess('Vendor');
$this->paginate = array('conditions' => array($this->Vendor->parseCriteria($this->passedArgs)), 'order' => 'Vendor.created_on DESC', 'limit' => 15);
$this->set('vendor', $this->paginate('Vendor'));
$this->render('/vendors/admin_items');
}
class StocksRealtimeController extends AppController {
var $uses = 'StockRealtime';
function index(){
$this->layout = NULL;
$this->autoRender = false;
$this->set('stocksRT', $this->StockRealtime->find('all'));
$this -> render(`/TestView/index`);
}
}

Posting to a controller with ajax in CakePHP 2.0

When I post to this controller, I get this back as the response: Fatal error: Call to a member function find() on a non-object in /app/Controller/AppController.php on line 26 which probably has to do with using $this->data() explicitly. I was using CakePHP save without form
per a recommendation in there, but since I'm not using a form to send the data (thus not using $this->request->data()), I'd like to know what the replacement is for $this->data() so I can get this working.
My database table is is submissions_favorites.
This is my SubmissionFavorite model:
class SubmissionFavorite extends AppModel {
var $name = 'SubmissionFavorite';
var $belongsTo = array(
'User' => array(
'className' => 'User'
)
);
}
This is AjaxController (what I'm posting to):
class AjaxController extends AppController {
var $layout = 'ajax'; // uses an empty layout
var $autoRender = false; // renders nothing by default
var $uses = 'SubmissionFavorite';
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->loginRedirect = array('controller' => 'home', 'action' => 'index');
$this->Auth->allow('addFavorite');
$this->Auth->flashElement = 'flash_error';
}
public function addFavorite() {
$this->autoRender = false;
$this->data['SubmissionFavorite']['user_id'] = $this->Session->read('Auth.User.id');
$this->data['SubmissionFavorite']['submission_id'] = $_POST['id'];
$this->data['SubmissionFavorite']['when'] = DboSource::expression('NOW()');
$message = array('success' => 'success');
$toReturn = json_encode($message);
if ($this->RequestHandler->isAjax()) {
if ($this->Session->read('Auth.User')) {
$this->SubmissionFavorite->save($this->data);
return $toReturn;
} else {
$login = array('login' => 'Please log in to add favorites');
return json_encode($login);
}
}
}
Line 26 in my AppController is:
protected function getSubmissionCount() {
$totalSubmissions = $this->Submission->find('count');
return $totalSubmissions;
}
Which is totally unrelated to anything else. I didn't even add anything to AppController when I wrote the new method within my AjaxController, so I'm not sure how it's relevant (or why I'm even getting an error in that file).
First, following cake conventions, you should name your model SubmissionsFavorite (note the s between Submission and Favorite). This is because your table name is composed by 2 words, even representing a relationship between 2 other tables.
Also, you can't do $this->Submission->... on AppController without telling cake whatever is "Submission". Take a look at this link to see how to initialize Submission model and use it on AppController: Can I use one model inside of a different model in CakePHP?
Regards.
Try to change all
var $name = 'SubmissionFavorite';
to:
public $name = 'SubmissionFavorite';
Also change: var $uses = 'SubmissionFavorite';
to: public $uses = array ('SubmissionFavorite');

Zend Framework how to do this in order to not repeat myself

I have this thing that I need in multiple places:
public function init()
{
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) $this->_redirect('/'); #Logout the user
}
These two lines:
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) $this->_redirect('/'); #Logout the user
Whats the best way to do it in ZendFramework?To create a plugin or? I mean I want to execute it in multiple places but If I need to edit it I want to edit it in one place.
Here is an example of an Action Helper that you can call from your controllers easily.
<?php
class My_Helper_CheckFbLogin extends Zend_Controller_Action_Helper_Abstract
{
public function direct(array $params = array())
{
// you could pass in $params as an array and use any of its values if needed
$request = $this->getRequest();
$view = $this->getActionController()->view;
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) {
$this->getActionController()
->getHelper('redirector')
->gotoUrl('/'); #Logout the user
}
return true;
}
}
In order to use it, you have to tell the helper broker where it will live. Here is an example code you can put in the bootstrap to do so:
// Make sure the path to My_ is in your path, i.e. in the library folder
Zend_Loader_Autoloader::getInstance()->registerNamespace('My_');
Zend_Controller_Action_HelperBroker::addPrefix('My_Helper');
Then to use it in your controller:
public function preDispatch()
{
$this->_helper->CheckFbLogin(); // redirects if not logged in
}
It doesn't go into much detail, but Writing Your Own Helpers is helpful as well.
If you need this check in every Controller you could even set up a baseController from which you extend instead of the default one:
class My_Base_Controller extends Zend_Controller_Action
{
public function init()
{ ...
class IndexController extends My_Base_Controller
{ ...
Shift your init() into the base controller and you don't need to repeat yourself in every specific controller.
Need a varying init() in a specific controller?
class FooController extends My_Base_Controller
{
public function init()
{
parent::init();
...

Categories