Unable to update user profile data in database - cakephp

In my controller
public function profile() {
$UserInfo = $this->Auth->user()
if(!empty($this->data)) {
print_r($this->data);
$this->User->save($this->data);
}
if(!empty($UserInfo['id'])){
$this->data = $this->User->find('first',array('conditions'=>array('id'=>$UserInfo['id'])));
}
}
when i submit the data it is not submitted to db and i get only previous value.

Why are you querying the session here? of course this will always get you the old data again after the save.
Use the database as always, update the database again and only then overwrite the session maybe (You seem to be using cake 1.3):
public function profile() {
$uid = $this->Session->read('Auth.User.id');
if (!empty($this->data)) {
$this->data['User']['id'] = $uid;
if ($this->User->save($this->data, true, array('email', 'first_name', 'last_name', 'id', ...))) {
// if you rely on auth session data from the user, make sure to update that here
$this->Session->write('Auth.User.email', $this->data['User']['email']); // etc
...
// OK, redirect
} else {
// ERROR
}
} else {
$this->data = $this->User->find('first', ...);
}
}
As you can see I update the session keys that have been changed.
If you are using 2.x (which you did not specify as for now) you could also use
$this->Auth->login($this->request->data['User']); // must be the User array directly
although you will have to careful to pass all the data that has been in the session before.
If you plan on using login(), it would be better to find(first) the updated record again and pass this into login() then.
But personally, I prefer to only update the fields that actually changed.
see Editing own account/profile

Related

Laravel db transaction half condition

Hi i found some bug in my laravel app and wondering how to fix it :/
My controlers code
public function patvirtinimas($id,$bookid)
{
return \View::make('grazintiknyga.patvirtinti',compact('id','bookid'));
}
public function grazintiknygasave($id,$bookid,Request $request)
{
if(Input::get('taip'))
{
$grazinimas = Carbon::now();
$grazinimas->format("Y-m-d");
$kasprieme = Auth::user()->id;
$resetas = NULL;
//dd($kasprieme);
DB::beginTransaction();
try {
DB::table('borrows')
->where('id', $id)
->update(['grazinimo_data' => $grazinimas,
'prieme' => $kasprieme
]);
DB::table('books')
->where('id', $bookid)
->update(['isdavimo_data' => $resetas,
'terminas' => $resetas,
'grazinimo_data' => $resetas
]);
DB::commit();
// jeigu viskas gerai
} catch (\Exception $e) {
DB::rollback();
dd($e);
// jeigu kazkas negerai
}
return \Redirect::to(url('grazinti-knyga'))->with('grazinta','Knyga grąžinta sėkmingai!');
}
elseif(Input::get('ne'))
{
return \Redirect::to(url('grazinti-knyga'))->with('negrazinta','Knygos grąžinimas atšauktas!');
}
}
One function for viewing other for updating tables in db
routes
Route::get('patvirtinti-grazinima-{id}-{bookid}', 'BorrowController#patvirtinimas');
Route::post('grazinimas-save-{id}-{bookid}', 'BorrowController#grazintiknygasave');
The problem is when i edit route directly in my browser grazinimas-save-{someid}-{somebookid}
When one of parameters matches other dont then half of db transaction works and
other doesn't update and destroys my db :? can some one help fix this bugs ? that both parameters must match in db to update. Maybe there is some parameters hidding and validation?
Slashes / are the expected way to separate arguments in your routes.
Your parameters are not getting passed on properly to your Controller.
Changes the routes to the following (if you can)
Route::get('patvirtinti-grazinima/{id}/{bookid}', 'BorrowController#patvirtinimas');
Route::post('grazinimas-save/{id}/{bookid}', 'BorrowController#grazintiknygasave');
Another option is to handle the logic in your Controller or a Middleware (https://laracasts.com/discuss/channels/laravel/using-dash-instead-of-slash-in-routes)

Save without updating the 'modified' field

I'm working on a new project using CakePHP 3.0.
I'm using the authentication component and whenever a user logs in, I'm updating the value of the field visited.
UsersController:
public function login() {
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
$this->Users->setVisited($user['id']);
return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error('Your username or password is incorrect.');
}
}
UsersTable:
public function setVisited($id) {
$user = $this->findById($id)->first();
$user->visited = Time::now();
if($this->save($user)) {
return true;
}
return false;
}
Now, I would like to do this save without updating the value of the field modified. I've tried the approach used in previous versions of cake:
$user->modified = false;
It doesn't work though, throwing and error: Call to a member function format() on a non-object because datetime fields are now treated as objects I guess.
Any help would be greatly appreciated,
Paul
You have a couple ways of doing this. What you want is actually to avoid calling callbacks when saving the entity. For those cases you have updateAll
$this->updateAll(['visited' => Time::now()], ['id' => $id]);
You can also do the same as before, but you will need to disable the Timestamp behavior before saving:
$this->behaviors()->unload('Timestamp');
I would recommend using updateAll

change details before Cakephp Auth compontent reads the database

