I'm trying to protect administrators from accidentally deleting each other in CakePHP 2.4 by checking the group_id. I tried using the following delete method, but it deletes the user anyway and doesn't redirect. How do I return the group_id of the user and then redirect and display an appropriate flash saying "Administrators cannot be deleted"?
public function delete($id = null) {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException();
}
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
if ($user['User']['group_id'] == 1) { //Check user group
$this->Session->setFlash(__('Administrators can not be deleted'), 'flash/error');
$this->redirect(array('action' => 'index'));
}
if (!$this->User->delete()) {
$this->Session->setFlash(__('User could not be deleted'), 'flash/error');
$this->redirect(array('action' => 'index'));
}
if ($this->User->delete()) {
$this->Session->setFlash(__('User deleted'), 'flash/success');
$this->redirect(array('action' => 'index'));
}}
You have a typo in your code -- change your = to == ; then your if statement shouldn't be evaluating as true all the time
if ($user['User']['group_id'] == '1')
Session is either a component (part of the Controller layer) or a helper (part of the View layer) -- it is not intended to be used in the Model, nor should it be used in the model, generally. And redirect() is a controller method only. Just have beforeDelete return false, and then in your controller have a check to see if the delete failed (i.e. it returned false), and if so, show your error flash message, and redirect.
Related
I am trying to edit one of my members password (i have been allowed by the user).
Now for this function i have the following action:
if (!$this->User->exists($id)) {
throw new NotFoundException(__('Invalid USer'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The User has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The User could not be saved. Please, try again.'));
}
} else {
}
}
However when i try to save i get the following error:
2013-10-21 11:53:53 Error: [PDOException] SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'MarcEmp' for key 'username'
So it tries to insert a new entry.
Does anyone know what i am doing wrong?
You are forgetting to set the current id to update, so Cake will try to create a new record by default. Try adding:
$this->User->id = $id;
Just before the save operation. So your entire function should look like:
/**
* Edit an existing user.
*
* #param int $id The user id to edit.
*/
public function edit($id) {
if (!$this->User->exists($id)) {
throw new NotFoundException(__('Invalid User'));
}
if ($this->request->is('post') || $this->request->is('put')) {
$this->User->id = $id; // <-- Add it here
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The User has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The User could not be saved. Please, try again.'));
}
}
}
I'm using isAuthorized to deny access to methods if the record id doesn't belong to the user. Profiles can have many documents and documents belong to one profile:
Controller/DocumentsController.php
public function add($id = null) {
if ($this->request->is('post')) {
$this->request->data['Document']['profile_id'] = $id;
$this->request->data['Document']['user_id'] = $this->Auth->user('id');
$this->Document->create();
if ($this->Document->save($this->request->data)) {
$this->Session->setFlash(__('The document has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The document could not be saved. Please, try again.'));
}
}
}
public function isAuthorized($user) {
if ($this->action === 'index') {
return true;
}
if (in_array($this->action, array('view', 'add', 'edit', 'delete'))) {
$document_id = $this->request->params['pass'][0];
if ($this->Document->isOwnedBy($document_id, $user['id'])) {
return true;
}
}
return parent::isAuthorized($this->Auth->user());
}
Model/Document.php
public function isOwnedBy($document, $user) {
return $this->field('id', array('id' => $document, 'user_id' => $user)) === $document;
}
I'm passing the profile id as $id to docments/add from one of my profile views via Cake link helper:
View/Profiles/view.ctp
echo $this->Html->link('New Document',
array('controller' => 'documents', 'action' => 'add',$profile['Profile']['id'])
);
What happens when I click on New Document from profiles/view is that it sends the request but doesn't redirect, just refreshes the page, or it redirects back to profiles/view, not sure which. My first guess is since I'm not defining the profile id in the isAuthorized callback within DocumentsController, isOwnedBy is returning false. Any suggestions on how to get the profile id in isAuthorized within DocumentsController?
Thanks in advance!
The solution to this is relativley easy. When using isAuthorized with parameters from another controller, be sure to reference the right model.
if ($this->Document->Profile->isOwnedBy($document_id, $user['id'])) {
return true;
}
I need to delete icon file related to current news if news was deleted.
I see 2 approaches.
First:
public function admin_delete ($id = null, $icon = null) {
if ($this->request->is('get')) {
throw new MethodNotAllowedException();
}
if ($this->News->delete($id)) {
unlink(WWW_ROOT . 'img/icons/news/' . $icon);
$this->Session->setFlash('ok!');
$this->redirect(array('action' => 'index'));
}
}
I need to pass the record ID and filename to this action from view.
For me it seems slightly ugly and also can cause Nginx related issues.
Second one:
public function admin_delete ($id = null) {
if ($this->request->is('get')) {
throw new MethodNotAllowedException();
}
$icon = $this->News->read('icon', $id);
if ($this->News->delete($id)) {
unlink(WWW_ROOT . 'img/icons/news/' . $icon['icon']);
$this->Session->setFlash('ok!');
$this->redirect(array('action' => 'index'));
}
}
But I'm not sure is it a good approach and should I use read or find('first').
I hope you can give me some advice on how to do it in more correct way.
Thanks in advance!
None of that stuff should be in controller. Fetch the record using find('first') in the model's beforeDelete() and save the filename in a model property. Then in afterDelete() delete file who's filename you cached in beforeDelete().
I'm trying to access data in my Model for my controller method.
For starters what is the difference between these two???
$post = $this->Post->find('first',array('conditions'=>array('Post.id'=>$id)));
$this->set(compact('post'));
and
$this->Post->id = $id;
$this->data = $this->Post->read();
as I'm trying to compare the user_id for a post against the logged in user like so:
if($this->Post->user_id != $this->Auth->user('id'))
but it doesn't work as intended (it always returns false)... what is the difference between the two code chunks and why doesn't my line above work properly?
test to see if it helps to compare this code "userid":
function index() {
$user_id = $this->data['Post']['user_id'];
if($user_id != $this->Auth->user('id')){
//go
}
}
This is what I ended up with:
$post = $this->Post->find('first',array('conditions'=>array('Post.id'=>Tiny::reverseTiny($id))));
if ($this->request->is('post') || $this->request->is('put'))
{
$this->Post->id = $post['Post']['id'];
if ($this->Post->save($this->request->data))
{
$this->Session->setFlash('Your post has been updated');
$this->redirect(array('controller' => 'posts', 'action' => 'index'));
}
else
{
$this->Session->setFlash('Server broke!');
}
}
else
{
if($post['Post']['user_id'] != $this->Auth->user('id'))
{
$this->Session->setFlash('Not yours!');
$this->redirect(array('controller' => 'posts', 'action' => 'index'));
}
else
{
$this->request->data = $this->Post->read(null, $post['Post']['id']);
}
}
There are differences between find() and read(), read will grab all related model data and set the active record of the model to the result. Whereas a find will just all related model data in a query and assign the result to the variable.
Use debug($this->data) to reveal the structure of your returned data. You will find it is $this->data['Post']['user_id'] for the User ID.
i research about mvc and n-tier architecture different. but i can't understand how model pass data to view in mvc?
for example in cakephp I have an controller and action like this:
function edit($id = null) {
if (!$id && empty($this->data)) {
$this->Session->setFlash(__('Invalid user', true));
$this->redirect(array('action' => 'index'));
}
if (!empty($this->data)) {
if ($this->User->save($this->data)) {
$this->Session->setFlash(__('The user has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.', true));
}
}
if (empty($this->data)) {
$this->data = $this->User->read(null, $id);
}
$groups = $this->User->Group->find('list');
$this->set(compact('groups'));
}
in this section:
if (!$id && empty($this->data)) {
$this->Session->setFlash(__('Invalid user', true));
$this->redirect(array('action' => 'index'));
}
we check that id passed or not. if have not be set we redirect user. than:
if (!empty($this->data)) {
if ($this->User->save($this->data)) {
$this->Session->setFlash(__('The user has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.', true));
}
}
if submitted data from view we update row in db. then :
if (empty($this->data)) {
$this->data = $this->User->read(null, $id);
}
$groups = $this->User->Group->find('list');
$this->set(compact('groups'));
and if id have been set and if not data submitted its mains the page early opened and data in relation this id will be read from db and displayed in view.
now I can't understanding how and where model pass data to view in this cakephp's standard mvc????
thanks for help.
Models do not send data to the view. controllers do, by calling the set method. controllers use models to get data from database and then send it to the view:
$this->set('myVariable','myValue');
or you can use compact to send complex data at once like in your example:
$groups = $this->User->Group->find('list');
$this->set(compact('groups'));