cakephp-3 hasmany form data save - cakephp

I have two tables resumes and links. resumes has hasmany relation with links.I want to save many links for single resume.
My $this->request->data array is like
Array
(
[alternate_email] =>
[mobile] => 23232
[level] => Student
[youtube] =>
[links] => Array
(
[0] => Array
(
['link'] => www.google.com
['user_id'] => 1
)
[1] => Array
(
['link'] => abc.com
['user_id'] => 1
)
)
)
$resume = $this->Resumes->newEntity($this->request->data);
if ($this->Resumes->save($resume)) {
// return true;
}
This is working and my data is saved in resumes table properly but in links table data saved like following:
id | resume_id | user_id | link
1 | 1 | |
I want like
id | resume_id | user_id | link
1 | 1 | | www.google.com

try do that:
$resume = $this->Resumes->newEntity($this->request->data, ['associated' => ['Links']]);
if ($this->Resumes->save($resume, ['associated' => ['Links']])) {
// return true;
}

Go to your Model/Entity/Link.php and add link to protected $_accessible array

Related

CodeIgniter Database Rows Into Arrays To Use By Parser For Views Built-In Template

1) My original settings table design:
-------------------------------------------
site_name | site_slogan | site_url
-------------------------------------------
Company | This rocks! | http://localhost/
-------------------------------------------
However, I would like to redesign so I can explicitly put different datatypes like char(255) or varchar(512), or maybe INT in the future for each row:
-------------------------------
name | value
-------------------------------
site_name | Company
site_slogan | This rocks!
site_url | http://localhost/
site_phone | 123465798
-------------------------------
In my controller, I would like to use $this->parser->parse('page',$data); but I don't know how to put the result of my database query into arrays in a loop so that in my Views I can use them like this:
{site_name} - {site_slogan}
Edit:
This the result of $data = $this->db->select("*")->from('settings')->get()->result_array(); from the feedback I received.
Array
(
[0] => Array
(
[name] => site_name
[value] => My Name
)
[1] => Array
(
[name] => site_tagline
[value] => My Tagline
)
[2] => Array
(
[name] => site_url
[value] => My URL
)
)
So this is how I parse and make them usable in views {site_name} {site_tagline} {site_url} .
$data = array(
'site_name' => $data['0']['value'],
'site_tagline' => $data['1']['value'],
'site_url' => $data['2']['value']
);
$this->parser->parse('page', $data);
You could assign the $data values to a new array and pass the new array instead :
foreach ($data as $key => $cfg) {
$new_data[$cfg['name']] = $cfg['value'];
}
$this->parser->parse('page', $new_data);

Updating belongsToMany association data

