Create new hasMany children from parent controller - cakephp

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'));
}

Related

Saving data using where clause

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()

Can't pass an entity as an parameter to another action in the same controller in CakePHP 3.2

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.

Saving single data into a database - CakePHP

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)) {

on editing inserting a new row instead of updating the current row in cakephp 2x

I m having trouble in updating the student profile form,after i gave the user_id to the student profile.Every time when i try to edit the form, on saving it provide new id to the existing user. I don't know where I'm getting wrong. Plz help.Thanks in Advance.
Here is my add and edit function in Student Profiles controller:
public function add() {
if ($this->request->is('post')) {
$this->StudentProfile->create();
$data = $this->request->data;
$data['StudentProfile']['user_id'] = $this->Auth->user('id');
// code implemented below
//$this->loadModel('User');
if ($this->StudentProfile->save($data)) {
//Update user here if Profile saved successfully
//$this->StudentProfile->id = $this->Auth->user('id');
$this->Session->setFlash(__('Your account profile has been created'));
$this->redirect(array('controller' => 'studentprofiles', 'action' => 'index'));
}else{
$this->Session->setFlash(__('Your Profile was saved, but an error has occurred while updating the Users table'));
//Email your self the user ID here or something ??
}
}
$h=array(
'fields' => array('Height.height'),
'recrusive' => 0
);
$this->loadModel('Height');
$height = $this->Height->find('list',$h);
$this->set(compact('height'));
}
public function edit($id = null) {
if (!$this->StudentProfile->exists($id)) {
throw new NotFoundException(__('Invalid student profile'));
}
if ($this->request->is(array('post', 'put'))) {
$this->request->data['StudentProfile']['user_id'] = $this->Auth- >user('id');
// code implemented below
// $this->loadModel('User');
if ($this->StudentProfile->save($this->request->data)) {
//$this->StudentProfile->id = $this->Auth->user('id');
$this->Session->setFlash(__('The student profile has been saved.'), 'default', array('class' => 'alert alert-success'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The student profile could not be saved. Please, try again.'), 'default', array('class' => 'alert alert-danger'));
}
} else {
$options = array('conditions' => array('StudentProfile.' . $this- >StudentProfile->primaryKey => $id));
$this->request->data = $this->StudentProfile->find('first', $options);
}
$h=array(
'fields' => array('Height.height'),
'recrusive' => 0
);
$this->loadModel('Height');
$height = $this->Height->find('list',$h);
$this->set(compact('height'));
}
Can't believe I'm replying to my own question . Well In case anyone have the same above problem,the solution is just add the following code after this-
$this->request->data['StudentProfile']['user_id'] = $this->Auth->user('id');
// add this code to avoiding giving new id to existing user on edit:
$this->request->data['StudentProfile']['id'] = $id;
A better way of saving edited information is to set the ID on the model before the save like so
$this->StudentProfile->id = $this->Auth->user('id');
If you initiate a save after setting the above then the row will be edited and not add a new row.

Cakephp 2 model beforeSave() not being called

I can't figure out why this code isn't working. The beforeSave is not being called. It's supposed to fail the save and put some lines in the debug log, but it actually does save OK and no lines are written in the debug log.
<?php
class Link extends AppModel {
var $name = "Link";
var $belongsTo = array('Category' => array('className' => 'Category', 'foreignKey' => 'category_id'));
public function beforeSave(){
if ($this->data[$this->alias]['id'] == null) {
$this->log("new record", 'debug');
$link = $this->find('first',array('conditions' => array('Link.status = 1 AND Link.category_id = '.$this->data[$this->alias]['category_id']), 'order' => array('Link.order DESC') ));
if (is_null($link)) {
$this->data[$this->alias]['order'] = 1;
}else{
$this->data[$this->alias]['order'] = $link['Link']['order'] + 1;
}
}
else {
$this->log("old record", 'debug');
}
return false;
}
}
?>
I am launching a save in the controller like this:
public function add($category_id = null)
{
if ($category_id == null) {
$this->Session->setFlash(__('Category id cant be null'),'default', array('class' => 'error-message'));
$this->redirect(array('action' => 'index', 'controller' => 'categories'));
}
else
{
if($this->request->is('post'))
{
$this->Link->create();
$this->Link->set('category_id' => $category_id));
if($this->Link->save($this->request->data))
{
$this->Session->setFlash(__('The link has been saved'),'default', array('class' => 'success'));
$this->redirect(array('action' => 'index/'.$category_id));
}
else
$this->Session->setFlash(__('The link could not be saved. Please, try again.'),'default', array('class' => 'error-message'));
}
$this->set('category_id',$category_id);
}
}
Another question in StackOverflow points out that the beforeSave method needs to be declared in the Model. I've also done the same thing with another model.
Here's some general advice and some comments on your code for an answer:
1) If a model callback or any model method isn't working, make sure the correct model is being used and not the default model (AppModel). Check filename, class name, extension (in your case), and location.
2) You're using conditions array incorrectly (in this case).
array('conditions' => array('Link.status = 1 AND Link.category_id = '.$this->data[$this->alias]['category_id'])
You should really be doing:
array('conditions' => array('Link.status' => 1, 'Link.category_id' => $this->data[$this->alias]['category_id'])
3) Your redirect is being used wrong
$this->redirect(array('action' => 'index/'.$category_id));
Should be:
$this->redirect(array('action' => 'index', $category_id));
As written, your save() will always fail with this beforeSave(). beforeSave() must return true in order for the save function to succeed.
In fact, yours appears to always return false, guaranteeing a failed save.
From the Cake manual:
Be sure that beforeSave() returns true, or your save is going to fail.

Resources