I would like to be able to save data while providing a where clause.
I have the following code:
$game = $this->Games->newEntity();
if ($this->request->is('post')) {
$game = $this->Games->patchEntity($game, $this->request->data);
if ($this->Games->save($game)) {
$this->Flash->success(__('The game has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The game could not be saved. Please, try again.'));
}
}
I tried this, but it didn't work:
$this->Games->save($game)->innerJoinWith('Leagues', function ($q) use($s) {
return $q->where(['Leagues.user_id' => $s]);
}
)
I suspect having to do a find with a where clause and patch the request data to it?
$game = $this->Games->find()->innerJoinWith('Leagues', function ($q) {
return $q->where(['Leagues.user_id' => $this->Auth->user('id')]);
})
->where(['Games.id' => $id])
->first();
if(! count($game)){
$this->Flash->error(__('The game could not be found.'));
return $this->redirect(['action' => 'index']);
}
if ($this->request->is('post')) {
$game = $this->Games->patchEntity($game, $this->request->data);
if ($this->Games->save($game)) {
$this->Flash->success(__('The game has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The game could not be saved. Please, try again.'));
}
}
Anything simpler?
There is no such saving syntax, retrieving the proper entity in beforehand is the correct way to go, and there isn't really a "simpler" way - however there surely is room for optimization.
Personally I'd use finders to DRY things up, ie create a finder on the GamesTable that restricts things to specific league users:
public function findForLeagueUser(\Cake\ORM\Query $query, array $options)
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('The `id` option is invalid or missing.');
}
return $query
->innerJoinWith('Leagues', function (\Cake\ORM\Query $query) use ($options) {
return $query->where([
$this->Leagues->aliasField('user_id') => $options['id']
]);
});
}
and combine things in the controller action:
$game = $this->Games
->find('forLeagueUser', ['id' => $this->Auth->user('id')])
->where(['Games.id' => $id])
->first();
You could also use firstOrFail() instead, which throws an exception if the record cannot be found, this is what Table::get() does internally too.
And you could reduce things even further by using a dynamic finder for the games id:
$game = $this->Games
->findById($id)
->find('forLeagueUser', ['id' => $this->Auth->user('id')])
->first();
See also
Cookbook > Database Access & ORM > Retrieving Data & ... > Using Finders to Load Data
Cookbook > Database Access & ORM > Retrieving Data & ... > Custom Finder Methods
Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Dynamic Finders
API > \Cake\Datasource\QueryTrait::firstOrFail()
Related
I have two controllers "Events" and "Activities" and both have many "Attendees".
$this->hasMany('Attendees')
->setClassName('Attendees')
->setForeignKey('foreign_id')
->setConditions(array('Attendees.class' => 'Activity'))
->setDependent(true);
I am using a class and a foreign_id in my Attendees table to link them. I would like to create addAttendee() function in my ActivitiesController for example to add a new attendee, but I am not sure how to proceed.
public function addAttendee($id = null)
{
$activity = $this->Activities->get($id, ['contain' => ['Venues', 'Contacts']]);
if ($this->request->is('post'))
{
??
}
$this->set(compact('activity'));
}
I found some documentation on saving with association but not on creating new association.
You can create a new Attendee entity then link it to your $activity.
$data = ['first_name' => 'blah', 'last_name' => ... fields]);
$attendee = $this->Attendee->newEntity($data);
$this->Attendee->link($activity, [$attendee]);
source: https://api.cakephp.org/4.2/class-Cake.ORM.Association.HasMany.html#link()
I proceed this way. It's working but not sure if it's the right way to proceed ??
public function addAttendee($id)
{
$activity = $this->Activities->get($id, ['contain' => ['Venues', 'Contacts']]);
$attendee = $this->Activities->Attendees->newEmptyEntity();
if ($this->request->is('post'))
{
$attendee = $this->Activities->Attendees->patchEntity($attendee, $this->request->getData() + ['class' => 'retreat', 'foreign_id' => $id]);
if ($this->Activities->Attendees->save($attendee))
{
$this->Flash->success(__('The attendee has been saved.'));
return $this->redirect(['action' => 'view', $id]);
}
$this->Flash->error(__('The attendee could not be saved. Please, try again.'));
}
$this->set(compact('activity', 'attendee'));
}
While adding a new book into the DB I want to have separate actions for patching the request in a new entity and for saving that entity. The action for patching request into new entity returns this entity to another method.
The code is like this:
public function bookAdder($book = [])
{
if ($this->Books->save($book)) {
$this->Flash->success(__('The book has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The book could not be saved. Please, try again.'));
return $this->redirect(['action' => 'add']);
}
}
public function add()
{
$user_id = $this->request->session()->read('Auth.User.id');
$book = $this->Books->newEntity();
if ($this->request->is('post')) {
$book = $this->Books->patchEntity($book, $this->request->data);
$book->set(array('user_id' => "$user_id"));
return $this->redirect(['action' => 'bookAdder', $book]);
}
$users = $this->Books->Users->find('list', ['limit' => 200]);
$this->set(compact('book', 'users'));
$this->set('_serialize', ['book']);
}
While saving a test record, I am getting this error:
Error: A route matching "/books/book-adder/{ "title": "cc", "writer":
"cc", "edition": "cc", "course": "cc", "description": "cc", "price":
2, "user_id": "1"}" could not be found.
Error screenshot Here
I also tried public function bookAdder($book){ }
but still no success.
Is there any way to solve this issue? Thanks in advance!
Multiple Functions !
Are you doing some practice for making multiple functions ? That's
great if you make your function reusable and more readable.
But what you are doing here is adding some complexity for nothing. When you redirect to bookAdder function you would generate url something like this:
book-adder/%7B%0A%20%20%20%20"name"%3A%20"abc"%2C%0A%20%20%20%20"user_id"%3A%20"1"%0A%7D
And you are passing entity as function parameter. And obviously that routing error occur.
So you really don't need multiple function here at least for things you are doing.
Make it simple:
public function add()
{
$user_id = $this->request->session()->read('Auth.User.id');
$book = $this->Books->newEntity();
if ($this->request->is('post')) {
$book = $this->Books->patchEntity($book, $this->request->data);
$book->set(array('user_id' => "$user_id"));
if ($this->Books->save($book)) {
$this->Flash->success(__('The book has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The book could not be saved. Please, try again.'));
return $this->redirect(['action' => 'add']);
}
}
$users = $this->Books->Users->find('list', ['limit' => 200]);
$this->set(compact('book', 'users'));
$this->set('_serialize', ['book']);
}
If you really need entity from another function program flow should be something like this:
makeEntity function:
public function makeEntity($book = null,$requestData = []) {
$book = $this->Books->patchEntity($book, $requestData);
return $book;
}
Add function:
public function add()
{
$user_id = $this->request->session()->read('Auth.User.id');
$book = $this->Books->newEntity();
if ($this->request->is('post')) {
$book = $this->makeEntity($book, $this->request->data);
$book->set(array('user_id' => "$user_id"));
return $this->redirect(['action' => 'bookAdder', $book]);
}
$users = $this->Books->Users->find('list', ['limit' => 200]);
$this->set(compact('book', 'users'));
$this->set('_serialize', ['book']);
}
And which doesn't make much differences.
I tried to do on all things I think and I dont know how to do it. I have read the book of Cake...
I dont know how to add this value in 1 column in my database.
When I'm adding 'Task' I want to add my 'name' in column 'created_by'.
Code from Add Task:
public function add()
{
$task = $this->Tasks->newEntity();
if ($this->request->is('post')) {
$task = $this->Tasks->patchEntity($task, $this->request->data);
if ($this->Tasks->save($task)) {
$this->Flash->success(__('The task has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The task could not be saved. Please, try again.'));
}
}
$users = $this->Tasks->Users->find('list', ['limit' => 200]);
$this->set(compact('task', 'users'));
$this->set('_serialize', ['task']);
}
When I will write
echo $this->Auth->user('name');
die();
I have got my name which is 'Mariusz'.
Now I want to add it into column 'created_by'. I think I need to change this line:
$task = $this->Tasks->patchEntity($task, $this->request->data);
But I dont know how. In book of Cake there is information
$articles->patchEntity($article, $this->request->data(), [
'validate' => 'custom',
'associated' => ['Tags', 'Comments.Users' => ['validate' => 'signup']]
]);
But I dont think its good.
I have created the relation
User -> has_many -> Task
Task -> belongs_To -> User
Please can you try following code :
$data['name']=$this->Auth->user('name');
$task = $this->Tasks->patchEntity($task, $data);
if ($this->Tasks->save($task)) {
I am using cakephp 3.x and i have an edit function in my controller in which i am checking whether id is in the query string or not as well as whether is it exists in the database record or not. Here below is my code which is working perfectly fine.
UsersController.php
public function edit($id = null)
{
// first checking whether id sent or not ..
if(empty($this->request->params['pass']))
{
$this->Flash->error('Invalid Action');
return $this->redirect(['action' => 'index']);
}
// Now checking whether this user id exists or
$check_user = $this->Users
->find()
->where(['user_id' => $id])
->toArray();
if(!$check_user)
{
$this->Flash->error('Invalid Id, User not found');
return $this->redirect(['action' => 'index']);
}
$user = $this->Users->get($id);
// And so on
}
The thing is, i am using this same code in many other functions to check the same thing so i had comeup creating a common function in the same controller and use it in multiple functions like below.
UsersController.php (Updated)
public function checkId($id)
{
// first checking whether id sent or not ..
if(empty($this->request->params['pass']))
{
$this->Flash->error('Invalid Action');
return $this->redirect(['action' => 'index']);
}
// Now checking whether this user id exists or
$check_user = $this->Users
->find()
->where(['user_id' => $id])
->toArray();
if(!$check_user)
{
$this->Flash->error('Invalid Id, User not found');
return $this->redirect(['action' => 'index']);
}
}
public function edit($id = null)
{
$this->checkId($id);
}
Now if i execute the url in my browser http://localhost/5p_group/users/edit/ , i get this error saying Record not found in table "users" with primary key [NULL]
Can someone guide me how to fullfil both these 2 conditions (check id in the url or not as well as is it valid id or not) using common function which i have created above .. it is working absolutely fine if i put that code inside my same edit() function.
Any help or suggestion will be highly appreciated.
Thanks
In your code you forgot to add function parameter $id, you already use it in the query
public function checkId()
change to
public function checkId($id)
[Update]
Here is also a function return issue
if(empty($id))
{
$this->Flash->error('Invalid Action');
return $this->redirect(['action' => 'index']);
}
change to >>
if(empty($id))
{
$this->Flash->error('Invalid Action');
$this->response = $this->redirect(['action' => 'index']) ;
$this->response->send () ;
die () ;
}
I have a users controller, where if I add a user I want to redirect based on the usertype a user selects on making his account
the situation:
users table
id
name
usertype_id
The user add form has a select box for user type, I have two types of users: teachers and students (each another table, model, controller) if the user chooses teacher I want to redirect to /teachers/add/$id if the user chooses student I want to redirect to: /students/add/$id
this is what I have atm, but that doesn't work obviously
<?php
class UsersController extends AppController {
var $name = 'Users';
function add() {
if (!empty($this->data)) {
$this->User->create();
if ($this->User->save($this->data)) {
$id = $this->User->id;
if ($this->User->usertype_id=='1')
{
$this->redirect(array('students/add/'.$id));
} elseif ($this->User->usertype_id=='2') {
$this->redirect(array('teachers/add/'.$id));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.', true));
}
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.', true));
}
}
$usertypes = $this->User->Usertype->find('list');
$this->set(compact('usertypes'));
}
}
?>
I'm pretty sure the problem is the assumption that, because $this->User->id exists, $this->User->usertype_id must also exist, which it does not. I ran into that issue when I first started working with CakePHP, too. :)
If the user type was passed via the add form, you need to check the data array:
Change
if ($this->User->usertype_id=='1')
To
if ($this->data['User']['usertype_id'] == '1')
If that doesn't work (I can't remember if $this->data is emptied after a successful save) then you should store the value prior to the save, like so:
function add() {
if (!empty($this->data)) {
$usertype_id = $this->data['User']['usertype_id'];
$this->User->create();
if ($this->User->save($this->data)) {
$id = $this->User->id;
if ($usertype_id == '1') {
$this->redirect(array('students/add/'.$id));
} elseif ($usertype_id == '2') {
// the rest remains the same
Addendum
Rather than using the concatenation in your redirect, This looks cleaner to me:
$this->redirect(array('controller' => 'teachers', 'action' => 'add', $id));
But I guess that's just preference.
Addendum 2
I have some additional advice about cleaning up your controller and moving all of the logic to the model. This way you can re-use the code from other controllers in the future, and your current controller will be easier to read. I would change the entire method to look like this:
// this is in /controllers/users_controller.php
function add() {
if (!empty($this->data)) {
$saved_user = $this->User->save_user($this->data);
if ($saved_user['success']) {
$this->redirect(array(
'controller' => $saved_user['controller'],
'action' => 'add',
$this->User->id
));
}
}
$this->Session->setFlash(__('The user could not be saved. Please, try again.', true));
$usertypes = $this->User->Usertype->find('list');
$this->set(compact('usertypes'));
}
// this is in your model, /models/user.php
function save_user($data) {
$this->create;
$usertype_id = $data['User']['usertype_id'];
return array(
'controller' => ($usertype_id == '2') ? 'teachers': 'students';
'success' => $this->save($data),
);
}