laravel seeder array to string conversion - laravel

I have a model factory like this
$factory->define(App\Sale::class, function (Faker\Generator $faker) {
return [
'unit' => $faker->randomDigit,
'street_no' => $faker->randomDigit,
'street_name' => $faker->streetName,
'street_type' => $faker->streetSuffix,
'suburb' => $faker->randomElements(['Melton South','Melton West','Rye']),
'postcode' => $faker->numberBetween($min=1000, $max=4000),
'sale_date' => $faker->dateTimeThisYear,
];
});
Database seeder runs it
factory(App\Sale::class, 5)->create();
The problem is when i run it php artisan db:seed I'm getting the error
[Illuminate\Database\QueryException]
Array to string conversion (SQL: insert into `sales` (`unit`, `street_no`,
`street_name`, `street_type`, `suburb`, `postcode`, `sale_date`,
`updated_at`, `created_at`)
values (7, 1, Labadie Centers, Bridge, Rye, 3758, 2016-08-12 1
5:02:07, 2017-05-23 13:16:56, 2017-05-23 13:16:56))
The error sql doesnt show any arrays that i can see.
When i pasted that sql into my db app and ran it, in order to make it work i had to quote all the strings, but laravel docs dont say anything about that when using faker ?
Am I missing something in the model factory ?
exi

Try to change
'suburb' => $faker->randomElements(['Melton South','Melton West','Rye']),
to
'suburb' => $faker->randomElement(['Melton South','Melton West','Rye']),
Note 's' on Elements

Related

Laravel Scheduled Job using updateOrCreate method

I am trying to make a scheduled job that will take data from a table in one database and insert it into a table on another database. The job will run every minute, so I need to check for duplicates and insert only the new data.
This is what I have in my Job:
$db_maintenance_old = DB::connection('maintenance_old');
$getMaintenanceMachines = $db_maintenance_old->table('machines')->get();
foreach ($getMaintenanceMachines as $key => $value) {
MaintenanceMachine::updateOrCreate([
'machine_name' => $value->Code,
'external_id' => $value->MachnineID,
],[
'machine_name' => $value->Code,
'external_id' => $value->MachnineID,
'machine_status' => 1,
'created_at' => date('Y-m-d H:i:s'),
]);
}
With php artisan schedule:run I get this error:
BadMethodCallException : Call to undefined method Illuminate\Database\Query\Builder::updateOrCreate()
I think I am using the updateOrCreate Method right, or maybe not. I have no clue what I am doing wrong.

How do I get a value of another table on Laravel?

I'm trying to get just value of id column on a table but it returns
SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '[{"id":1}]' for column 'id_jenis' at row 1 (SQL: insert into `pesanan` (`name`, `telpon`, `alamat`, `id_jenis`, `jenis`, `do`, `updated_at`, `created_at`) values (Pradita Candrani, 0813, Jalan Sunan Ampel Kasin, [{"id":1}], Cuci Basah Standar, None, 2019-11-27 12:18:35, 2019-11-27 12:18:35))
Here it is my code on Controller
public function pesan(Request $request){
$harga = Harga::select('id')->where('nama',$request->jenis)->get();
Pesanan::create([
'name' => $request->nama,
'telpon' => $request->telpon,
'alamat' => $request->alamat,
'id_jenis' => $harga,
'jenis' => $request->jenis,
'do'=>$request->do
]);
return redirect('/pesanan');
}
how can I fix this? Please help
You're getting object now and passing it to id_jenis directly. use first() instead of get(). and pass the $harga->id in id_jenis.
$harga = Harga::select('id')->where('nama',$request->jenis)->first();
Pesanan::create([
'name' => $request->nama,
'telpon' => $request->telpon,
'alamat' => $request->alamat,
'id_jenis' => $harga->id,
'jenis' => $request->jenis,
'do'=>$request->do
]);
If you want to store multiple ids in id_jenis then use pluck.
$harga = Harga::where('nama',$request->jenis)->pluck('id')->toArray();
Here you'll get multiple ids in array. so use json_encode to store JSON in db as below.
Pesanan::create([
'name' => $request->nama,
'telpon' => $request->telpon,
'alamat' => $request->alamat,
'id_jenis' => json_encode($harga),
'jenis' => $request->jenis,
'do'=>$request->do
]);
$harga = Harga::select('id')->where('nama',$request->jenis)->get();
After this line, write
\Log::info(['Harga', $harga]);
and check the latest file and error in /storage/logs/laravel.log
Welcome to the wonderful world of debugging

Laravel Insert Seed if data doesn't already exist

