Get last inserted ID after inserting to associated table - cakephp

Employees table has a field named current_address_id. I'm adding a new address to Addresses like:
$updatedEntity = $this->patchEntity($employee, [
//some other fields
'user' => $userData,
'employees_phones' => $phonesData,
'employees_addresses' => $addressesData,
], [
'associated' => ['Users', 'EmployeesPhones', 'EmployeesAddresses']
]);
$this->save($updatedEntity);
I'm inserting the new address successfully but now I need to update Employees.current_address_id with the new address ID. How can I do this?

Table::save() returns the entity with updated ids. So store the return value in a variable and use appropriate property of the entity.

Try this one. It works for me.
$this->ModelName->save($updatedEntity);
$lastInsertedId = $updatedEntity->id;
The save method will update the entity with the last insert id as long as the entity id is not already set.

Related

Laravel update record control

I'm building a laravel application where i have a Reservation model. After the new record is created, the user may want to update it.
I'm looking for a solution to check if the UpdateRequest values are the same of the actual records and if there are updates only update the modified values.
Example, the original record has :
{'id' => 1, 'name' = 'Jhon', surname = 'Doe'}
While the UpdateRequest has
{'id' => 1, 'name' = 'Jhon', surname = 'Kirby'}
So, my questions are :
How do i check which values are different?
How do i update only the
specified values?
I've tried to look at the documentation of laravel but it doesn't seem to refer to this situation, is there any solution or should I just update all the values?
Thank you

Can an aliased query use a contain clause?

