How to stop eloquent trying to set updated_at
Hey guys,
I would like to ask for any suggestions about how to stop Eloquent trying to set the updated_at columns in my DB table, which is not present there. For this particular table, I only require the created_at to be set.
I haven an override on the setUpdatedAt method
public function setUpdatedAt($value) { }
which as Google told me should stop laravel from setting the updated_at parameters on the model; however, it does not.
Thanks to everyone in advance.
public function setUpdatedAtAttribute($value)
{
// to Disable updated_at
}
or
protected $timestamps = false;
public function setUpdatedAtAttribute($value)
is not present in Laravel 5. What is interesting though, the exception thrown, shows this:
at Builder->update(array('read' => '1', 'updated_at' => '2015-02-24 22:16:39')) in Builder.php line 288
at Builder->update(array('read' => '1')) in Model.php line 1559
at Model->performUpdate(object(Builder), array()) in Model.php line 1492
at Model->save() in MessagesRepository.php line 97
at MessagesRepository->update(object(Message), array('read' => '1')) in MessagesController.php line 55
by which it seems that even though the Builder object receives the input array without the updated_at attribute set, it sets it afterwards, which it shouldn't...
Where do you set these functions ?
The only thing I do is that my Message model class extends the Model class and overrides the
public function setUpdatedAt($value)
I just put that method into my Message model and left the body of the method empty so that the updated_at attribute is not set, which does not seem to be true. How come that the updated_at attribute is being set anyway in the Builder instance?
Looking in core and get this :
/**
* Update a record in the database.
*
* @param array $values
* @return int
*/
public function update(array $values)
{
return $this->query->update($this->addUpdatedAtColumn($values));
}
Looks like for any update builder add updated_at column :
/**
* Add the "updated at" column to an array of values.
*
* @param array $values
* @return array
*/
protected function addUpdatedAtColumn(array $values)
{
if ( ! $this->model->usesTimestamps()) return $values;
$column = $this->model->getUpdatedAtColumn();
return array_add($values, $column, $this->model->freshTimestampString());
}
So if you set timestamps builder will always update updated_at...
Hi, maybe you could use the boot() method from a BaseModel and make use of the static::updating event for removing any updated_at content.
public function boot()
{
parent::boot();
static::creating(function()
{
static::setUpdatedAtAttribute() //Call a custom setUpdatedAtAttribute function
});
}
public static function setUpdatedAtAttribute()
{
//put here your content.
}
Hope it helps you.
@robobalasko There is no reliable way to do it, but disabling timestamps for the model, then add creating event handler, like mentioned above:
public $timestamps = false;
// ...
// boot
static::creating( function ($model) {
$model->setCreatedAt($model->freshTimestamp());
});
It will take care of created_at column for you.
After an hour of digging in the core I found a way how to accomplish this...
First of all, I extended the default model class with a custom BaseModel class that all my other models now extend. Then, I added a new attribute to my BaseModel class, along with an accompanying method:
protected $useUpdatedAt = true;
public function usesUpdatedAt()
{
return $this->useUpdatedAt;
}
Finally, I modified the updateTimestamps() method of the core Model class to use an if when setting the updated_at column like this:
if ($this->usesUpdatedAt())
{
$this->setUpdatedAt($time);
}
and also the first line of the Builder class' addUpdatedAtColumn method like this:
if ( ! $this->model->usesTimestamps() || ! $this->model->usesUpdatedAt()) return $values;
AND IT WORKS!
Now, in every model where the updated_at timestamp is not required, I only have to set the $useUpdatedAt param of that particular model class to false.
Not sure if this is the best way to go, but certainly, it is the only one I could come up with myself... Anyway, looking at it now, yours is much cleaner, so I'll probably use that creating model event since there won't be many Models that would not require updated_at being set.
@robobalasko I suppose you overriden the method on Eloquent\Builder in the core files, which is not a good idea. It will be reset with next composer update. So, yes, it can be achieved that way, but it's not reliable and a bit longer ;)
Try to use this.
for disabling updated_at
public function setUpdatedAt($value){
;
}
for disabling created_at
public function setCreatedAt($value){
;
}
For disabling both just use
public $timestamps = false ;
To stop eloquent on trying to set "updated_at" and "created_at", you need to do the following
1st:
Locate the file... "laravel folder"\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php
2nd:
Open this file then find the follwoing functions:
updateTimestamps() getUpdatedAtColumn() getCreatedAtColumn()
3rd:
Inside the function updateTimestamps(), just comment the following codes inside the if conditions:
$time = $this->freshTimestamp();
if (! $this->isDirty(static::UPDATED_AT)) {
//$this->setUpdatedAt($time);
}
if (! $this->exists && ! $this->isDirty(static::CREATED_AT)) {
//$this->setCreatedAt($time);
}
Inside the function getUpdatedAtColumn(), just comment this code:
//return static::CREATED_AT;
Inside the function getCreatedAtColumn(), just comment this code:
//return static::UPDATED_AT;
Then after that, the eloquent will never set the field "updated_at" and "created_at". Hope it helps. :)
Good job modifying core.
If you want to disable it for only one or few objects you can try this
class YourModelName extends Model { /** * @var string */ protected $table = "your_table_name_here";
/**
* @var array
*/
protected $guarded = [];
/**
* @var string
*/
public $updated_at = '';
}
It seems if you add only the following line in your object declaration is just enough. Not elegant but this works for me.
public $updated_at = '';
.. and sorry for my bad English :D
I borrowed from @raulursu. This works for me when only using created_at.
protected $dates = ['created_at'];
protected $updated_at = '';
I'm using $fillable and thus using $guarded is not recommended.
You can disable updated_at attribute as follows
/**
* The name of the "updated at" column.
*
* @var string
*/
const UPDATED_AT = null;
works for laravel 5.5
The easiest way for me was like what @raysmithdev mentioned here, however a slight modification if I may
instead of: protected $timestamps = false;
use: public $timestamps = false;
just declare the public timestamps variable to false and everything will work great.
public $timestamps = false;
@Shahrukh4 your solution worked perfectly for me. Thank you so much.
You'll often encounter tables where you don't even want to have an updated_at column because you'll never touch the records after their creation. The easiest way (for me at least) to achieve it is this:
- Migration. Replace the default
$table->timestamps();call with a new one like this:
$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
this will continue filling the created_at column automatically and will be handled by MySQL.
- Model. Disable the timestamps because you no longer want to rely on Laravel generating the timestamps. Also, you might want to add a
$datescast attribute, just to make sure that thecreated_atcolumn is always being cast to a Carbon instance.
class SomeModel extends Model
{
public $timestamps = false;
protected $dates = ['created_at'];
...
}
If you are using 5.5.x:
const UPDATED_AT = null;
And for 'created_at' field, you can use:
const CREATED_AT = null;
Make sure you are on the newest version. (This was broken in Laravel 5.5.0 and fixed again in 5.5.5).
Please or to participate in this conversation.