Mauro Baptista

I'm a software developer! I'm comfortable with PHP and Javascript. Currently developing this blog and a limo reservation app using Laravel and TDD!

Always learning something new!

March 01, 2017 at 12:00 / By Mauro Baptista / Laravel PHP

Fixing the TokenMismatchException on Laravel Test

It quite frustrating when you get the Illuminate\Session\TokenMismatchException when running your tests.

I've found a solution that is not beautiful, but it works!

Basically is add the following code (lines 10 to 12) on the class Illuminate\Foundation\EnvironmentDetector:


    /**
     * Get the environment argument from the console.
     *
     * @param  array  $args
     * @return string|null
     */
    protected function getEnvironmentArgument(array $args)
    {
        if (isset($args[0]) && Str::endsWith($args[0], 'phpunit')) {
            return 'env=testing';
        }

        return Arr::first($args, function ($value) {
            return Str::startsWith($value, '--env');
        });
    }

I have no idea, but the args that the Laravel returns when I'm using the PHPunit do not contain an --env. Including this if, I can force include this env and return the \App::environment() as testing.

Note:
Even though I'm setting < env name="APP_ENV" value="testing"/> on my phpunit.xml, I keep getting the App:environment() which the value that I set on .env file. That is the reason to include this if conditional.

January 24, 2017 at 00:00 / By Mauro Baptista / Laravel PHP

How test a custom validation on Laravel

On this post we went through the creation of custom validations, but how to test this validations?

On my approach, I like to create a Unit test, and add all my custom validations tests there. To test the even and odd number, I would write a simple test like that:

January 19, 2017 at 00:00 / By Mauro Baptista / Laravel PHP

How to add multiple custom validations

I had to create a custom validation to a project, so I've included on the AppProvider something like:


Validator::resolver(function ($translator, $data, $rules, $messages, $validator) {
    return new MyCustomValidator($translator, $data, $rules, $messages, $validator);
});

Ok. It works well! But then I had to include another custom validation, as a simple answer I've just added one more Validator::resolver on the provider, and ok!?! Hummm.. Houston we have a problem! Just the second one was running, the first one was ignored.

Googling it, I've come with this solution:

January 17, 2017 at 00:00 / By Mauro Baptista / Laravel PHP

Find Model Using Table Name

On the post about creating a custom validation using data from a different table, I hard-coded the Class Name, since I use the suggested names as standard, but maybe that's not your case.

If you want to find the Model only using the table name, you can use the following code:


public function getModelFromTable($table)
{
    foreach( get_declared_classes() as $class ) {
         if( is_subclass_of( $class, 'Illuminate\Database\Eloquent\Model' ) ) {
            $model = new $class;
            if ($model->getTable() === $table) {
                 return $class;
            }
        }
    }

    return false;
}

This code gets all declared classes and verify which one extends the Model class, then it compares the given table with the Model table.

When it found a match, it returns the class name. This way you need to instantiate the class by yourself!

January 12, 2017 at 00:00 / By Mauro Baptista / Laravel PHP

Custom Validation Using Data From a Different Table

You want to confirm a hotel booking, but you want to confirm that the room can fit the number of people on this booking.

The two tables that matter are Room and Booking, and you want to validate a value from Booking that will use an info from Room.

My solution was:

1. Create a custom validation extending the Validator class.


\Validator::extend('greather_than', 'App\Validation\ValidationController@greaterThan');
2. I expect to call this validations as:

'people' => ['required', 'integer', 'min:1', 'greather_than:rooms,max_people,'.request('room_id')],

Where greather_than is my custom validation, and it requires 3 parameters:

  • $parameters[0] -> the table where it will find the value
  • $parameters[1] -> the column on that table that will be used to compare
  • $parameters[2] -> the id from the table

Basically, I want to search the ID request('room_id') on table rooms and return the value from the column max_people.

