I have a problem with updated_at, created_at fields in Laravel 5.
Here is my migration:
Schema::create('lots', function (Blueprint $table) {
$table->increments('id');
$table->integer('lot');
$table->integer('is_active');
$table->timestamps();
});
But when I insert some data into this table, updated_at and created_at fields are null. How make them auto-complete with current timestamps?
I insert data like this:
\DB::table('admin_lots')->insert([
'lot' => $request->cycle_lot,
'is_active' => '1',
]);
Thanks.
You have to use the create method instead of the insert method in Laravel.
The create method automatically adds timestamps for created_at and updated_at fields:
// GOOD:
User::create(array(
'name' => 'John'
));
On the contrary, the insert method bypasses Eloquent, (it uses the query builder) and does not update updated_at/created_at columns!
// BAD:
User::insert([
'name' => '[[ test name ]]',
]);
dd(
User::where(['name' => '[[ test name ]]'])->first()->create_date
);
You probably do not use Eloquent when inserting data, in this case you should add timestamps manually.
If you do not want to do this, but you still need filled timestamps, use this hack:
$table->timestamp('created_at')->default(\DB::raw('CURRENT_TIMESTAMP'));
$table->timestamp('updated_at')->default(\DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
Update
Based on your updated code, here's another solution:
\DB::table('admin_lots')->insert([
'lot' => $request->cycle_lot,
'is_active' => '1',
'created_at' = \Carbon\Carbon::now()->toDateTimeString(),
'updated_at' = \Carbon\Carbon::now()->toDateTimeString()
]);
Check if your model has this line.
public $timestamps = false;
If it has, delete it.
When you instert data directly, Laravel won't know about your timestamps.
You can either set the timestamps manually in the insert statement, or switch to using Eloquent models , which handle many things out of the box for you, including timestamps. It's also way easier to maintain than straight queries, where applicable.
Eloquent ORM
You need to use Laravel's awesome Eloquent feature to make timestamps written to the Database automatically...
As by seeing your example the code for eloquent will go something like this:
$lot_inputs = array(
'lot' => $request->cycle_lot,
'is_active' => 1
);
$new_lot = Lot::create($lot_inputs);
Please note that you should have the Model for the table = 'lots' (and it must extend Eloquent) so that you can easily use Eloquent methods and its properties...
It would be great if you use Eloquent ORM as much as possible so that if in future you want to change your DB technology then you won't need to specify the written eloquent queries again (e.g: the conversion of query to different DB languages is automatically done by Eloquent)
Thanks I hope this will help you to resolve your issue..!!
Related
I have a table with columns like "name", "surname", "user_id", and I need to check if entry exists first by id, and then by name and surname together, if there is none, create it. How do I do it neatly, instead of making two update statements, and if both return 0 just create a new one (which seems too bulky)
I thought of using firstOrNew, but it seems that it only can work while matching all of the parameters.
Is there any method I've missed that would apply well to my situation?
You could try something like this (assuming you want to create a model [saved to the database]):
$attributes = [
'name' => ...,
'surname' => ...,
];
$model = Model::where('id', $id)
->orWhere(fn ($q) => $q->where($attributes))
->firstOr(fn () => Model::create($attributes));
This would search for a record by id OR name and surname. If it doesn't find one it will create a new record with the name and surname (assuming those attributes are fillable on the Model).
Laravel 8.x Docs - Eloquent - Retrieving Single Models / Aggregates firstOr
When using the select2 field/column type in Laravel Backpack, the list view displays the 'id' of the foreign entity instead of the foreign key required (in this case the 'name' of the Session).
Laravel 5.8.4, Backpack 3.4. I asked in GitHub and the response was that my relationships were incorrect in my models. I don't think that's the problem as the name loads in the edit view.
GradeCrudController
$this->crud->addColumn([
'label' => "Session",
'type' => 'select2',
'name' => 'session_id', // the db column for the foreign key
'entity' => 'session', // the method that defines the relationship in your Model
'attribute' => 'name', // foreign key attribute that is shown to user
'model' => "App\Models\Session" // foreign key model
]);
Grade (Model)
public function session()
{
return $this->belongsTo('App\Models\Session');
}
Session (Model)
public function grades()
{
return $this->hasMany('App\Models\Grade');
}
As it's been a few days and nobody has responded, I thought I'd post the answer I came up with. Note that I highly doubt that this is the correct solution, but for my project it will do.
I added a Laravel Observer for the Grade Model. Once a user adds a new record, the observer visits the session table, pulls the name of the session using the key and adds it as a column to the Grades table.
Then in backpack I just display the 'name' column.
There has to be a better way than this... But for now it will do.
I see you're using a "select2" column type. That's not something Backpack provides by default - it only has a "select" column.
Most likely what happened is that Backpack loaded the "text" column, since it couldn't find a "select2" column. Hence, the ID.
Try changing "select2" to "select". It should work for you without any observers/anything else.
I was having a similar issue. I could not get the foreign key attribute to show up no matter what. I finally got it working by doing to following.
Add the foreign key to the belongsTo method. It should be the name of the column in that model that has the ID that is associated with in the belongsTo model.
public function session()
{
return $this->belongsTo('App\Models\Session','name');
}
One other item that I suggest is to make sure all columns that have foreign keys are set to the same data types in the database.
I'm trying to get the same result as in Eloquent when create and update will return the model back.
In the case of query builder, how can I return the model when insert returns boolean and update returns the ID of the updated row?!?!?
For example: DB::table('users')->insert( ['email' => 'john#example.com', 'votes' => 0] );
Will return boolean, instead what I am looking for is to get that created user, same behavior with User::create().
DB::table('users')->update() will return the ID of the updated row, again I want the updated row as an object same behavior with User::update().
I know that insertGetId() will give me the ID when I use insert(), but I don't want to make an extra step to use the ID and find the row.
Also, for the update, I don't want to use the ID that update() returns to use it in order to find the row.
Does that make any sense?
Use insertGetId() instead of insert() and then find() the model. For example:
$id = DB::table('users')->insertGetId(['name' => 'Ivanka', 'email' => 'ivanka#ivanka.com']);
$user = User::find($id);
When you are updating you have the id, so just find() it: User::find($id).
Documentation that explains how insertGetId() works: https://laravel.com/docs/5.7/queries#inserts
also, you can use from below code if you want.
find the last insert column:
$last_id = Illuminate\Support\Facades\DB::getPdo()->lastInsertId();
and next:
$user = User::find($last_id);
i am trying to preform update or create action on many records using laravel model.
Normal insert with updateOrCreate works perfectly with foreach but i want to avoide it as it slowing things down.
I have something like 200k records.
Is there is any way to achive it?
I tried this answer below
https://stackoverflow.com/a/34815725/1239122
But it is not super elegant.
Any ideas?
You can try this library for batch insert and update.
https://github.com/mavinoo/laravelBatch
I didn't find a way to bulk insert or update in one query. But I have managed with only 3 queries. I have one table name shipping_costs. Here I want to update the shipping cost against the shipping area. I have only 5 columns in this table id, area_id, cost, created_at, updated_at.
// first get ids from table
$exist_ids = DB::table('shipping_costs')->pluck('area_id')->toArray();
// get requested ids
$requested_ids = $request->get('area_ids');
// get updatable ids
$updatable_ids = array_values(array_intersect($exist_ids, $requested_ids));
// get insertable ids
$insertable_ids = array_values(array_diff($requested_ids, $exist_ids));
// prepare data for insert
$data = collect();
foreach ($insertable_ids as $id) {
$data->push([
'area_id' => $id,
'cost' => $request->get('cost'),
'created_at' => now(),
'updated_at' => now()
]);
}
DB::table('shipping_costs')->insert($data->toArray());
// prepare for update
DB::table('shipping_costs')
->whereIn('area_id', $updatable_ids)
->update([
'cost' => $request->get('cost'),
'updated_at' => now()
]);
You can use insert() in Query Builder to bulk insert. But update statement needs conditions. Please read the document:
https://laravel.com/docs/5.7/eloquent#updates
As far as I know, you can not do it for the update as you need to check the condition for the update, But you can do it for insert
$data = array(
array('name'=>'John', 'phone'=>'1234567890'),
array('name'=>'Deo', 'phone'=>'9876543210'),
//...
);
Model::insert($data);
I use Laravel 5.6, and I have a problem with my seeder.
I use this :
factory(\App\Models\Merchant::class)->create([
'email' => 'admin#domain.com',
])->each(function ($m) {
$m->stores()->save(factory(\App\Models\Store::class)->create()
->each(function ($s) {
$s->products()->save(factory(\App\Models\Product::class, 10)->create());
})
);
});
All are hasMany relations.
Doing this, I have this error :
General error: 1364 Field 'merchant_id' doesn't have a default value
(SQL: insert into stores ....)
It's like my first $stores->save( ... ) doesn't use the merchant created.
In my DB, I have one merchant created.
If I use ->make() instead of ->create(), it works for the Store, but I can't save products because it's not persisted...
Is it possible to use multiple save in factories like this ?
Your code may need a little refactoring as you may be chaining creation of models incorrectly:
factory(\App\Models\Merchant::class, 2)->create([
'email' => 'admin#domain.com',
])->each(function ($m) {
$store = factory(\App\Models\Store::class)->create(['merchent_id' => $m->id]);
factory(\App\Models\Product::class, 10)->create(['store_id' -> $store->id]);
);
});
Note: In order to use the ->each() method, you need to have a collection instance. I do not think creating only one merchant will return a collection. In the example, we create 2 merchents.