Using Model events with Eloquent in Slim PHP 4

Using Model events with Eloquent in Slim PHP 4

This article shows how to use Model events with Illuminate Database and Eloquent in Slim PHP version 4

I had some trouble making the Illuminate Database events working with Eloquent in Slim PHP 4. I had it working in Slim PHP version 3, but somehow a few thing has changed since.

For the explanations in this article you should know that the following dependencies are in the composer.json file:

  • "slim/slim": "^4" (4.7.1)
  • "illuminate/database": "^8" (v8.29.0),
  • "illuminate/events": "^8" (v8.29.0),

Furthermore it is important to know that the DB namespace defined in some namespaces has been defined in composer.json as:

"autoload": {
    "psr-4": {
        "App\\": "app/",
        "DB\\": "app/Db/"
    }
},

Container dependency

Since Slim PHP is not using services like Laravel does, it is important to add a depencency for the Capsule or Databasemanager to the dependency container used in your application. If you are not using dependencies, you can add this to the bootstrap of your application.

Add the following to the dependencies container:

use Illuminate\Database\Capsule\Manager as Capsule;
use App\Factory\DatabaseManagerFactory; // this is 

...

return [
    ... other dependencies

    Capsule::class => function (ContainerInterface $container) {
        $factory = new DatabaseManagerFactory($container);
        return new $factory->capsule;
    },

    ... more dependencies
];    

App\Factory\DatabaseManagerFactory

Create a file in the \app\Factory folder of your appliction with the following content:

<?php
namespace App\Factory;

use Illuminate\Container\Container;
use Illuminate\Database\Capsule\Manager;
use Illuminate\Events\Dispatcher;
use Psr\Container\ContainerInterface;

class DatabaseManagerFactory
{
    public $capsule;

    public function __construct(ContainerInterface $container)
    {
         // this would usually be in your dependency settings or on a safe place within 
         // your application. This is purely for explanatory reasons that is has been placed here

         $dbSettings = [
            'driver' => 'mysql',
            'host' => 'localhost',
            'database' => 'gateway',
            'username' => 'db_username',
            'password' => 'db_password',
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => ''
        ];

        $manager = new Manager;
        $manager->addConnection($dbSettings);

        $manager->getConnection()->enableQueryLog();

        $manager->setEventDispatcher(new Dispatcher(new Container()));

        $manager->setAsGlobal();
        $manager->bootEloquent();

        $this->capsule = $manager;
    }
}

Model example

In the following model I have defined the model and the events to dispatch:

protected $dispatchesEvents = [
    'deleting' => PincodeDeleting::class
];

In earlier versions of Eloquent this property was named events, but that doesn't work anymore. It has to be dispatchesEvents.

<?php

namespace DB\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

use DB\Events\PincodeDeleting;

class PincodeModel extends Model
{
    protected $table = 'gateway_pincode';

    use SoftDeletes;

    protected $fillable = [
        'ip_address', 'pincode', 'token', 'validated'
    ];

    protected $dispatchesEvents = [
        'deleting' => PincodeDeleting::class
    ];
}

Defining the 'deleting' event class

The deleting event is a class that has been placed in \app\Db\Events\PincodeDeleting.php which is namespaced as DB\Events

<?php
namespace DB\Events;

use DB\Models\PincodeModel;

class PincodeDeleting
{
    public function __construct(PincodeModel $Pincode)
    {
        $Pincode->validated = 1;
        $Pincode->update();
    }

}

Using this in an example

In the following example a function is finding the record that has to be deleted. Then on this record, if found, a delete() is executed.

function deletePincodeRecord($data)
{
    $record = PincodeModel::where('pincode', $data['pincode'])
        ->where('token', $data['token'])
        ->firstOrFail();

    $record->delete();
}

When the record is found and deleted the result will be that the validated field will have the value of 1, even if we haven't defined it in our deletePincodeRecord.

Following code won't trigger your custom events !!!

function deletePincodeRecord($data)
{
    PincodeModel::where('pincode', $data['pincode'])
        ->where('token', $data['token'])
        ->delete();
}

This doesn't work if you want to trigger your custom events. It will however soft delete the record, but it won't execute the deleting event. The reason is that the delete is executed on a chained static class function. Therefor will not dispatch any custom events, simply because there is no model object to instantiate the events.

That is why you have to create the model object from a selection and on this object execute the database table mutations to trigger the custom events as well.

Links

If you are a novice in Slim PHP or need a valuable resource of information I can highly recommend this free online tutorial from Daniel Opitz.

I have bought his e-book, which is regularly updated and I must admit that I am using it a lot as reference. I have no business interest in this recommendation, neither do I know Davdid Opitz personally.

More from same category