How to use sync() with additional pivot fields [Laravel 5] [duplicate] - php

This question already has answers here:
Laravel 5: syncing an extra field via pivot
(2 answers)
Closed 7 years ago.
Here is my code:
public function updateGroupIntoDatabase(){
$group_id = 6;
$group = Group::find($group_id);
$group -> name = Input::get('groups');
$projectsIds = Input::get('projects');
$userIds = array_merge(Input::get('clients'),Input::get('workers'));
array_push($userIds, Auth::id());
$adminId = Auth::id();
if($group -> save()){
foreach($userIds as $userId){
$name = User::find($userId);
$group -> projects() -> sync($projectsIds,array('admin_id' => $adminId, 'user_id' => $userId,'user_name' => $name -> name));
}
when I execute this I get like this:
id project_id group_id admin_id user_id user_name
1 4 6 0 0
But it should for each user_id create new record... When I use attach method It works find but when I use sync it create just one record with additional pivot fields filds 0. Any solution for this?

When using sync with pivot data:
$group->projects()->sync( array(
1 => array( 'admin_id' => $adminId, 'user_id' => $userId ),
2 => array( 'admin_id' => $adminId, 'user_id' => $userId ),
...
));

Related

Bulk insert or update for the given where

I have a function that gets $homes and $member_id as parameters. $homes is an array, $member_id is an integer.
$homes = array( 'home13', 'home21', 'home34', 'home44' );
$member_id = 5;
How do I insert/update into the following DB?
in the format:
id home_name member_id
1 home13 5
2 home21 5
2 home34 5
2 home44 5
The function I used:
public function store($homes, $member_id) {
foreach( $homes as $home ) {
$data[] = [ 'member_id' => $member_id, 'home_name' => $home ];
}
Home::insert( $data );
}
which works fine while inserting. However, I need to update all records for a given $member_id if the member_id already exists.
For example, if the $member_id is 5 and $homes is now array( 'home54' ), all other home_name that are previously stored for the $member_id 5 should be deleted. so that the following would only remain.
id home_name member_id
1 home54 5
You can use Laravel's upsert() method
Example:
Home::upsert([
['home_name' => 'home54', 'member_id' => 5, 'id' => 1],
['home_name' => 'home13', 'member_id' => 5, 'id' => 2],
['home_name' => 'home21', 'member_id' => 5, 'id' => 3],
], ['member_id', 'id'], ['home_name']);
This method consists of three arguments.
Values to insert/update
Columns that uniquely identify the values
The values that need to be updated
Please note that you need to use a unique composite key to use upsert() method.
Example from Seeder class:
$table->unique(['member_id','id']);
Reference from Laravel docs: https://laravel.com/docs/9.x/eloquent#upserts
You can use updateOrCreate method to achieve this
public function store($homes, $member_id) {
foreach( $homes as $home ) {
Home::updateOrCreate( 'member_id' => $member_id, 'home_name' => $home );
}
}

How I get data by group User ID for foreach controller function in Laravel

How can I get data by grouping user_id for a foreach loop in a controller's function in Laravel. For example, user_id = 2, 5 rows available, user_id = 1, 10 rows available. Then show 2 arrays.
$lists = lists::wherestatus(1)->groupby('user_id')->get();
foreach($lists as $list){
$list = functionHere;
}
What function can I create for this on the controller for grouping?
I need more information, but based on what you shared, you should be able to do this (removing the foreach):
$lists = Lists::whereStatus(1)->get()->groupBy('user_id');
The difference is that if you use groupBy before get, you are grouping your query by user_id, so instead of getting 5 rows for user_id = 2 and 10 for user_id = 1, you are going to get 2 rows and just the latest data, so you need to use Collection's groupBy.
What you want to do is group all the information by user_id but have each row, a schema like this:
[
'1' => [ // user_id
['user_id' => '1', 'column1' => 'random value'],
['user_id' => '1', 'column1' => 'other value'],
// 8 remaining rows
],
'2' => [ // user_id
['user_id' => '2', 'column1' => 'other nice value'],
// 4 remaining rows
],
]
you should first in List model set:
public function scopeStatus(){
return $this->where('status','1');
}
and in your controller:
$products = List::status()->groupby('user_id')->get();

Laravel, sync data with Pivot

Laravel 5.3, I have this 2 models:
User:
public function newFunctions()
{
return $this
->belongsToMany('App\NewFunctions', 'user_newfunctions')
->withPivot(['function_count', 'days_count']);
}
NewFunctions:
public function users()
{
return $this
->belongsToMany('App\User', 'user_newfunctions', 'new_function_id', 'user_id')
->withPivot(['function_count', 'days_count']);
}
I now how can I save new data to User, with this:
$user = User::findOrFail($id);
$user->name = $request->input('name');
$user->save();
But now I have to update some values of a pivot table. the pivot table is this:
user_id | new_functions_id | function_count | days_count
---------------------------------------------------------
814 | 1 | 5 |2019-07-19 12:26:19
814 | 3 | 7 |2019-07-19 12:26:19
I have more than 1 row per user_id. I was trying to use:
$user
->newFunctions()
->sync([
'days_count' => $test_date,
'function_count' => $test_int_number
]);
But I'm getting error like:
Ilegal offset type
because is trying to update with this:
array(
'records' => array(
'days_count' => object(Carbon), 'function_count' => '66'),
'results' => array(),
'id' => object(Carbon),
'attributes' => array()
)
)
in BelongsToMany.php
So:
How could I update the values for each user_id on the pivot table?
And how should use syncto update just 'function_count' and 'days_count'? they come from request.
->sync() isn't used like that; it's used to attach() and detach() related new_function_ids until only the ids in sync() are present. You're probably looking for updateExistingPivot()
An example of ->sync() would be using the array:
$user->newFunctions()->sync([
"new_function_id" => 1,
"function_count" => 6,
"days_count" => "2019-07-08 12:00:00",
]);
This would remove the record where new_function_id is 3, and updating the values where new_function_id is 1.
To update function_count and days_count for either new_function_id of 1 or 3, use ->updateExistingPivot() (pass the id you want to update as the first parameter):
$user
->newFunctions()
->updateExistingPivot("1", [
"function_count" => 6,
"days_count" = "2019-07-08 12:00:00"
]);
// or $user->newFunctions()->updateExistingPivot("3", ...);
This will update the pivot table where new_function_id is 1, while leaving the row where new_function_id is 3.
Edit: If you're looking to update all existing records in the pivot table, you'll need to do this in a loop, call a sync with all current records in a single array, or run a manual query.

Using subquery for update in Yii2 ActiveRecord

Is it possible to use subquery when updating an ActiveRecord?
I have a products table with following columns
id number_of_orders
1 3
2 3
3 2
and an items table
id product_id
1 1
2 1
3 1
4 2
5 2
6 2
7 3
8 3
What I want is
UPDATE products
SET number_of_orders = (
SELECT COUNT(id) FROM items WHERE product_id = 1
)
WHERE id = 1
I have tried
$subquery = ItemsModel::find()
->select('COUNT(id)')
->where(['product_id' => 1]);
ProductsModel::updateAll(
[
'number_of_orders' => $subquery
],
[
'id' => 1
]
);
and
$product = ProductsModel::findOne(1);
$product->number_of_orders = $subquery;
$product->save();
but none of this going to work.
Does anyone have any idea about solving this problem?
Conclusion:
Each of the two ways works very well after I updated to yii 2.0.14.
Try update Yii to the last version. Since 2.0.14 all instances of yii\db\ExpressionInterface (including Query and ActiveQuery) should be handled properly and generate SQL in similar way as yii\db\Expression. So all this should work in Yii 2.0.14 or later:
$subquery = ItemsModel::find()
->select('COUNT(id)')
->where(['product_id' => 1])
ProductsModel::updateAll(
['number_of_orders' => $subquery],
['id' => 1]
);
$product = ProductsModel::findOne(1);
$product->number_of_orders = $subquery;
$product->save();
ProductsModel::updateAll(
['number_of_orders' => new Expression('SELECT COUNT(id) FROM items WHERE product_id = 1')],
['id' => 1]
);
Last example should work also in earlier versions of Yii.
You can use count() to get number of records.
$itemCount = ItemsModel::find()
->where(['product_id' => 1]);
->count();
$product = ProductsModel::findOne(1);
$product->number_of_orders = $itemCount;
$product->save();
i would prefer:
$model = ProductsModel::findOne(1);
$model->updateAttributes(['number_of_orders' => ItemsModel::find()->where(['product_id' => 1])->count()]);
or you can do
$query = Yii::$app->db
->createCommand(sprintf('UPDATE %s SET number_of_orders=(SELECT COUNT(*) FROM %s WHERE product_id=:id) WHERE id=:id', ProductsModel::tableName(), ItemsModel::tableName()), [':id' => $id, ])
->execute();
ps: if both tables are the same, you have to do:
$query = Yii::$app->db
->createCommand(sprintf('UPDATE %s SET number_of_orders=(SELECT * FROM (SELECT COUNT(*) FROM %s WHERE product_id=:id) xxx) WHERE id=:id', ProductsModel::tableName(), ItemsModel::tableName()), [':id' => $id, ])
->execute();

How to attach different value for additional field in pivot table Laravel 5

I have project_group pivot table with this fields: id, group_id, project_id, admin_id, user_id
This I use to attach group and projects together:
$group -> projects() -> attach($projects,array('admin_id' => Auth::user()->id));
Is it possible to for every record in that pivot table add diffirent user_id.
For example:
First record:
id = 1, group_id = 1 project_id = 2 admin_id = 1 user_id = 1
Second record:
id = 2, group_id = 1 project_id = 3 admin_id = 1 user_id = 1
3th record:
id = 3, group_id = 1 project_id = 2 admin_id = 1 user_id = 2
4th record:
id = 3, group_id = 1 project_id = 3 admin_id = 1 user_id = 2
Basicly if I select 2 projects from projects html list and 2 users from html users list I need to get result like in example above...
Sure, like this:
$projects = [
2 => ['admin_id' => 1, 'user_id' => 1],
3 => ['admin_id' => 1, 'user_id' => 2],
// and so on
];
$group->projects()->attach($projects);
And if I understood your problem right, you can build such an array like this:
$projectsIds = [2,3];
$userIds = [1,2];
$projects = [];
$adminId = Auth::id();
foreach($userIds as $userId){
$projects += array_fill_keys($projectIds, [
'admin_id' => $adminId,
'user_id' => $userId
]);
}
$group->projects()->attach($projects);
Here is one solution, if someone has better way please put here...
$projectsIds = [11,33];
$userIds = [1,2,4];
$adminId = Auth::id();
if($group -> save()){
foreach($userIds as $userId){
$group -> projects() -> attach($projectsIds,array('admin_id' => $adminId, 'user_id' => $userId));
}

Categories