I use a union to join two datasets and then the following query to setup for pagination correctly
$paginationQuery = $this->find('all')
->contain(['EmailAddresses' => [
'foreignKey' => false,
'queryBuilder' => function($q) {
return $q->where(['Members__id' => 'EmailAddresses.member_id']);
}
]])
->select( $selectMainUnion )
->from([$this->getAlias() => $query])
->order(['Members__last_name' => 'ASC', 'Members__first_name' => 'ASC']);
I have also tried
$paginationQuery = $this->find('all')
->contain(['EmailAddresses'])
->select( $selectMainUnion )
->from([$this->getAlias() => $query])
->order(['Members__last_name' => 'ASC', 'Members__first_name' => 'ASC']);
and tried
$query->loadInto($query, ['EmailAddresses']); where $query is the result of the union.
Neither of these result in email addresses added to $paginationQuery.
Is there a way to do this?
Adding to clarify the code
$selectMain =['Members.id',
'Members.member_type',
'Members.first_name',
'Members.middle_name',
'Members.last_name',
'Members.suffix',
'Members.date_joined'];
foreach($selectMain as $select) {
$selectMainUnion[] = str_replace('.', '__', $select);
}
$this->hasMany('EmailAddresses', [
'foreignKey' => 'member_id',
'dependent' => true,
]);
Looking at the SQL in DebugKit SQL Log, there is no reference to the EmailAddresses table.
Generally containments do work fine irrespective of the queries FROM clause, whether that's a table or a subquery should be irrelevant. The requirement for this to work however is that the required primary and/or foreign key fields are being selected, and that they are in the correct format.
By default CakePHP's ORM queries automatically alias selected fields, ie they are being selected like Alias.field AS Alias__field. So when Alias is a subquery, then Alias.field doesn't exist, you'd have to select Alias.Alias__field instead. So with the automatic aliases, your select of Members__id would be transformed to Members.Members__id AS Members__Members__id, and Members__Members__id is not something the ORM understands, it would end up as Members__id in your entities, where the eager loader would expect id instead, ie the name of the primary key which is used to inject the results of the queried hasMany associated records (this happens in a separate query), your custom queryBuilder won't help with that, as the injecting happens afterwards on PHP level.
Long story short, to fix the problem, you can either change how the fields of the union queries are selected, ie ensure that they are not selected with aliases, that way the pagination query fields do not need to be changed at all:
$fields = $table->getSchema()->columns();
$fields = array_combine($fields, $fields);
$query->select($fields);
This will create a list of fields in the format of ['id' => 'id', ...], looks a bit whacky, but it works (as long as there's no ambiguity because of joined tables for example), the SQL would be like id AS id, so your pagination query can then simply reference the fields like Members.id.
Another way would be to select the aliases of the subquery, ie not just select Member__id, which the ORM turns into Member__Member__id when it applies automatic aliasing, but use Members.Member__id, like:
[
'Member__id' => 'Members.Member__id',
// ...
]
That way no automatic aliasing takes place, on SQL level it would select the field like Members.Member__id AS Member__id, and the field would end up as id in your entities, which the eager loader would find and could use for injecting the associated records.

Delete record in patchentities in cakephp 3

Some rows which are related to employee are needed to be updated
User can update some record and delete some record in same form.
while doing patch entity list of records which is already present in table are fetched and stored in list object and it is patched with data which comes by request.
But only records are updated not deleted while doing patch entity.
$UserSkillsTable = \Cake\ORM\TableRegistry::get('UserSkills');
$list = $this->UserSkills
->find('ALL')
->contain(['MsSkills', 'MsSkills.MsSkillHeads', 'SkillLevels', 'RoSkillLevels'])
->where([
'UserSkills.emp_code' => $this->request->session()->read('user_emp_code'),
'approve_status' => 'P',
'UserSkills.is_active' => '1'
])
->toArray();
$userSkillEntities = $this->UserSkills->patchEntities(
$list,
$this->request->data['old_user_skill']
);

CakePHP: Save data in two models

In CakePHP I have two models: Clients & Tickets. A client can have many tickets and a ticket can only have 1 client.
When adding a new ticket I want to automatically create a new client by only entering a name. So the form would be:
Name = "Name client" >> Name should be save in Client table en new client_ID in Ticket table
Info = Ticket information >> Save in Ticket table.
"Save"
I'm not sure how this works. I have associations in the model and tried to saveAll but there is no data stored in the Client table. And how do I get the ID in the Ticket table?
Hope someone can point me in the right direction. I've searched for other answers but cant seem to find a solution. Is saveAll the right way to do this?
You should set a php condition before insert values into the table, the sql request 4 exemple return the numbers of repetition of the same ticket_id so if the returned value is greater than 1 the request can't execute else the request insert the values
The function to count number of rows : mysql_num_rows('request');
You can use the callback methods.
If you have defined your relation in the Ticket model with belongsTo Client, it will be accessible from that model.
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'client_id',
),
);
So, if you want to make a new client before saving the ticket, you can do:
public function beforeSave ($options = array()) {
$this->data['Client']['name'] = $someVar;
$this->Client->save($this->data);
$this->data[$this->alias]['client_id'] = $this->Client->getInsertID();
return true;
}

cakephp not saving update value to related table, but no errors

Update order function finds all orderlines of current order.
Loops through subtracting quantity ordered from stock level and holding new stock level value in $newstock. All good.
But won't save.
Echoes "success" and the correct value but the database is not updated.
The Order status field does update, with the same code syntax.
It also has the same relationships with the Orderline. (Function called from Orderline Controller)
The table relationships are:
'Product'hasMany = array('Orderline');
'Order' hasMany = array('Orderline');
'Orderline' belongsTo = array('Order', 'Product');
function updateOrder(){
$this->data['Order']['id'] = $this->getOrderid();
$orderproducts = $this->Orderline->find('all',array('conditions' =>
array('Orderline.order_id' => $this->data['Order']['id'])));
foreach($orderproducts as $orderproduct){
$newstock = $orderproduct['Product']['stock']-$orderproduct['Orderline']['quantity'];
$this->data['Product']['stock']= $newstock;
if( $this->Product->saveAll($this->data)){
echo "success" ;
}else{
echo "not saved";
}
}
$this->data['Order']['status']= 1;
$this->Order->saveall($this->data);
}
I want to add that I was running into silent save fails using saveAll because I hadn't cleared the APP/tmp/cache folder.
Solved.
It had actually been adding new rows to the Product table.
This line was missing from the insert in the foreach loop, reminding it to use the current Product id to know where to insert the new data.
$this->data['Product']['id']= $orderproduct['Product']['id'];

Resources