Is there any way to run a laravel seed to only insert the records if they do not exist already?
My current laravel seeder looks like this
DB::table('users')->insert([
//Global Admin
[
'member_id' => 11111111,
'firstname' => 'Joe',
'lastname' => 'Bloggs'
],
[
'member_id' => 22222222,
'firstname' => 'Jim',
'lastname' => 'Bloggs'
],
]);
Pretty standard!
would I have to wrap each and every insert in a try catch? like this
try {
DB::table('users')->insert(['member_id' => 11111111, 'firstname' => 'Joe', 'lastname' => 'Bloggs']);
} catch(Exception $e){
//Die silently
}
try {
DB::table('users')->insert(['member_id' => 22222222, 'firstname' => 'Jim', 'lastname' => 'Bloggs']);
} catch(Exception $e){
//Die silently
}
Later on I might want to add extra rows to the same seeder without having to write a new one, and re run php artisan db:seed to only add my new rows.
Is this possible?
You can achieve this by Eloquent firstOrCreate.
The firstOrCreate method will attempt to locate a database record
using the given column / value pairs. If the model can not be found in
the database, a record will be inserted with the attributes from the
first parameter, along with those in the optional second parameter.
So, if you identify the user by member_id, you can do something like this:
User::firstOrCreate(
['member_id' => 11111111],
[
'firstname' => 'anakin',
'lastname' => 'skywalker',
'password' => Hash::make('4nak1n')
]
);
If you want to locate the record by 'member_id', 'firstname' and 'lastname' fields, something like this:
User::firstOrCreate(
[
'member_id' => 11111111,
'firstname' => 'anakin',
'lastname' => 'skywalker'
],
[
'password' => Hash::make('4nak1n'),
]
);
As stokoe0990 stated, it is not advisable to run seeders in production. The Laravel Seeder was written as way to generate test data. Per the documentation "Laravel includes a simple method of seeding your database with test data using seed classes".
That said, The only way you can satisfy your question is to build the logic into your seed:
$users = array(
['member_id' => 11111111,'firstname' => 'Joe','lastname' => 'Bloggs'],
['member_id' => 22222222,'firstname' => 'Jim','lastname' => 'Bloggs']
);
foreach ($users as $user) {
if (\App\User::find($user['id'])) {
DB::table('users')->insert($user);
}
}
Seeding is only supposed to be used for testing, anyways.
Why don't you just execute php artisan migrate:fresh --seed?
This will refresh your database (deletes the tables) then runs all your migrations again and finally seeds the database again.
You should never be using seeders in production.
Just add the new data to your seeder, run migrate:fresh and re-seed :)
You can achieve that by using Eloquent updateOrInsert() method:
DB::table('users')->updateOrInsert('your_data');
Read more about it here.
The best I recommend is to truncate (or delete all) the data in the table anytime you migrate. Try something like this:
//data in the table
DB::table('users')->delete(); //or use model like this: User::truncate();
DB::table('users')->insert([
//Global Admin
[
'member_id' => 11111111,
'firstname' => 'Joe',
'lastname' => 'Bloggs'
],
[
'member_id' => 22222222,
'firstname' => 'Jim',
'lastname' => 'Bloggs'
],
]);
Then there will be no duplications when you run php artisan db:seed

Laravel relationship with method "with" returns null

Today I wanted to do some clean code so just started selecting columns for with relationship. With this code:
\App\Genre::with([
'family'
])->where([
'slug' => $slug,
'is_active' => true
])->first();
everything is working fine. But when I start selecting columns for "with" method:
\App\Genre::with([
'family' => function ($query) {
$query->select('name_pl', 'name_lat');
}])->where([
'slug' => $slug,
'is_active' => true
])->first();
I got that family is null (but it should be an object with columns: name_pl, name_lat). What I am doing wrong?
family method in Genre class looks like this:
public function family () {
return $this->belongsTo(Family::class);
}
I am using Laravel 5.4
Pretty sure you need to add a related column to the list of selected columns, otherwise Laravel won't b able to match the data to eager-load.
Assuming that Genre has a family_id and Family has an id primary key column specified, you need this:
$query->select('id', 'name_pl', 'name_lat'); // See the id added here?
Should do the trick.
For clarity, the matching I mentioned is this one:
select * from genre
select * from family where id in (1, 2, 3, 4, 5, ...)
-- where the comma-separated list of IDs consists of the unique family_id values retrieved in the first query.
Why don't you try:
\App\Genre::with('family:name_pl,name_lat')->where([
'slug' => $slug,
'is_active' => true
])->first();

Group by not working - Laravel

