Can You Test Emptiness of Laravel Collection using empty()?

In short, Yes and No. Not the way we commonly do a variable, but in laravel way yes. It’s a common mistake done by almost all the laravel developer once in a lifetime until the bug appears (Well, you are not counted, if you are exceptional :P). So, let’s explore.

Let’s look at how laravel collection is constructed. Go to your laravel tinker console and try this:

php artisan tinker
Psy Shell v0.9.12 (PHP 7.2.31 — cli) by Justin Hileman
>>> $collection = collect([])
=> Illuminate\Support\Collection {#3164
     all: [],
   }

You see, when I create an empty collection, laravel still puts an underlying array called ‘all’. This is the manipulator array and contains all the content inside. This array is accessible through the collection all method:

>>> $collection->all()
=> []

You see, the return is an empty array. But when it’s just the collection, it’s not really empty, it has an underlying content holder.

So, how can we test emptiness of the collection? Well, there are 3 ways.

I) Laravel gives a way to return the number of element in the collection with a collection method calls count(). You can test it against 0 to see if the collection is empty or not

>>> $collection->count()
=> 0

II) You may use the regular php count() method to return that it doesn’t contain any leaf element and test it against 0:

>>> count($collection)
=> 0

III) If you are a big fan of ’empty’ and still would like to follow, then you can grab the content of the collection using all method and test it against empty as following:

>>> empty($collection->all())
=> true

So, yeah, now you know all the ways 🙂

How to Do Full Page Caching in Laravel / How to Cache Views in Laravel

Most of the developers use Laravel Cache for database query result caching. Although, this is efficient, but the ultimate caching performance enhancement is achieved through FPC or Full Page Caching for web apps. Laravel doesn’t give any hint, neither describe how to do this in their documentation, which is why the article.

What is Full Page Caching?

Technically a full page caching means, to cache the html response from an app. In FPC, it is generally accepted to use the route/view as the cache key concatenating or mixing with the VERB in request header.

When a user requests for a route, we usually pull a controller behind the route to process and prepare several data before sending them to views for response. But what if the data hasn’t changed since the last request? That technically means the response hasn’t changed, right? This essentially says, you can cache the full response and skip the whole controller processing, even pulling the view, instead, only put the Cached data in the response. Theoretically, this is the best form of caching mechanism for ‘Web Based’ solutions like Ecommerce, Newspapers, Blogs etc. This technique is known as FPC or Full Page Caching.

Laravel Cache

Laravel is best known for it’s documentation. Although, the Laravel Cache documentation, only follows how to cache the database queries, not the views. To understand how to do FPC using Laravel, let’s first look at how our views are usually formed.

class NewsController extends Controller {
    public function index() {
        $news = News::all();
        return view('news.index')->with('news', $news);
    }
}

Here the view() helper method, returns a Laravel View instance. It doesn’t return the html or renders one. So who does it? Laravel does it for you under the hood, and pass it to Response class. Now to cache the views, you have to return the html and save it to cache. There are basically two ways of doing it.

The easiest way is to use a function called ‘render()’ that is available to View class which returns the html of the created View instance. Here is how you may convert the above controller method to return from cache:

class NewsController extends Controller {
    public function index() {
        if ( Cache::has('news_index') ) {
            return Cache::get('news_index');
        } else {
            $news = News::all();
            $cachedData = view('news.index')->with('news', $news)->render();
            Cache::put('news_index', $cachedData);                                         
            return $cachedData;           
        }  
    }
}

This should be it, simple, ha!

Here is more! I looked at the laravel documentation a bit more, and I could find there is another way you can do the above. This is using the Response class. view method returns a Views instance, while Response instance is able to return rendered html based on view. Here is how to do this:

Response::view('news.index')->with('news', $news);

This also means our idea that Laravel does the rendering under the hood is a bit wrong, it basically shoots the views instance to a response instance (which it has to) and returns it, that put the rendered html in the final response. We can now cache the above output and serve for future requests without entering the controller’s processing!

TDD: Date Assertions – Laravel 7, PHP 7.* – Carbon 2 – Changes

If you follow a TDD approach to develop your software, and also a Laravel user, working with a JSON API, you might have experienced some date assertion issues while asserting Json with Laravel 7. Previously, when Laravel was using Carbon 1 for date management, it would not return the whole Carbon object for assertJson. Which is why, the following would work in a sample PHPUnit Test:

$contact = factory(Contact::class)->create();
$response = $this->get('/api/contacts' . $contact->id);

$response->assertJson([
'name' => $contact->name,
'email' => $contact->email,
'meeting_date' => $contact->meeting_date,
'company' => $contact->company,
]);

But as of now, Carbon 2, returns the whole Carbon object for $contact->meeting_date here, the assertion will fair, because the $response, didn’t get a Carbon object, instead a Json string here.

If you go through the Carbon documentation here, you can see the following under the section ‘Migrate to Carbon 2’:

$date->jsonSerialize() and json_encode($date) no longer returns arrays but simple strings: "2017-06-27T13:14:15.000000Z". This allows to create dates from it easier in JavaScript. 

This is basically what you need to use if you are on Laravel 7 with Carbon 2. You need to serialize the data as Laravel is not doing it for you automatically here to fix this up. Just change the ‘meeting_date’ to the following:

'meeting_date' => $contact->meeting_date->jsonSerialize(),

and this should let your assertion pass.

Remember, you might not need to explicitly do this in your controller return until you are following a TDD based development where an assertion to pass is important to continue the process. Laravel resource would implicitly serialize your data before returning them from controller.