3. On Validation Controller (I put it in a separate folder, because I'm using some Trait to handle my validations, but that is not important for this issue):


    /**
     * Rule to compare if a given value is greater than a value in
     * another database
     *
     * @param  \Illuminate\Http\\Request  $request
     * @return \Illuminate\Http\\Response
     */
    public function greaterThan($attribute, $value, $parameters, $validator) {
        
        if (count($parameters) != 3)
            throw new \InvalidArgumentException("Validation rule greather_than requires 3 parameters.");

        $className = '\App\' . studly_case(str_singular($parameters[0]));

        $model = new $className;
        $param = $model->find($parameters[2])->pluck($parameters[1])->first();

        return $value <= $param;
    }

Now it is ready to use, but it has a problem: The class namespace and the class name are hard-coded. I can use it because I follow the suggested names by Laravel, but maybe you need to make some changes to make it work.

Whoops, looks like something went wrong.

1/1 ErrorException in Filesystem.php line 111: file_put_contents(): Only 0 of 255 bytes written, possibly out of free disk space

  1. in Filesystem.php line 111
  2. at HandleExceptions->handleError('2', 'file_put_contents(): Only 0 of 255 bytes written, possibly out of free disk space', '/opt/bitnami/apps/carnou.com/blog/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php', '111', array('path' => '/opt/bitnami/apps/carnou.com/blog/storage/framework/sessions/5kuANdEXY8EsIXF6FVMnMdKbygO7wdXD3x3UCqP5', 'contents' => 'a:4:{s:6:"_token";s:40:"7BbbbRgHT2k6dBmhpwln9mPZ1IKdCcjbpR62tgqz";s:9:"_previous";a:1:{s:3:"url";s:17:"http://carnou.com";}s:9:"_sf2_meta";a:3:{s:1:"u";i:1519159872;s:1:"c";i:1519159872;s:1:"l";s:1:"0";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}}', 'lock' => true))
  3. at file_put_contents('/opt/bitnami/apps/carnou.com/blog/storage/framework/sessions/5kuANdEXY8EsIXF6FVMnMdKbygO7wdXD3x3UCqP5', 'a:4:{s:6:"_token";s:40:"7BbbbRgHT2k6dBmhpwln9mPZ1IKdCcjbpR62tgqz";s:9:"_previous";a:1:{s:3:"url";s:17:"http://carnou.com";}s:9:"_sf2_meta";a:3:{s:1:"u";i:1519159872;s:1:"c";i:1519159872;s:1:"l";s:1:"0";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}}', '2') in Filesystem.php line 111
  4. at Filesystem->put('/opt/bitnami/apps/carnou.com/blog/storage/framework/sessions/5kuANdEXY8EsIXF6FVMnMdKbygO7wdXD3x3UCqP5', 'a:4:{s:6:"_token";s:40:"7BbbbRgHT2k6dBmhpwln9mPZ1IKdCcjbpR62tgqz";s:9:"_previous";a:1:{s:3:"url";s:17:"http://carnou.com";}s:9:"_sf2_meta";a:3:{s:1:"u";i:1519159872;s:1:"c";i:1519159872;s:1:"l";s:1:"0";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}}', true) in FileSessionHandler.php line 83
  5. at FileSessionHandler->write('5kuANdEXY8EsIXF6FVMnMdKbygO7wdXD3x3UCqP5', 'a:4:{s:6:"_token";s:40:"7BbbbRgHT2k6dBmhpwln9mPZ1IKdCcjbpR62tgqz";s:9:"_previous";a:1:{s:3:"url";s:17:"http://carnou.com";}s:9:"_sf2_meta";a:3:{s:1:"u";i:1519159872;s:1:"c";i:1519159872;s:1:"l";s:1:"0";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}}') in Store.php line 263
  6. at Store->save() in StartSession.php line 88
  7. at StartSession->terminate(object(Request), object(Response)) in Kernel.php line 177
  8. at Kernel->terminate(object(Request), object(Response)) in index.php line 56