Lazy Loading a Laravel Model relationship through a repository

If your Laravel Model needs access to repository for pulling relationship data, think again.

It’s the wrong way round, don’t do it. Your models need access to data without any N+1 issues from using Lazy load. So if you need to merge some data streams and return a collection, rather than use a repo call to access each stream object; Create a view table which `Union ALL`’s the data various models. Then the model can have lazy load access to all the things you need, and the laravel commands, `->with()` or `->load()` can work without slowing it all down

2 new Laravel things I’m using

Just wanted to share these two simple things I’ve recently found for Laravel 5.3

1. Repository Generator

https://github.com/andersao/l5-repository

This packages just removed about half a day of setting up the backend CRUD per. Model / Entity. A few commands, follow the instructions and then boom, you’ve got a fully functional repository class.

Sure, I’d need to write my on Tests around it performing as “expected”, however, I now have a basic Interface and Abstract which I can use across different Models.

2. Laravel Collective “Custom Components”

https://laravelcollective.com/docs/5.2/html#custom-components

Laravel Collective packages have been staple Laravel components for a while now, however I’ve never quite got to down all the docs (just whizzed on with the bits I need).

I’ve found the Custom Components part method. Before I’ve been creating a new “HTML Components” service class and linking up blade template files with that, however, now I can just keep it within the HTML Facade without any trouble. Much cleaner!

[ReflectionException] Class LocalUsersSeeder does not exist

Just a quick techie post to help out any other laravelians’ who might hit this issue with Laravel 5.2 and database seeding.

I’ve written a seeder and it keeps failing to seed when I run this,

artisan migrate:refresh ---seed

[ReflectionException]
Class LocalUsersSeeder does not exist

Turns out the quick fix was all I had to do was re-run the

composer dump-autoload

Then it all worked! #HTH

Changing the storage path in Laravel 5

So changing the Storage path in Laravel 5 is apparently more difficult than it possibly should be.

Here’s how I solved it with @stauffermatt ‘s tutorial to start but appended to make sure the storage path is stored in Config per. server rather than hardcoded into your Git stored php files.

  1. First follow Matt Stauffer’s tutorial, and add an application override

https://mattstauffer.co/blog/extending-laravels-application

# File /app/Application
<!--?php namespace App;

class Application extends Illuminate/Foundation/Application
{
    /**
     * Get the path to the storage directory.
     *
     * @return string
     */
    public function storagePath()
    {
        return $this->basePath.'/theNewStorage';
    }
}

  1. Then change your `bootstrap/app.php to…
$app = new AppApplication(
realpath(__DIR__.'/../')
);
  1. NOW, my extra bit. Create a config/paths.example.php and add it to git. Then duplicate it as, config/paths.php, add that file to your .gitignore and change the path to the server’s storage path.
<!--?php 

return [

    // Url to the server's storage file
        // eg, 'storagePath' => "/var/www/storage",
       'storagePath' => base_path()."/storage",
];

  1. Alter you app/Application.php file to load in the Config Repo with your new config file
<!--?php namespace App;

use Illuminate/Config/Repository as Config;

class Application extends Illuminate/Foundation/Application
{
    /**
     * Get the path to the storage directory.
     *
     * @return string
     */
    public function storagePath()
    {
        $path = config_path(). '/paths.php';
        $items = include $path;

        $config = new Config($items);

        return $config->get('storagePath');
     }
}

There. Dunnit.

SQLite and multiple renaming or dropColumn ‘s error in laravel 5.0 aritsan migrate

So #HTH

One of my migration scripts in Laravel 5 has 3 dropColumn requests in and 1 rename column. This all works fine with laravel migrations on MySQL and MariaDB, as you would expect.

However once you try to run those same migrations on a mysqlite / sqlite database you may start seeing errors like so

SQLSTATE[HY000]: General error: 1 no such column: XXX (SQL: CREATE TEMPORARY TABLE

Now following up the issue on Github it is related to this, https://github.com/laravel/framework/issues/2979 but Taylor doesn’t believe it’s a bug, saying,

I would do them in two separate operations.

 The work around unfortunately is to split EACH drop Column and rename into 1 separate migration file each…

Crazy, but tbh. if that’s the worst bug I come across with Laravel 5, I’ll take it.

Why we test… the two other tests I’m forgetting to write

This morning was spent fixing something, which frankly, I should have known better! However, when you’re coding and project managing on your own, it’s not easy to keep everything rolling.

When I write new Repository methods, I leave a comment note @totest to remind me to come back and write some tests!

However, I’ve missed writing 2 simple types of tests which would have taken 20 mins and then saved me an hour this morning. So I thought I’d share with you lot.

In My Laravel Middleware I have a method which checks the UserId provided is one of our students.

    $user = $this->userRepo->findByUidOrFail($this->fetchUser());

However, because I haven’t filled in any tests on that Repo yet, I’ve been going around the houses trying to fix a problem which some simple unit tests would have flagged 2 days ago. The return wasn’t erroring if the user isn’t there AND was returning a Collection when it should have been giving me a Model

So along with unit testing positive results from a successful method call, we should be writing two other types of tests.

The Exception Test.

Clearly this method name says, find…OR FAIL!!!! However, it wasn’t throwing a ModelNotFoundException on failing, it was just returning a Collection!

The tests I have written to assert it’s working now,


// UserRepositoryInterfaceTest.php /** * @expectedException ErrorException */ public function test_findByUidOrFail_incorrect_params() { $records = $this->theRepo->findByUidOrFail(); } /** * @expectedException IlluminateDatabaseEloquentModelNotFoundException */ public function test_findByUidOrFail_modelNotFound() { $this->theRepo->findByUidOrFail("foo"); }

The returned type Test.

It seems weird to test you’re getting the write variable type back, however, it’s crucially important. Because what if you expect an integer, 2, and you’re returned a string of “2”. Any triple if’s === would fail and probably throw something else off.

So we test for cast types. In this example, I assert the Model by looking for a certain method’s availability or not.

// UserRepositoryInterfaceTest.php

public function test_findByUidOrFail_is_model()
{
    $record = $this->helper->createAUser();
    $result = $this->theRepo->findByUidOrFail($record->uid);

    $this->helper->assertIsModel($result);
}

// TestHelper.php

public function assertIsModel($obj)
{
    PHPUnit::assertEquals(
        method_exists($obj, 'getTable'),
        true,
        'obj is not a Model'
    );
}

Against the Repository Command pattern…

So a while back I wrote an article about trying out a new pattern, “the repository and command pattern“.

Since using it in one of our major projects I have found it not all that great. So, yes it’s nice having it split from the Repo which I see as a way of searching on data, however, it’s a pain in the wotsit to test. Also, in Laravel it seems to add a lot of extra un-necessary time to my workflow.

The real problem however appears to be a mis-interpretation of what Commands are used for. Since Laravel 5.1 was released it has re-named Commands to Jobs. Highlighting that they should be used more so for delayed tasks rather than, inserting new models NOW!

So, it’ll take time to un-do I imagine and move them into the repository, however I’m glad I tried it as I’ve learnt a lot about testing!