Reputation: 767
I know it's possible to define accessors and mutators for individual fields, like so:
public function setSomeAttribute($value) {
// set the attribute
}
public function getSomeAttribute() {
// return the attribute}
}
But is it possible to define a fallback method that will be used for all attribute gets and sets?
The reason being that I want to convert any empty values to null values on the fly, to keep my database clean and allow nullable fields to be null instead of an empty string (if there's a better way to do this let me know!)
I'm looking for something like
public function setAttribute($property,$value) {
$this->$property = empty($value) ? null : $value;
}
UPDATE:
Thanks to Chris Goosey I've found a solution that works for me. I extended the Eloquent model method setAttribute, and I set the value to the column default if it's empty. That's usually null, zero or an empty string in my databases so works for me!
public function setAttribute($key, $value)
{
// Convert empty values to their default values (e.g. null, zero)
if(empty($value) && $this->getSchema()->hasColumn($key)) {
$value = $this->getSchema()->getColumn($key)->getDefault();
}
parent::setAttribute($key,$value);
}
Upvotes: 12
Views: 7945
Reputation: 498
Best way is probably to extend the Eloquent class overwriting the setAttribute and getAttribute methods.
For all your models to inherit these overwritten methods you would want to create a class that extends eloquent e.g.
<?php
class BaseModel extends eloquent {
public function setAttribute($property,$value) {
$this->$property = empty($value) ? null : $value;
}
public function getAttribute($key) {
// Do Stuff
}
}
and then all your models should extend from this new class, e.g.
<?php
class User extends BaseModel {
protected $table = 'users';
}
It is also worth mentioning your new methods should have all the functionality of the old method plus your new functionality, this is what the getAttribute() looks like (Illuminate\Database\Eloquent line 2212):
/**
* Get an attribute from the model.
*
* @param string $key
* @return mixed
*/
public function getAttribute($key)
{
$inAttributes = array_key_exists($key, $this->attributes);
// If the key references an attribute, we can just go ahead and return the
// plain attribute value from the model. This allows every attribute to
// be dynamically accessed through the _get method without accessors.
if ($inAttributes || $this->hasGetMutator($key))
{
return $this->getAttributeValue($key);
}
// If the key already exists in the relationships array, it just means the
// relationship has already been loaded, so we'll just return it out of
// here because there is no need to query within the relations twice.
if (array_key_exists($key, $this->relations))
{
return $this->relations[$key];
}
// If the "attribute" exists as a method on the model, we will just assume
// it is a relationship and will load and return results from the query
// and hydrate the relationship's value on the "relationships" array.
$camelKey = camel_case($key);
if (method_exists($this, $camelKey))
{
return $this->getRelationshipFromMethod($key, $camelKey);
}
}
and the setAttribute in the same file looks like this (line 2338):
/**
* Set a given attribute on the model.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function setAttribute($key, $value)
{
// First we will check for the presence of a mutator for the set operation
// which simply lets the developers tweak the attribute as it is set on
// the model, such as "json_encoding" an listing of data for storage.
if ($this->hasSetMutator($key))
{
$method = 'set'.studly_case($key).'Attribute';
return $this->{$method}($value);
}
// If an attribute is listed as a "date", we'll convert it from a DateTime
// instance into a form proper for storage on the database tables using
// the connection grammar's date format. We will auto set the values.
elseif (in_array($key, $this->getDates()))
{
if ($value)
{
$value = $this->fromDateTime($value);
}
}
$this->attributes[$key] = $value;
}
Hope this helps!
Upvotes: 13