I'm not able to run this simple query in Laravel 5.3
$top_performers = DB::table('pom_votes')
->groupBy('performer_id')
->get();
It gives me:
SQLSTATE[42000]: Syntax error or access violation: 1055 'assessment_system.pom_votes.id' isn't in GROUP BY (SQL: select * from `pom_votes` group by `performer_id`)
However if I copy raw query from the error and fire directly in PhpMyAdmin, it works fine.
I have already checked this:
https://laravel.com/docs/5.3/queries#ordering-grouping-limit-and-offset
Any help would be appricaited.
Thanks,
Parth Vora
Edit your applications's database config file config/database.php
In mysql array, set strict => false to disable MySQL's strict mode
Maybe your issue is due to the fact that you are using a MySQL server vith version 5.7.5+. From this version on the way GROUP BY works is changed since they make it behave in order to be SQL99 compliant (where in previous versions it was not).
Try to do a full group by or change the configuration of your MySQL server.
Link to official MySQL doc where full GROUP BY is explanined
More safe method instead of disabling strict ('strict' => false) what you could do is pass an array to the config, enabling only the modes that you want:
// config/database.php
'connections' => [
//...
'mysql' => [
//...
'strict' => true,
'modes' => [
//'ONLY_FULL_GROUP_BY', // Disable this to allow grouping by one column
'STRICT_TRANS_TABLES',
'NO_ZERO_IN_DATE',
'NO_ZERO_DATE',
'ERROR_FOR_DIVISION_BY_ZERO',
//'NO_AUTO_CREATE_USER', // This has been deprecated and will throw an error in mysql v8
'NO_ENGINE_SUBSTITUTION',
],
],
],
For anybody who is still getting the same error after changing that setting, try clearing the config cache by running php artisan config:cache
Go to config/database.php
Update strict value false.
return [
'connections' => [
'mysql' => [
'strict' => false
]
]
]
There are ways to fix this
#1
Get only the columns we are grouping by, in this case category_id.
NOTE: Columns in select must be present in groupBy, and vice versa.
$posts = Post::query()
->select('category_id')
->groupBy('category_id')
->get();
category_id
1
2
#2
But I want all columns!
Okay, so you want to get all columns. Then the trick is to simply not use groupBy() on a database level. Instead, you can use it with the returned collection instead.
$posts = Post::query()
->get()
->groupBy('category_id');
[
'1' => [
['id' => 1, 'name' => 'Post 1', 'category_id' => 1, 'author_id' => 4 'visits' => 32],
['id' => 2, 'name' => 'Post 2', 'category_id' => 1, 'author_id' => 8 'visits' => 12],
],
'2' => [
['id' => 3, 'name' => 'Post 3', 'category_id' => 2, 'author_id' => 12 'visits' => 201],
['id' => 4, 'name' => 'Post 4', 'category_id' => 2, 'author_id' => 4 'visits' => 0],
],
]
#3
It is possible to simply disable "strict mode" in Laravel, by setting it to false in the database.php config file. While possible I cannot recommend doing so. It is better to spend the time learning how to write proper SQL queries, as the results given by turning "strict mode" off, can be unpredictable and lead to problems down the road.
Reference
https://sinnbeck.dev/posts/laravel-groupby-error
You can define this line before your query, let's suppose you want to use groupBy so for that instead of changing the config strict to false, simply add this line before where you had used groupBy:
\DB::statement("SET SQL_MODE=''");//this is the trick use it just before your query where you have used group by. Note: make sure your query is correct.
//this is just an example code.
$Rspatients = DB::table('reports')
->select(
DB::raw("day(created_at) as day"),
DB::raw("Count(*) as total_patients"))
->orderBy("created_at")
->groupBy(DB::raw("day(created_at)"))
->get();
My company uses raw SQL to run group by without risking changing mysql settings.
here is an working example :
public static function getPositivesDaily($start_date, $end_date, $admin_id)
{
$positives = DB::select(
'select COUNT(inspections.id) as total,DATE_FORMAT(inspections.created_at, :format) as date
from inspections
where inspections.created_at between :start_date and :end_date
and inspection_results = 1
and admin_id = :admin_id
GROUP BY date',
['format'=>'%Y-%m-%d', 'start_date'=>$start_date, 'end_date'=> $end_date, 'admin_id'=>$admin_id]
);
return $positives;
}
Ask me anything about this code if you don't understand and I will reply as soon as I can.
cheers.
If you false strict mode then you can't use other strict functionality to fix this error Go to the Illuminate\Database\Connectors\MySqlConnector.php and change function like below:
protected function strictMode() {
return "set session
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY
_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'";
}
replace function with this.

Resources