How can i UPDATE all records using associative array? - php

I have this table that contains my site settings:
I would want to update all records at once with data that comes from a form.
The data looks like this:
$data = [
"brand" => "bbb"
"mail" => "kontakt#aaa.pl"
"phone" => "111"
"site-name" => "test"
];
Now I would like to update that with key of the associative array and with it value.
I tried:
DB::table('settings')->update($data);
But there is an error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'brand' in 'field list' (SQL: update `settings` set `brand` = bbb, `mail` = kontakt#aaa.pl, `phone` = 111, `site-name` = test)
Obviously it thinks that brand is a column name.
So I transformed the $data to this array:
$data = [
0 => [
"name" => "brand"
"value" => "bbb"
]
1 => [
"name" => "mail"
"value" => "kontakt#aaa.pl"
]
2 => [
"name" => "phone"
"value" => "111"
]
3 => [
"name" => "site-name"
"value" => "test"
]
];
and now the error is:
SQLSTATE[42S22]: Column not found: 1054 Unknown column '0' in 'field list' (SQL: update `settings` set `0` = {"name":"brand","value":"bbb"}, `1` = {"name":"mail","value":"kontakt#aaa.pl"}, `2` = {"name":"phone","value":"111"}, `3` = {"name":"site-name","value":"test"})
So now it thinks that index of each row in array is column name and at this place i have no idea how to do this...
Can anyone help me please?

I came to this solution although i think it looks ugly and there should be a better way to do this, if no better answers will be given i will mark my answer as correct
$data = [
"brand" => "bbb"
"mail" => "kontakt#aaa.pl"
"phone" => "111"
"site-name" => "test"
];
foreach($data as $key=>$d) {
DB::table('settings')->where('name','=',$key)->update(['value' => $d]);
}

Your table looks something like you can only take a set of data and update it with time. Why because there are no foreign key relations.
if that is the case then why not have brand_name, mail, phone and site_name for settings columns,
Your migrations
public function up()
{
Schema::create('settings', function (Blueprint $table) {
$table->string('brand_name');
$table->string('mail');
$table->string('phone');
$table->string('site_name');
$table->timestamps();
});
}
In your model?
protected $fillable = ['brand_name', 'mail', 'phone', 'site_name'];
or
protected $guarded = [];
In your controller
public function method(Request $request)
{
// You can also abstract this in to a custom request class
$request->validate([
'brand_name' => 'required',
'mail' => 'required',
'phone' => 'required',
'site_name' => 'required',
]);
// Add data if record doesn't exist, update when it does
// To use the validated method on request all needed fields must be required
Settings::updateOrCreate($request->validated())
}
Should in case I was wrong you can still check out Laravel Mass Update
https://laravel.com/docs/8.x/eloquent#mass-updates
Laravel Upserts
https://laravel.com/docs/8.x/eloquent#upserts

You can use upsert to update multiple records
First transform data to add column name using collection
$data=collect($data)->transform(function ($value,$name){
return ["name"=>$name,"value"=>$value];
})->values()->toArray();
and here i used model
Setting::upsert($data,["name"],["value"]);
To understand Upserts
Upsert perform multiple "upserts" in a single query
first argument consists of the values to insert or update
second argument lists the column(s) that uniquely identify records within the associated table.
third and final argument is an array of the columns that should be updated if a matching record already exists in the database.
Also important point
All databases systems except SQL Server require the columns in the
second argument provided to the upsert method to have a "primary" or
"unique" index.
It means in your mysql table settings column name to be unique index or else it will insert as new row
Ref:https://laravel.com/docs/8.x/eloquent#upserts

Related

Laravel updateOrCreate with hasMany relationship

I have users that can have multiple parameters. These are called for example user_param_1, user_param_2, ..., user_param_n. This is dynamic. It is a separate table user_parameters, which stores id, user_id, name and value. The relationship is a belongsTo and hasMany between Users and UserParameters. The problem is:
When editing, I want to keep it dynamically and if the user has an user_param_n+1, it should be created. But I already have problems to write the condition for the existing parameters.
I create myself an userParameters array, which contains from the $request variable only the necessary parameters. The array looks like this:
[
0 => [
"name" => "par1"
"value" => "var1"
]
1 => [
"name" => "par2"
"value" => "var2"
]
2 => [
"name" => "par3"
"value" => "var3"
]
]
Then I want to save it. My controller knows the user, so I can access to $user->id.
foreach ($userParameters as $userParameter) {
$user->parameters()->updateOrCreate(['id' => $user->parameters->id, 'user_id' => $user->id], $userParameter);
}
The issue is, that $user->parameters is an array of eloquent models. The condition is wrong. I can't access id directly. But how I can solve it? I need something like "['id' => [IF-DATABASE-ID-EXISTS-IN-ARRAY-$user-parameters]"... but how in an eloquent way?
Thanks in advance!
Best regards
I think you need to get the existing parameter using user_id and parameter_name cuz it's the uniqueness of that parameter row, if there is no parameter with this name it will create it with user_id & parameter_name and parameter_value passed to updateOrCreate function
foreach ($parameters_from_request as $parameter) {
$user->parameters()
->updateOrCreate(
[
'name' => $parameter['name'] ,
'user_id' => $user->id
],[
'name' => $parameter['name'],
'value'=> $parameter['value']
]);
}

Inserting with relationships in laravel

I am facing a problem in Laravel 5.3 that I looked the docs and also searched web but didn't find anything on it.
I am using Laravel Relationships to join two tables. Now I want the data to be inserted on both the tables at the same time after the user submits a form. The catch in this is the first table is the primary one say "users" and second one "xyz" belongsTo the first table. The table "xyz" contains "users_id" column that connects both the tables. And obviously "users_id" is the "id" column of "users" table.
Now the problem arriving is that I want to insert the data in "users" table (that is easily done) and "xyz" table at the same time. The User::create() function will create the user data easily and it is working also but for inserting the data in "xyz" table I will be needing the "user_id" column data and ID will not be generated until the user is created as ID column has Auto-Increment attribute activated.
Code:
$user = new User;
$inputArry = array('data1' => $request['field1'],
'data2' => $request['field2'],
'data3' => $request['field3'],
);
$user->create($inputArry);
$user->xyz()->create([
'user_id' => $user->id,
'name' => $request['name'],
'about' => $request['desc'],
'tag' => $request['tag'],
]);
Above is the code that I am using for this purpose but it is giving me a error.
Error:
QueryException in Connection.php line 761:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'soft_id' cannot be null (SQL: insert into `xyz` (`user_id`, `name`, `about`, `tag`, `updated_at`, `created_at`) values (, John, I am John, dev, 2016-11-09 21:01:29, 2016-11-09 21:01:29))
One way of inserting related table is using relations as:
$user = User::create($user_inputs);
$xyz = $user->xyz()->create($xyz_inputs);
It will automatically fills the user_id in the xyz table.
If you need insert many items, use createMany or saveMany method.
For example:
$post = App\Post::find(1);
$post->comments()->createMany([
[
'message' => 'A new comment.',
],
[
'message' => 'Another new comment.',
],
]);
In the offical laravel docs:
https://laravel.com/docs/5.6/eloquent-relationships#inserting-and-updating-related-models
You can create them like this instead of saving them on same time...
$id = User::create($input_arr)->id;
Xyz::create([
'user_id' => $id,
...
]);

use laravel Eloquent's updateOrCreate

i want to insert a new record if doesn't exist and update it if exists, i came across a method updateOrCreate, but im having hard time implementing it
$list = mList::updateOrCreate(
[
['user_id' => 162, 'movie_id' => 862]
],
[ 'tag' => 'watched'] //this data should be updated if the above got match
);
but im getting the following query exception
SQLSTATE[42S22]: Column not found: 1054 Unknown column '162' in 'where clause' (SQL: select * from lists where (162 = 862) limit 1)
it should look for a column called user_id not 162
ps: im doing this with two conditions where(user_id = 162 and movie_id =862)
but when i do it with a single condition it works surprisingly.
if there is any other eloquent method can do the same please refer to me ..
Try using [ ] insead of [ [ ] ], like:
$list = mList::updateOrCreate([
'user_id' => 162,
'movie_id' => 862
], [
'tag' => 'watched'
]);

Cake ORM QueryBuilder is selecting data from joined table differently [duplicate]

WHen i try to do :
$fields = array('id' => 'custom_id', 'title' => 'some_name');
The result I get has id as a string.
If I do:
$fields = array('custom_id', 'title' => 'some_name');
then it gives custom_id as integer.
How can I obtain custom_id as id without loosing the data type. I read the documentation but didn't found much help.
There is something that virtual fields can do I think. But is it possible inside the find query without the use of virtual fields etc?
Thanks in Advance
As of CakePHP 3.2
you can use Query::selectTypeMap() to add further types, which are only going to be used for casting the selected fields when data is being retrieved.
$query = $table
->find()
->select(['alias' => 'actual_field', /* ... */]);
$query
->selectTypeMap()
->addDefaults([
'alias' => 'integer'
]);
You can use any of the built-in data types, as well as custom ones. In this case the alias field will now be casted as an integer.
See also
API > \Cake\Database\Query::selectTypeMap()
Cookbook > Database Access & ORM > Database Basics > Data Types
Cookbook > Database Access & ORM > Database Basics > Adding Custom Types
With CakePHP 3.1 and earlier
you'll have to use Query::typeMap(), which will not only affect the selected field when data is being retrieved, but in various other places too where data needs to be casted according to the field types, which might cause unwanted collisions, so use this with care.
$query
->typeMap()
->addDefaults([
'alias' => 'integer'
]);
See also
API > \Cake\Database\Query::typeMap()
Change the type of existing columns
Changing the type of an existing column of a table is possible too, however they need to be set using a specific syntax, ie in the column alias format used by CakePHP, that is, the table alias and the column name seprated by __, eg, for a table with the Articles alias and a column named id, it would be Articles__id.
This can be either set manually, or better yet retrieved via Query::aliasField(), like:
// $field will look like ['Alias__id' => 'Alias.id']
$field = $query->aliasField('id', $table->alias());
$query
->selectTypeMap()
->addDefaults([
key($field) => 'string'
]);
This would change the the default type of the id column to string.
See also
API > \Cake\Datasource\QueryInterface::aliasField()
Hi my alternative example full, user schema() in controller Users add type column aliasFiels by join data:
$this->Users->schema()
->addColumn('is_licensed', [
'type' => 'boolean',
])
->addColumn('total_of_licenses', [
'type' => 'integer',
]);
$fields = [
'Users.id',
'Users.username',
'Users.first_name',
'Users.last_name',
'Users.active',
'Users__is_licensed' => 'if(count(LicenseesUsers.id)>=1,true,false)',
'Users__total_of_licenses' => 'count(LicenseesUsers.id)',
'Users.created',
'Users.modified',
'Languages.id',
'Languages.name',
'Countries.id',
'Countries.name',
'UserRoles.id',
'UserRoles.name',
];
$where = [
'contain' => ['UserRoles', 'Countries', 'Languages'],
'fields' => $fields,
'join' => [
'LicenseesUsers' => [
'table' => 'licensees_users',
'type' => 'LEFT',
'conditions' => [
'Users.id = LicenseesUsers.users_id'
],
],
],
'group' => 'Users.id'
];
// Set pagination
$this->paginate = $where;
// Get data in array
$users = $this->paginate($this->Users)->toArray();

Laravel: extra field sync with array

Im trying to save data inside a pivot table with an extra field called data.
when i save i have this array:
[
5 => "files"
4 => "pictures"
3 => "tags"
1 => "thumbs"
]
My table looks like this:
project_id
option_id
name
The ids shown above refer to option_id and the string to name inside the database.
When i try to use sync like this: $project->options()->sync($data);
$data is the array shown above
Im getting a error thats its trying to save the option_id with "files".
Here is how i build up the data that i use for sync:
Im trying to get what you suggested but dont know how to achieve it:
here is how i build up the array:
foreach($request->input('option_id') as $id) {
$option['option_id'][] = $id;
$option['data'][] = $request->input('data')[$id];
}
$data = array_combine($option['option_id'], $option['data']);
This is covered in the manual:
Adding Pivot Data When Syncing
You may also associate other pivot table values with the given IDs:
$user->roles()->sync(array(1 => array('expires' => true)));
In your example, you would have to change your array to look something like below but I believe this would translate to:
$data = [
5 => [ 'name' => "files" ],
4 => [ 'name' => "pictures" ],
3 => [ 'name' => "tags" ],
1 => [ 'name' => "thumbs" ],
];
$project->options()->sync($data);
I believe you may also need to modify how your Project model relates itself to your Options model:
// File: app/model/Project.php
public function options()
{
return $this->belongsToMany('Option')->withPivot('name');
}
This is also noted in the linked-to manual page:
By default, only the keys will be present on the pivot object. If your pivot table contains extra attributes, you must specify them when defining the relationship.
Update
Try creating your $data array like this:
$data = [];
foreach($request->input('option_id') as $id) {
$data[$id] = [ 'name' => $request->input('data')[$id] ];
}

Categories