Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.3] Allow key arguments to model getAttributes #15722

Merged
merged 1 commit into from
Oct 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions src/Illuminate/Database/Eloquent/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -3067,13 +3067,31 @@ public function is(Model $model)
}

/**
* Get all of the current attributes on the model.
* Get a selection of the current attributes on the model.
*
* @param array $keys
*
* @return array
*/
public function getAttributes()
public function getAttributes($keys = [])
{
return $this->attributes;
if ($keys === []) {
return $this->attributes;
}

$keys = is_array($keys) ? $keys : func_get_args();

$result = [];

foreach ($keys as $key) {
$value = $this->getAttribute($key);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using getAttribute within this method might cause some incompatibilites. When you ask all attributes, Eloquent won't cast nor use mutators in any of them; but when you specify some keys you will get them casted or mutated (if there is something to mutate). In my view, this method may cause confusion since it works one way with parameters and in a different way without parameters.

For example, let's say we have this Model:

User extends Eloquent
{
    protected $casts = [
        'active' => 'boolean'
    ];

   public function getFullNameAttribute()
   {
        return $this->first_name . ' ' . $this->last_name;
   }
}
$attributes = $model->getAttributes();

// You'll get the following without "full_name" attribute
$attributes = [
    // ...
    'active' => 1,
    'created_at' => '2016-10-07 14:47:25',
    // ...
];

This is how it comes from the database. If you use $model->getAttributes() that's what you'll get, but if you just ask for those attributes as you propose this is what you'll get:

$attributes = $model->getAttributes(['active', 'created_at', 'full_name']);

$attributes = [
    // ...
    'active' => true,
    'created_at' => new Carbon('2016-10-07 14:47:25'),
    'full_name' => 'Cristian Llanos',
    // ...
]

In this case you'll get active as a boolean, not a number and created_at as a Carbon instance since its a timestamp and Eloquent does that when you call getAttribute.

Newcomers or someone who doesn't know about this behaviour might have a hard time figuring out why this method provides different results in certain occasions.

I'm not very confident about this, but I suppose getAttributes should return us all attributes already casted or mutated as needed. However, this is not the case nowadays and for that purpose we can use $model->toArray() (which will give us all attributes casted or mutated).


if (! is_null($value)) {
$result[$key] = $value;
}
}

return $result;
}

/**
Expand Down
12 changes: 12 additions & 0 deletions tests/Database/DatabaseEloquentModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ public function testAttributeManipulation()
$this->assertEquals(json_encode(['name' => 'taylor']), $attributes['list_items']);
}

public function testGetMultipleAttributes()
{
$model = new EloquentModelStub(['name' => 'taylor', 'framework' => 'laravel', 'foo' => 'bar']);

$this->assertEquals(['name' => 'taylor', 'foo' => 'bar'], $model->getAttributes('name', 'foo'));
$this->assertEquals(['name' => 'taylor', 'foo' => 'bar'], $model->getAttributes(['name', 'foo']));
$this->assertEquals(['name' => 'taylor'], $model->getAttributes('name'));
$this->assertEquals(['name' => 'taylor'], $model->getAttributes(['name']));

$this->assertEquals(['name' => 'taylor'], $model->getAttributes(['name', 'doesntexist']));
}

public function testDirtyAttributes()
{
$model = new EloquentModelStub(['foo' => '1', 'bar' => 2, 'baz' => 3]);
Expand Down