I'm trying to access the email address for a user that's signed in and I can do so successfully in all of my Controllers except for one.
Here is the error I'm getting
Notice (8): Undefined index: User [APP/View/Layouts/default.ctp, line 37]
And here is the corresponding line of code (remember, this works in all of my other controllers).
<center><font color="black"><td><?php echo $user['User']['email']; ?></td></text></center>
Here is the DemosController
<?php
// app/Controller/DemosController.php
class DemosController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add','logout');
$user = $this->Demo->read(null, $this->Auth->user('id')); //this throws the error
//$user = $this->Demo->User->read(null, $this->Auth->user('id')); //Fatal error: Call to a member function read() on a non-object in
$this->set('user', $user);
}
//display the knockout table
public function index($article = null) {
}
}
I do not need a table in the database for this Controller. It's simply to display a table for demo purposes. Can I just let it reference user?
class Demo extends AppModel {
public $name = 'User';
}
Why can I access this in all of my controllers except this one? Is the Model/table situation causing the error? If so, is there a way to disable the use of a table?
You have a couple problems going here:
First, when not using a table, you set a model's $useTable property to false.
Secondly, without a table, no database call will work (just plug in sample data to the table anyway, who would know if its a demo?)
It still bears mentioning that $this->Model->read() is for updating records. Changing the line to the following will allow the set call to function properly:
$this->Demo->find('first', array(
'conditions' => array(
'Demo.field' => $this->Auth->user('id')
)));
Getting properties of the logged-in user via AuthComponent
You don't have to pass information of the currently logged-in user to the view via a 'viewVar'.
To access properties of the currently logged-in user outside of the controller, use the 'static' interface of the AuthComponent
Inside your views or layouts, output the information like this;
<p>The current users email is: <?php echo AuthComponent::user('email') ?></p>
<p>The current users id is: <?php echo AuthComponent::user('id') ?></p>
<p>And all properties of the user are:</p>
<pre><?php print_r(AuthComponent::user());?></pre>
See: Accessing the logged in user
You can remove these lines from your beforeFilter();
$user = $this->Demo->read(null, $this->Auth->user('id')); //this throws the error
//$user = $this->Demo->User->read(null, $this->Auth->user('id')); //Fatal error: Call to a member function read() on a non-object in
$this->set('user', $user);
Related
I'm using a custom PHP framework which is largely based on CodeIgniter.
In one of my controller files, I've set a class property called $orderId. After the user has filled in the form and submitted, I'll do a DB insert, get the order no. and override the $orderId class property value with that order no.
Then I'll redirect to the submit page where I want to access that updated $orderId class property value. This final part is not working, the submit class gets a blank value for property $orderId.
Where am I going wrong pls? The basic example below. Maybe I can't do this because of the redirect and should use a session var instead?
Thanks!
[EDIT] Or I could pass the orderId as the 3rd URL param in the redirect. E.G. redirect('orders/submit/'.self::$orderId); in which case I'll turn all the self:: instances into $this-> for class level scope.
class Orders extends Controller {
private static $orderId;
public function __construct() {
// assign db model
}
public function index() {
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$data = [
// form data to pass to db model
];
self::$orderId = 12345; // example order no. return from db model
if(!empty(self::$orderId)) {
redirect('orders/submit');
}
}
}
public function submit() {
$data = [
'orderId' => self::$orderId
];
$this->view('orders/submit', $data);
}
}
The issue itself is a fundamental architecture problem. static only works when you're working with the same instance. But since you're redirecting, the framework is getting reinitialised. Losing the value of your static property. Best way to go about doing this is by storing the order id in a session variable and then read that variable. Sessions last for the as long as the browser window is open
I have applied the fix to Codeigniter in DB_driver.php to allow me to connect to 2 databases at once by adding $this->db_select(); to function simple_query($sql).
I then have a MY_Controller.php that loads both my databases and each controller that I have extends it:
class MY_Controller extends CI_Controller {
public function __construct() {
$this->db1 = $this->load->database('db1',TRUE);
$this->db2 = $this->load->database('db2',TRUE);
}
}
My application is a backend administration panel into for an existing database. I would rather not manipulate the existing database with additional tables, but rather any tables my administration panel needs will be stored in another database (db1 is my panel, db2 is the existing database). My $active_group in /config/database.php is set to db1.
Form validation in this format:
$userRules = "trim|required|min_length[4]|max_length[25]|xss_clean|is_unique[users.username]";
$this->form_validation->set_rules('username', 'Username', $userRules);
Works just fine because in that case I wish to query the db1 and the users table (my admin panel database).
However, if I want to do the same on db2 with something like this:
$useridRules = "trim|required|min_length[4]|max_length[25]|xss_clean|is_unique[login.userid]";
$this->form_validation->set_rules('userid', 'Username', $useridRules);
Does NOT work because it's still trying to query db1. An error is returned:
Error Number: 1146
Table 'db1.login' doesn't exist
SELECT * FROM (`login`) WHERE `user_id` = 'asdfjkl' LIMIT 1
Filename: libraries/Form_validation.php
Line Number: 954
db1.login definitely doesn't exist, as I need to query db2 for the login table, so the error is expected but not wanted.
I'm curious to see if anyone has found a way to use the is_unique validation rule to query their second database or the first depending on the instance at hand, or if I'll need to write a function using callback instead (or if you think it would be better to simply put my tables into the existing db2 and prefix them with ci_table?
I think you can use a callback function to call a specific function that does the checking:
So change this:
$userRules = "trim|required|min_length[4]|max_length[25]|xss_clean|is_unique[users.username]";
to this:
$userRules = "trim|required|min_length[4]|max_length[25]|xss_clean|callback_is_unique";
you will need to have a function to process it:
function is_unique($username){ // $username recieves the parameter automatically
//Go on with your query as bellow
$this->db2->
}
just to make this a bit more generic: extend the form validation class, make a new function and use that in the rules. say your second db is set at $this->db2
your rule would be is_db2_unique[table.field]
In your language file somewhere add the line:
$lang['form_validation_is_db2_unique'] = 'The {field} field must contain a unique value.';
libraries:MY_Form_validation.php
<?php if ( defined('BASEPATH') === FALSE ) exit('No direct script access allowed');
// this is used as to extend the base form validation class,
class MY_Form_validation extends CI_Form_validation
{
function __construct($rules = array())
{
parent::__construct($rules);
}
public function is_db2_unique($str, $field)
{
sscanf($field, '%[^.].%[^.]', $table, $field);
return isset($this->CI->db2)
? ($this->CI->db2->limit(1)->get_where($table, array($field => $str))->num_rows() === 0)
: FALSE;
}
}
I have two levels of admins who can create and update users, "Admin" and "Manager".
In my User _form.php I have a "user_type" dropdown that has my account levels.
I want to limit managers from creating "Admin" accounts, and obviously hide the dropdown entirely when a user is updating their own record.
a) Is there a way to use rules() to control this behaviour?
b) I thought about creating a scope called "hideAdmin" which would look like this:
'hideAdmin' => array(
'condition' => 'user_type != "Admin"',
),
and then creating a public method in my model called "scopeToUse()" which looks like this:
public function scopeToUse() {
$scope = 'hideAdmin()';
if(Yii::app()->authManager->checkAccess('Admin', Yii::app()->user->id)) {
$scope = 'orderAsc()';
}
return $scope;
}
And finally, creating my dropdown list like this.
<?php echo $form->dropDownList($model,'user_type_id',
CHtml::listData(UserType::model()->scopeToUse()->findAll(),'id','user_type')); ?>
I was hoping 'scopeToUse()' would return the scope name and it would work, but I just end up getting this back:
Fatal error: Call to a member function findAll() on a non-object
Any idea on the right way to do this?
EDIT
I ended up taking a cue from #Rafay-Zia-Mir and creating a new method in my user class that checked permissions and returned the appropriate CHtml::listData along with the scope I wanted. Wasn't exactly what I had intended, but the end result is the same, it kept me from putting too much code in my view, and it allowed me to use my scopes instead of duplicating the selection criteria.
This was the code:
public function userTypeDropdown() {
if(Yii::app()->authManager->checkAccess('Admin',Yii::app()->user->id)) {
$listData = CHtml::listData(UserType::model()->findAll(),'id','user_type');
} else {
$listData = CHtml::listData(UserType::model()->hideAdmin()->findAll(),'id','user_type');
};
return $listData;
}
Ok actually you can do this by using If statement in your View code. You can do like this
<?php
if(Yii::app()->authManager->checkAccess('Admin', Yii::app()->user->id)) {
?>
<?php $criteria=new CDbCriteria();
$criteria->condition="NOT user_type=Admin";
echo $form->dropDownList($model,'user_type_id',
CHtml::listData(UserType::model()->findAll($criteria),'id','user_type')); ?>
<?php } ?>
If the user is admin only then the dropdown will be shown.
EDIT: If you want to get it using function call then you can use this.
public function scopeToUse() {
if(Yii::app()->authManager->checkAccess('Admin', Yii::app()->user->id)) {
$this->getDbCriteria()->mergeWith(array(
'condition' => 'NOT user_type="Admin"',
'order'=>'id ASC'
));
}
return $this;
}
then you can use use
<?php echo $form->dropDownList($model,'user_type_id',
CHtml::listData(UserType::model()->scopeToUse()->findAll(),'id','user_type')); ?>
I've been trying to learn cakephp recently but I'm struggling to find any tutorials that deal with storing data into a table after it's been modified. I'm used having complete control where everything goes in PHP, so it's been a struggle adjusting to the automated processe of MVC.
I thought a good first experiment would be to take an input and concatenate a letter to it(let's just say "m"). Then, store both the original value and the concatenated value in a table with fields "orignal" and "concatenated". So, if I typed "hello", the value in the original field would be "hello" and the concatenated field would be "hellom".
My question is would the model be responsible for concatenating the original value? Would it also do the saving or is that the controllers responsibility?
Here is my code: I'm getting the following error.
Fatal error: Call to a member function save() on a non-object in /Applications/XAMPP/xamppfiles/htdocs/cake/app/Model/Concatenate.php on line 6
View/Concatenates/add.php
<h1>Add Something</h1>
<?php
echo $this->Form->create('Concatenate');
echo $this->Form->input('original');
echo $this->Form->end('Add Numbers');
?>
Now for the model
class Concatenate extends AppModel {
function saveConcat($original,$concatenated) {
$this->set(array(
'original' => $original,
'concatenated' => $concatenated));
$this->save();
}
}
?>
Now for the controller
<?php
class ConcatenatesController extends AppController {
public $helpers = array('Html', 'Form');
public $components = array('Session');
public function index() {
$this ->set('concatenates', $this->Concatenate->find('all'));
}
public function add() {
if ($this->request->is('post')) {
$original = $this->request->data['Concatenate']['original'];
$concatenated = $original."m" ;
$this->Concatenate->saveConcat($original,$concatenated);
}
}
function isempty(){ //used to check if there is data in the table. If there isn't any, "no data" will be displayed
$mysorts = $this->Concatenate->find('all');
$this->set('concatenates', $mysorts);
}
}
?>
This is the never ending debate (or preference) about fat model/skinny controller and vice versa.
As far as saving goes, the model should definitely handle the logic for that. Although, you would most likely call it from the controller like $myModel->save($data);
In concatenating values, I would personally handle that in the controller because it is business logic that isn't directly related to the model. For example, you may wish to concatenate a string and send it to the view instead.
[EDIT]
Disclaimer: I have almost zero experience with CakePHP but the fundamentals are the same.
You mentioned you can't get it to work, so one thing I am noticing is you have a function called Concatenate() in your model. This is the PHP4 style of constructors and is no longer "best practice" (unless of course you are running PHP4 but why on earth would you be doing that). In fact, it is likely to be deprecated entirely in the near future. The PHP5 way of doing constructors is with the __construct() function. If you do decide to use a constructor, I'd make sure to call parent::__construct(); in it to ensure the parent AppController class loads correctly.
In looking at the Concatenate() method's functionality, I doubt you intend to have that as your constructor anyway. Rename that function to something clear like saveConcat(). Also, I'm not sure I would be using $this->request->data as your source in case you want to be able to reuse this function and call it with any value. In that case, I'd add a parameter to the function
class Concatenate extends AppModel {
function saveConcat($data) {
if ($this->Concatenate->save($data)) {
$this->Session->setFlash('Your post has been saved.');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Unable to add your post.');
}
}
}
Then somewhere in your controller, you will have to actually call this function. Modify your add() function from your controller to be something like this:
public function add() {
if ($this->request->is('post')) {
// Put data into array for saving
$data[] = array( 'original' => $this->request->data );
$data[] = array( 'concatenated' => $original."m" );
// Call model function to save it
$this->Concatenate->saveConcat($data);
}
}
[EDIT 2]
I just can't figure out why I'm getting the error: Call to a member function save() on a non-object.
When you call $this->Concatenate->save from inside the Concatenate class, that means you are trying to access a variable inside the class called Concatenate and execute a function. Neither of which exist of course. The reason is you need to call the object itself as such:
$this->save("blah blah");
That method (I'm assuming is a parent method from the AppModel class) will be called referencing the current instance of the Concatenate object.
Having problems accessing session variables through different actions in ZF.
Here are the contents of the bootstrapper:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initSession()
{
Zend_Session::start();
$sessionUser = new Zend_Session_Namespace('sessionUser');
}
}
I assign a variable to $sessionUser in the IndexController:
$sessionUser->userId = $res->userId;
$sessionUser->organisationId = $res->organisation_organisationId;
$sessionUser->forename = $res->forename;
And attempt to access the variable in the Administrator controller:
$sessionUser->organisationId
Yet I receive the error:
Notice: Undefined variable: sessionUser in /usr/local/zend/apache2/htdocs/SA1/application/controllers/AdministratorController.php on line 17 Notice: Trying to get property of non-object in /usr/local/zend/apache2/htdocs/SA1/application/controllers/AdministratorController.php on line 17
And ideas what could be causing this?
Many thanks
To get the session variable back in your controller you also need to do:
$sessionUser = new Zend_Session_Namespace('sessionUser');
Well, the error you are getting is obvious. The $sessionUser is not defined.
You must initialize such variable before assinging values to it. Put this in your controller:
$sessionUser = new Zend_Session_Namespace('sessionUser');