Sometimes you just need to drop to a command line and explore your application interactively. A REPL will allow you to do just that by providing an interactive cli that knows about your application.

What is a REPL?

A REPL is basically a console for your application. It stands for Read - Eval - Print loop, meaning that it takes the commands you give it, evaluates the code, and outputs the result. This means that most anything that you can do in your application you can explore in the REPL.

What is it good for?

I find these especially helpful on remote servers to log in and easily explore the data using CodeIgniter commands that I'm already familiar with. You can easily interact with the models in your application to investigate bugs, fix small data errors, etc.

In this case, though, we're going to integrate the excellent PsySh into our application, which can actually do a lot more than just the example I provided above. Being able to interact with your models is the focus of this simple integration, though.

Create the Command

Since this runs from the command line, we first need to create a new command that will allow us to enter the repl.

php spark make:command Repl

Open up the new file in your editor. You can name the command whatever you'd like, but we'll keep it simple for this example and just call it repl. For the run() method we will modify it like:

use App\Libraries\Repl\Caster;
use Psy\Configuration;
use Psy\Shell;

class Repl extends BaseCommand
{
    //

    public function run(array $params)
    {
        $config = new Configuration([
            'updateCheck' => 'never',
            'usePcntl'    => false,
            'casters'     => $this->getCasters(),
        ]);

        // Psysh Shell instance
        $shell = new Shell($config);

        try {
            $shell->run();
        } catch (\Exception $e) {
            CLI::error($e->getMessage());
            exit(1);
        }
    }

    private function getCasters()
    {
        if (class_exists(Entity::class)) {
            return [Entity::class => Caster::class .'::castEntity'];
        }
    }

The first thing we do is to set up our PsySh configuration. The only interesting thing here though is the casters attribute. Casters are methods that can be called statically to format the element and return it as an array to display to the user. In this case, we're just going to implement one for Entities so you can view your data when you get them from the database.

The casters array maps the class name that you want to display with a static method that will take an instance of that class and return the information to display to the user on the command line. In this case, we're saying we want any class that extends from -- or is an -- Entity and we want to use a new class/method that we're going to create to handle that.

You could have easily just included that one line from getCasters() method above, but we might as well prepare for the future and keep it clean in case we want to add more casters along the way.

The next thing the script does is to get an instance of PsySh, and then run() it, which does all of the real work for us. At this point you almost have a working repl shell. If you comment out the casters line in the configuration you should be able to run it at this point.

php spark repl

Creating the Casters

The final thing is to create the actual Entity caster functionality. This is very simple, but again I've tried to future-proof it a bit and keep it organized. You were probably paying close attention above and noticed that we've already defined where the file should be located: app/Libraries/Repl/Caster.php. Create that file now and add this very simple class:

<?php

namespace App\Libraries\Repl;

class Caster
{
    public static function castEntity($entity)
    {
        return $entity->toArray();
    }
}

All this is doing is creating the static method that we told it to use above. The method takes a single argument: the Entity it should format. And we're just returning the result of the toArray() method for now. You could always customize it further if you want. You can use this file to hold any casters you find useful along the way also.

Now everything should be hooked up and working correctly. In your command line you can drop into the repl and explore:

php spark repl

CodeIgniter v4.4.5 Command Line Tool - Server Time: 2024-02-16 00:27:53 UTC-06:00

Psy Shell v0.12.0 (PHP 8.1.26 — cli) by Justin Hileman

> ENVIRONMENT 
"development"

> $u = model('UserModel')->find(1)
= App\Entities\User {#3982
    +id: "1",
    +username: "admin",
    +first_name: "Lonnie",
    +last_name: "Ezell",
    +avatar: null,
    +status: null,
    +status_message: null,
    +active: "0",
    +last_active: "2024-02-07 00:20:42",
    +created_at: "2024-01-09 16:12:52",
    +updated_at: "2024-01-31 23:56:46",
    +deleted_at: null,
  }

> $u->first_name
= "Lonnie"

While this is a very basic integration it is already quite powerful and allows you to explore quite a bit. I'd love to hear if you implement something like this and what other features you find helpful. Then maybe we should create a package for this that collects everything we find useful into one fantastic, shareable, package.