I am setting up a form that updates person and the associated person_to_role tables, person_to_role is a intermediate table that links person to role in a n..n relationship. role has a predefined list of roles, that shouldn't be modified from a person's scope.
I only need to update role_id and description in the person_to_role table and add/remove records.
SQL
--person
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| NICK_NAME | varchar(16) | YES | | NULL | |
| FIRST_NAME | varchar(24) | NO | | NULL | |
| MIDDLE_NAME | varchar(8) | YES | | NULL | |
| LAST_NAME | varchar(24) | NO | | NULL | |
| BIRTH_DATE | date | NO | | NULL | |
| GENDER | varchar(8) | NO | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
-- role
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| NAME | varchar(24) | NO | | NULL | |
| DESCRIPTION | varchar(100) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
--person_to_role
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| PERSON_ID | int(11) | NO | MUL | NULL | |
| ROLE_ID | int(11) | NO | MUL | NULL | |
| DESCRIPTION | varchar(100) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
PersonTable Model
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('person');
$this->setDisplayField('ID');
$this->setPrimaryKey('ID');
// define relations
$this->belongsToMany('Role', [
'joinTable'=> 'person_to_role',
'foreignKey' => 'PERSON_ID'
]);
}
Person controller -> edit()
public function edit($id = null)
{
$person = $this->Person->get($id, [
'contain' => ['role']
]);
$this->set('roles', $this->Person->Role->find('list'));
if ($this->request->is(['patch', 'post', 'put'])) {
$person = $this->Person->patchEntity($person, $this->request->getData());
if ($this->Person->save($person)) {
$this->Flash->success(__('The person has been saved.'));
return $this->redirect(['action' => 'index']);
}
$errors = print_r($person->errors(),1);
$this->Flash->error(__('The person could not be saved. Please, try again.<br><pre>'. $errors .'</pre>'),['escape'=> false]);
}
$this->set(compact('person'));
$this->set('_serialize', ['person']);
}
edit.ctp form fields
echo $this->Form->control('NICK_NAME');
echo $this->Form->control('FIRST_NAME');
echo $this->Form->control('MIDDLE_NAME');
echo $this->Form->control('LAST_NAME');
echo $this->Form->control('BIRTH_DATE');
echo $this->Form->control('GENDER',['type'=>'select','options'=>[''=> '-
Please Select -', 'Male'=>'Male','Female'=>'Female']]);
Assigned roles
...
<?php foreach ($person->role as $k=>$role) { ?>
<tr><td><?php
echo $this->Form->input("role.$k._joinData.ID",['type'=>'hidden','value'=>$person->role[$k]['_joinData']['ID']]);
echo $this->Form->input("role.$k._joinData.ROLE_ID",['value'=>$role-
>ID,'options'=>$roles,'templates'=>['formGroup' =>'{{input}}']])
?></td><td>
<?php echo $this->Form->input("role.$k._joinData.DESCRIPTION", ['value'=>$person->role[$k]['_joinData']['DESCRIPTION'],'templates'=>
['formGroup' =>'{{input}}']]); ?></td></tr>
<?php } ?>
...
This gives me the following POST data:
'NICK_NAME' => 'Johny',
'FIRST_NAME' => 'John',
'MIDDLE_NAME' => 'J.',
'LAST_NAME' => 'Smith',
'BIRTH_DATE' => '1961-01-01',
'GENDER' => 'Male',
'role' => [
(int) 0 => [
'_joinData' => [
'ID' => '1',
'ROLE_ID' => '5',
'DESCRIPTION' => 'person role description'
]
]
]
]
But the update fails with following errors:
The person could not be saved. Please, try again.
Array
(
[role] => Array
(
[0] => Array
(
[NAME] => Array
(
[_required] => This field is required
)
[_joinData] => Array
(
[PERSON_ID] => Array
(
[_required] => This field is required
)
)
)
)
)
It asks to provide person_to_role.person_id which is the foreignKey (it should know current person ID), and wants a value for role.name.
Did I set my association wrong? Any help is appreciated.
UPDATE 2017-08-20
Still no go, tried all possible variations from the docs and other Internet resources. Currently I am able to pass through validation to the save action, but an INSERT query is generated instead of UPDATE and errors out on unique constraint violation.
I have person.ID and person_to_role.ID accessible:
protected $_accessible = [
'*' => true,
'ID' => true
];
My POST data looks like this:
[
'NICK_NAME' => '',
'FIRST_NAME' => 'test',
'MIDDLE_NAME' => '',
'LAST_NAME' => 'user',
'BIRTH_DATE' => '1996-10-01',
'GENDER' => 'Male',
'role' => [
(int) 0 => [
'_joinData' => [
'ID' => '153',
'DESCRIPTION' => 'test edited text'
],
'ID' => '2'
]
]
]
I tried both, with and without person_to_role record ID in _joinData, same result:
INSERT INTO person_to_role (PERSON_ID, ROLE_ID, DESCRIPTION)
VALUES (129, 2, 'test edited text')
While trying different methods, including using 'through' association, I had the following lines added to my PersonToRoleTable.phpmodel:
$this->belongsTo('Person');
$this->belongsTo('Role');
After commenting these out, everything worked as expected, I am able to save updates as well as add new and delete existing records in the join table.

CakePHP - $this->data disappears before Model::save

I have a page for editing records of the Venue model in my app. This page was working at some stage, but is now broken.
in the controller action, debugging $this->data gives the expected array of form values. However, in the Venue model, debugging $this->data in beforeSave gives only the values for fields from a related (HABTM) model, Category:
app/models/venue.php (line 89)
Array
(
[Category] => Array
(
[Category] => Array
(
[0] => 1
[1] => 2
[2] => 8
)
)
)
What could be happening to this data between the form being submitted to the controller action, and the call to beforeSave? Where should I be looking to debug this?
THanks
Edit - here's what's in $this->data in the controller (actual data changed to remove phone numbers, addresses etc).
app/controllers/venues_controller.php (line 63)
Array
(
[Venue] => Array
(
[id] => 19
[city_id] => 1
[user_id] => 130
[name] => Acme Zoo
[email] => events#acmezoo.org.uk
[description] =>
Some text...
[blurb] => Truncated description...
[contact_id] =>
[address_1] => Acme Zoo
[address_2] => Some Road
[postcode] => PP9 4DD
[telephone] => 010101010101
[website] =>
[latitude] => 55.21222
[longtitude] => -2.111111
[featured] => 0
[active] => 1
[flagged] => 0
[smg] => 0
[smg_custom_icon] => 1
[listings] => 1
[send_email] => 0
[file] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
)
[Category] => Array
(
[Category] => Array
(
[0] => 3
[1] => 6
[2] => 10
)
)
)
And here's my code to save the data...
if (!empty($this->data)) {
if ($this->Venue->save($this->data)) {
$this->Session->setFlash('The venue has been saved','success');
$countryId = $this->Venue->City->field('country_id',array('id'=>$this->data['Venue']['city_id']));
if (!empty($this->data['Venue']['send_email'])){
$this->_emailVenue($this->Venue->id,'venue_added',$countryId);
}
$this->redirect(array('action' => 'index','city'=>$this->data['Venue']['city_id']));
} else {
$this->Session->setFlash('The venue could not be saved. Please, try again.','failure');
}
}
I think i found a solution to this but I am really unsure if this should be considered a "good" solution.
I backup the request data before the save and then restore it if it fails.
$temp = $this->request->data;
if ($this->Post->save($this->request->data)) {
}else{
$this->request->data = $temp;
}
Maybe a stupid question, but do you pass the content of controller $data to the model when you call the save() method ?
$this->Venue->save($this->data)
Are you trying to save an entry to the categories table at the same time? If so, you can use $this->Venue->saveAll($this->data) instead of save(). If you just want to save the Venue data, just pass that in to save() instead of the entire $this->data like this: $this->Venue->save($this->data['Venue']);

CakePHP HABTM relations listing

I'm have quite a problem while trying to make a list (for the admin section) of HABTM relations. Here's the deal:
permissions: id, name;
users: id, username;
permissions_users: permission_id, user_id
Permission HasAndBelongsToMany User
I want to make a listing like such:
User.id | User.username | Permission.id | Permission.name
1 | Jack | 1 | posts
1 | Jack | 2 | comments
2 | Mark | 1 | posts
3 | Kate | 3 | tags
Stuff like: $this->Permission->User->find('all'); (or the other way around) doesn't really work, because it will fetch many permissions for Jack, also the other way around it will fetch many users for the posts permission, thus making it impossible to list in the view.
What I want is to get a array like:
[0] = > array(
[User] => array([id] => 1 [username] => Jack)
[Permission] => array([id] => 1 [name] => posts)
)
[1] = > array(
[User] => array([id] => 1 [username] => Jack)
[Permission] => array([id] => 2 [name] => comments)
)
...
Any ideas?
I think you would need to use the foreach and loop through your result to reconstruct a new array like that.
$user = array('id' => '1', 'name' => 'Jack');
$data = array();
foreach($permission as $per) {
$data[] = array($user, $per['Permission'])
}

Cakephp retrieving HABTM which Conditions

I'm using cakephp and would like to display all Submissions which are part of Category 'X'
I have 4 tables with a HABTM relationship.
Users -> (haveMany) -> Submissions <-> (hasAndBelongsToMany) <-> Categories
but I would like to do so using the $this->paginate() and for each submission I would like to display the user who posted the submission.
User Table
Id | Name
-----+-------------------
1 | User 1
2 | User 2
Submission Table
Id | Name | User_id
-----+-------------------+--------------
1 | Submission 1 | 1
2 | Submission 2 | 2
Category Table
Id | Name
-----+-------------------
1 | Category 1
2 | Category 2
SubmissionCategory Table
Id | Submission_id | Category_id
-----+-------------------+-------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
I am having really trouble creating a paginate which can do this, I'm starting to think its not possible unless I'm missing something.
If I was not using cakephp this is the query I would want to do
SELECT
*
FROM
submissions_categories,
submissions,
users
WHERE
submissions_categories.category_id = 8
AND
submissions_categories.submission_id = submissions.id
AND
submissions.user_id = users.id
HABTM relationships are very unwieldy in CakePHP I find. You are going to need to set up the joins manually using the $paginate variable. Then you can pass in the optional conditions array to the paginate() function. Example:
<?php
class SubmissionsController extends AppController {
var $name = 'Submissions';
var $helpers = array('Html', 'Form');
var $paginate = array('joins' => array(
array(
'table' => 'submissions_categories',
'alias' => 'SubmissionsCategory',
'type' => 'inner',
'conditions'=> array('SubmissionsCategory.submission_id = Submission.id')
),
array(
'table' => 'categories',
'alias' => 'Category',
'type' => 'inner',
'conditions'=> array(
'Category.id = SubmissionsCategory.category_id'
)
)));
function index() {
$this->Submission->recursion = 1;
$this->set('submissions', $this->paginate(array('Category.id'=>1)));
}
}
?>

Resources