35

Is there a way to retrieve a model in Laravel with all the attributes, even if they're null? It seems to only return a model with the attributes that aren't null.

The reason for this is that I have a function that will update the model attributes from an array, if the attributes exists in the model. I use the property_exists() function to check the model if it has a particular attribute before setting it. The array key and model attribute are expected to match, so that's how it works.

It works fine if the model already has the attributes set, because the attribute exists and takes the value from the array. But nothing will get updated or set if the attribute was previously null, because it fails the property_exists() check.

What's ultimately happening is that I have a single array of attributes, and then perhaps two models. And I run my setter function, passing in the attributes array, and each of the objects in separate calls. If the model has a matching property, it gets updated.

kenshin9
  • 2,215
  • 4
  • 23
  • 38

6 Answers6

35

Here are two ways to do this. One method is to define default attribute values in your model.

protected $attributes = ['column1' => null, 'column2' => 2];

Then, you can use the getAttributes() method to get the model's attributes.

If you don't want to set default attributes though, I wrote up a quick method that should work.

public function getAllAttributes()
{
    $columns = $this->getFillable();
    // Another option is to get all columns for the table like so:
    // $columns = \Schema::getColumnListing($this->table);
    // but it's safer to just get the fillable fields

    $attributes = $this->getAttributes();

    foreach ($columns as $column)
    {
        if (!array_key_exists($column, $attributes))
        {
            $attributes[$column] = null;
        }
    }
    return $attributes;
}

Basically, if the attribute has not been set, this will append a null value to that attribute and return it to you as an array.

Thomas Kim
  • 15,326
  • 2
  • 52
  • 42
  • if the goal is to set empty values to null, the simplest way would be to append `->nullable()` to the field in the migration. You don't need to write a new method or set it in the model. That being said neither of these should be necessary – tam5 Nov 04 '15 at 14:06
  • The goal is for him to be able to get all attributes when they aren't yet set, and the only way to do that is to set the values to null (or some other default value). – Thomas Kim Nov 04 '15 at 16:35
  • 3
    At least, because we aren't able to see any code, I am assuming he is working with an empty instance since he's saying `getAttributes()` is not working. For example, something like `$user = new User; $user->getAttributes();` will not return attributes because it's not set. – Thomas Kim Nov 04 '15 at 16:44
  • ah, indeed you are correct if he is calling `new User;` I will update my answer to differ to yours in such a case – tam5 Nov 04 '15 at 17:15
  • Thanks! This led me in the right direction. Realistically, I didn't need every attribute on the model. Just a few select ones to update, which coincidentally are also the within the $fillable array when I thought about it. So I'm actually able to use $fillable to check if the model should have the attribute. – kenshin9 Nov 06 '15 at 03:17
27
$model->getAttributes();

Above will return an array of raw attributes (as stored in the database table)

$model->toArray() 

Above will return all the model's raw, mutated(if used), and appended attributes

Hope it will helpful!!

Mahesh Yadav
  • 2,416
  • 20
  • 23
  • `$model->attributesToArray()` is a good option if you want similar to `$model->getAttributes()` but with casting, etc applied (so without relationships). `$model->toArray()` is ok, but it'll also run `toArray()` recursively on any loaded relationships and include those as well. – iamacarpet Dec 07 '22 at 15:19
1

Update:

If you are trying to do this after instantiating like so:

$model = new Model;

then please differ to Thomas Kim's answer.

Otherwise: You could use the toArray() or getArributes() method on the model instance, that would give back all the attributes including nulls. Then you can use array_key_exists to check.

Like so:

if (array_key_exists('foo', $model->getAttributes())) {
    $model->foo = 'new value';
}
tam5
  • 3,197
  • 5
  • 24
  • 45
  • I tried instantiating a new model, and when trying either one of those functions, I get an empty array. I think that should be expected though. From the documentation for getAttributes() at least, it says "Get all of the current attributes on the model." – kenshin9 Nov 04 '15 at 05:42
  • You instantiated in your project or just in tinker? – tam5 Nov 04 '15 at 11:41
  • Sorry, I didn't think to mention that. I did instantiate it within my project. – kenshin9 Nov 04 '15 at 14:58
  • very weird for me it works. can you post your code maybe? – tam5 Nov 04 '15 at 15:04
1

I have this snippet on my other project to load all model attributes and relation.

public function forModel($with)
{
    $this->load($with);

    $attributes = $this->toArray();

    // Normalize Null Relation To Empty Model
    foreach ($attributes as $key => $value) {
        if (
            is_null($value) && 
            method_exists($this, Str::camel($key)) && 
            $this->{Str::camel($key)}() instanceOf \Illuminate\Database\Eloquent\Relations\Relation
        ) {

            $relation = $this->{Str::camel($key)}();
            $model = $relation->getModel();
            $attributesForRelation = $model->getAttributes();
            foreach ($model->getFillable() as $column)
            {
                if (! array_key_exists($column, $attributesForRelation))
                {
                    $attributesForRelation[$column] = null;
                }
            }

            $attributes[$key] = $attributesForRelation;
        } else {
            $attributes[$key] = $value;
        }
    }

    return $attributes;
}
Vortechron
  • 51
  • 1
  • 3
0

What if you were to explicitly declare all the fields you want back.

public function getSomeModelFromArray(Request $request)
{
    // This will only give back the columns/attributes that have data.
    // NULL values will be omitted doing it this way.
    //$model = $request->all();

    // However by declaring all the attributes I want I can get back 
    // columns even if the value is null. Additional filtering can be 
    // added on if you still want/need to massage the data.
    $model = $request->all([
        'id',
        'attr1',
        'attr2',
        'attr3',
        //...
    ]);

    //...

    return $model;
}

Pretty generic example but hopefully someone will find this useful.

Rockin4Life33
  • 2,240
  • 1
  • 31
  • 29
0

This worked form me:

$attributes = new App\Models\NameModel();
$attributes->getFillable();
Gustavo Marquez
  • 419
  • 4
  • 6