bookmark_borderLaravel Eloquent only()

$fullModel = Model::find(1) // Get model with id 1
$idArray = $fullModel->only('id')  // array containing id


// this does not work. You'll get back an empty collection
// It is trying to pull the id column off the collection object,
// not the models it contains
$models = Model::all()
$ids = $models->only('id')

// this will give you a collection of ids
$models = Model::all()
$ids = $models->pluck('id')

 

bookmark_borderLaravel Eloquent Attributes

When dealing with an Eloquent model, you can add your own attributes. These can be useful for computed values.

For example:

class Person extends Model
{
   // By default, all the database fields will be available.
   // Let's assume for this example class that we have
   // first_name, last_name, age
   // but we also want a property called full_name, that doesn't 
   // exist in the database. 

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

}

// To access that property in a controller, you use the camelCase version of it:
// (assuming you already have an object instance called $aPerson)

$fullName = $aPerson->fullName;

// To access the property directly from the class instance in a view using blade, 
//(assuming that you passed the instance to the view), you use the snake_case version of it

{{ $aPerson->full_name }}

Just remember that when creating an attribute, you start with get and end with Attribute, and the name goes in the middle. The whole thing is camelCase. This is Laravel’s convention.

bookmark_borderLaravel Eloquent sortBy function

Here is how you can sort a collection by an ordered array of ids.

The use case here was that I had a number of objects in a Redis cache, which were retrieved in unsorted order. The objects were large, so keeping them cached improved performance. However, the sorting information was not kept on the object, so to get them in the proper order required a table join. Using eloquent, I originally grabbed all the objects directly from the database. However, once the objects were in the cache, I turned it into a two step process. First I got the ids in the correct order, using the original eloquent statement, but I added a pluck statement to only grab the ids. This kept the query fast. Using all(), I returned them as an array.

After getting the collection of objects from the cache, in no particular order, I then sorted them using the array:

$sortedIds = [2536,6374,2562,366,167];  // these are in the desired order
$sortedCollection = $unsortedCollection->sortBy(function($item, $key) use($sortedIds){
     return array_search($item->id,$sortedIds);
});

To understand how this works, let’s say that the id’s in the unsorted collection are in this order:

167,366,2536,6274,2562

First pass:

$item->id = 167

position of this number in $sortedIds array: idx 4, (5th position)

Second pass:

$item->id = 366

position of this number in $sortedIds array: idx 3, (4th position)

As you can see, it is determining where they belong by finding the proper position within the sorted array.

The sortBy function builds up a new array in the correct order, then returns it.

 

bookmark_borderCompact and Extract

Compact takes individual variables, and packs them into an associative array. Extract does the opposite.

<?php
// example code

// Set 2 variables
$var1 = "one";
$var2 = "two";

// Create associative array
$arr = compact('var1','var2');

// Show results
var_dump($arr);

/* Output
array(2) {
  ["var1"]=>
  string(3) "one"
  ["var2"]=>
  string(3) "two"
}
*/


// Clear out the originals
unset($var1);
unset($var2);

// Recreate the variables from the array
extract($arr);

// Output the variables to prove they're back
var_dump($var1,$var2);

/* Output
string(3) "one"
string(3) "two"
*/

 

bookmark_borderSplat!

While looking through the Query Builder class in the Laravel source code today, I came across something I hadn’t seen before in PHP:

$query->{$method}(…array_values($value));

I had no idea what the three dots meant, so I went looking for it. Turns out it’s a feature added in PHP 5.6 called “variadic functions”, and is often referred to as the “splat operator”, or “scatter operator”. The page I found was from Lorna Jane, and explained it well. Basically, it lets you pack as many parameters as you want to pass in to a function into a single array. Here’s an example:

function test(...$arr)
{
    var_dump($arr);
}

test("value 1", "value 2");

Output:

array(2) {
  [0]=>
  string(7) "value 1"
  [1]=>
  string(7) "value 2"
}

If you remove the three dots, you get this:

function test($arr)
{
    var_dump($arr);
}

test("value 1", "value 2");

Output:
string(7) "value 1"

But wait! There’s more!

Turns out this triple dot thing can work both ways. It can also turn an array into individual parameters, like this:

function test($arg1, $arg2, $arg3)
{
    var_dump($arg1,$arg2,$arg3);
}

$arr[] = "value 1";
$arr[] = "value 2";
$arr[] = "value 3";

test(...$arr);

Outputs:

string(7) "value 1"
string(7) "value 2"
string(7) "value 3"

This usage is called Argument Unpacking. Here’s what happens if you don’t put the three dots:

function test($arg1, $arg2, $arg3)
{
    var_dump($arg1,$arg2,$arg3);
}

$arr[] = "value 1";
$arr[] = "value 2";
$arr[] = "value 3";

test($arr);

Outputs:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function test(), 1 passed in Standard input code on line 22 and exactly 3 expected in Standard input code:13
Stack trace:
#0 Standard input code(22): test(Array)
#1 {main}
  thrown in Standard input code on line 13

This shows that it is in fact unpacking that array into the individual input variables for the test function.

Thanks Lorna Jane for the great explanation!