Does someone here know how to change the username before the Auth component reads the database?
The problem im having is im using mobile numbers as a login but i want to add the country code (if not present) when loggin in to my site
Any one have an idea on this?
Would be appreciated
If you are using CakePHP 2.0, you can manipulate the login form data as usual and then call $this->Auth->login(). Example:
// in your controller
public function login() {
if ($this->request->is('post')) {
$this->data['User']['username'] = $this->addCountryCode($this->data['User']['username']);
if ($this->Auth->login()) {
// login successful
} else {
// login not successful
}
}
}
you could always extend the Auth component and do whathever you want before the asking the database :)
Something like this...
function login($data = null,$public = false) {
$this->__setDefaults();
$this->_loggedIn = false;
if (empty($data)) {
$data = $this->data;
}
if (/** query the database to check/modify the data. You could use the identify() method of the AuthComponent **/) {
$this->Session->write($this->sessionKey, $user);
$this->_loggedIn = true;
}
return $this->_loggedIn;
}
If you extend the auth component, remember to always use this component instead of the default Auth class. (e.g. in the AppController, the build_acl, the initdb, the beforefilter on the controllers, etc.)
Hope this helps

CakePHP organising controllers

i have the following queries common on few methods of the controllers. so is there a way to organise it ? i will need all the variables in the controller so i cant create a private method and return it.
// Checks if the User is logged in if yes gathers the ID
$id = $this->_loggedIN();
// Find the ItemID from the Item Table
$itemId = $this->User->Item->itemId('1', $id);
// Finding the User Data and last Status Message
$user = $this->User->Item->find('first', array('conditions' => array('Item.id' => $itemId), 'contain' => array('User', 'StatusMessage' => array('limit' => 1, 'order' => 'StatusMessage.created DESC'))));
Since this seems to pertain to the logged in user, you should do this once and save the data in the session. If you're using the AuthComponent (which you probably should), there already is a generic way to find out whether a user is logged in and what his id is:
$this->Auth->user('id');
All the other data of the user model is accessible in the same way. This is simply stored in the session under the key 'Auth' and is accessible like $this->Session->read('Auth.User.id'). If you want to store even more data about the user in the session (like related items or whatnot), do it once in the login method.
function beforeFilter() {
$this->Auth->autoRedirect = false;
}
function login() {
if ($this->Auth->user()) {
$item = /* find item */;
$user = /* find user */;
$this->Session->write('Auth.Item', $item);
$this->Session->write('Auth.User', $user);
$this->redirect($this->Auth->redirect());
}
}
How about a function in the AppController? Or even better - AppModel?

Cakephp Auth with multiple "Users" tables

I would like to know how to deal with only ONE authentification process and "users" in multiple tables. I have 4 Users table: users, admins, artists, teamadmins which all have specific fields, but I would like all of these users to be able to connect via only one form on the homepage, and being redirected after that to their specific dashboards.
I think the redirections shouldn't be a problem, and some routes added should work, but I really don't know where to look/start to ake this all possible.
Cheers,
Nicolas.
EDIT: here's the final solution (thanks to deizel)
App::import('Component', 'Auth');
class SiteAuthComponent extends AuthComponent {
function identify($user = null, $conditions = null) {
$models = array('User', 'Admin', 'Artist');
foreach ($models as $model) {
$this->userModel = $model; // switch model
$this->params["data"][$model] = $this->params["data"]["User"]; // switch model in params/data too
$result = parent::identify($this->params["data"][$model], $conditions); // let cake do its thing
if ($result) {
return $result; // login success
}
}
return null; // login failure
}
}
CakePHP's AuthComponent only supports authentication against a single "User" model at a time. The model is chosen by setting the Auth::userModel property, but it only accepts a string and not an array of models.
You can switch the userModel on the fly with the following code, but this requires you to know in advance which model to switch to (eg. your users have to choose their account type from a dropdown):
public function beforeFilter() {
if (isset($this->data['User']['model'])) {
$this->Auth->userModel = $this->data['User']['model'];
}
}
You can likely extend the core AuthComponent to add the functionality you want by overwriting the AuthComponent::identify() method so it loops over and attempts authentication with each model:
App::import('Component', 'AuthComponent');
class AppAuthComponent extends AuthComponent {
function identify($user = null, $conditions = null) {
$models = array('User', 'Admin', 'Artist', 'TeamAdmin');
foreach ($models as $model) {
$this->userModel = $model; // switch model
$result = parent::identify($user, $conditions); // let cake do it's thing
if ($result) {
return $result; // login success
}
}
return null; // login failure
}
}
You will have to replace occurrences of Auth in your application with AppAuth to use your extended AuthComponent, unless you use this trick.
While annoying, I think the best solution is probably using Cake's built in ACL support (see http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html).
If you do authentication the way you're talking about, you have to keep track of permissions in your controller code, checking to see what the userModel is. If you use an access control list, the permission tree will already exist in the database, which should simplify your code a great deal, and make it more modular.
It also means restructuring your data model to have a single users table and groups table instead of entity classes for each type of user.
I just went through the process of doing this myself... :(
this is also a possibility
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->authenticate = array(
AuthComponent::ALL => array('userModel' => 'AnotherModel'),
'Form',
'Basic'
);
}
Here is the final solution as suggested by deizel and modified by Nicolas:
App::import('Component', 'Auth');
class SiteAuthComponent extends AuthComponent {
function identify($user = null, $conditions = null) {
$models = array('User', 'Admin', 'Artist');
foreach ($models as $model) {
$this->userModel = $model; // switch model
$this->params["data"][$model] = $this->params["data"]["User"]; // switch model in params/data too
$result = parent::identify($this->params["data"][$model], $conditions); // let cake do its thing
if ($result) {
return $result; // login success
}
}
return null; // login failure
}
}

Resources