rougin/basilisk

A project skeleton for Slytherin.

v0.1.0 2024-09-06 01:01 UTC

This package is auto-updated.

Last update: 2024-10-09 07:39:26 UTC


README

Latest Version on Packagist Software License Build Status Coverage Status Total Downloads

Basilisk is a skeleton project made for Slytherin which provides a code structure that is based on my experiences creating projects using Slytherin as it's framework. The said code structure should be easy to understand and be based on SOLID principles.

Installation

Create a new project using Basilisk via Composer:

$ composer create-project rougin/basilisk "hogwarts"

What's inside?

Directory Structure

Note

The following directory names below are only the preferred names based on my experience building projects under Slytherin. But they can be easily be extended or removed as Slytherin not does not conform to those said preferences.

src/
├─ Checks/
├─ Depots/
├─ Models/
├─ Phinx/
│  ├─ Scripts/
│  ├─ Seeders/
├─ Routes/
├─ Scripts/

Checks

src/
├─ Checks/

This directory contains classes that are used for validation. Those classes may be extended to the Check class of Weasley:

namespace App\Checks;

use Rougin\Weasley\Check;

class UserCheck extends Check
{
    /**
     * @var array<string, string>
     */
    protected $labels =
    [
        'name' => 'Name',
        'email' => 'Email',
    ];

    /**
     * @var array<string, string>
     */
    protected $rules =
    [
        'name' => 'required',
        'email' => 'required|email',
    ];
}

Depots

src/
├─ Depots/

The main directory that should contain the logic of a project:

namespace App\Depots;

use App\Models\User;

class UserDepot
{
    /**
     * @var \App\Models\User
     */
    protected $user;

    /**
     * @param \App\Models\User $user
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * @return array<string, mixed>[]
     */
    public function all()
    {
        $result = $this->user->all();

        $items = array();

        foreach ($result as $item)
        {
            $row = ['id' => $item->id];

            $row['name'] = $item->name;

            $row['email'] = $item->email;

            $items[] = $row;
        }

        return (array) $items;
    }
}

Note

Prior in using depots, or may be best known as the Repository pattern, I implemented most of the logic in the Routes or Models directories. However, it presents a challenge to me in organizing their code. With using depots, I can reuse the same logic in to either Routes (for receiving user request) or in Scripts directory (for handling terminal-based actions).

Models

src/
├─ Models/

It is the directory where for storing the models (for Eloquent) or entities (if using Doctrine). The classes in this directory should represent a database table (e.g., if having a users table, it should be represented as User class):

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * @var string[]
     */
    protected $fillable =
    [
        'name',
        'password',
        'email',
    ];

    /**
     * @var string[]
     */
    protected $hidden =
    [
        'password'
    ];

    /**
     * @var string
     */
    protected $table = 'users';
}

Phinx

src/
├─ Phinx/
│  ├─ Scripts/
│  ├─ Seeders/

This directory is for the storage of related files for the Phinx package. The Scripts directory contains the generated database migrations while the Seeders directory must contain the database seeders.

// src/Phinx/Scripts/20171012020230_create_users_table.php

use Phinx\Migration\AbstractMigration;

class CreateUsersTable extends AbstractMigration
{
    public function change(): void
    {
        $properties = ['id' => false, 'primary_key' => ['id']];

        $table = $this->table('users', $properties);

        $table->addColumn('id', 'integer', ['limit' => 10, 'identity' => true]);
        $table->addColumn('name', 'string', ['limit' => 200]);
        $table->addColumn('email', 'string', ['limit' => 200]);
        $table->addColumn('password', 'string', ['limit' => 500]);
        $table->addColumn('created_at', 'datetime');
        $table->addColumn('updated_at', 'datetime', ['null' => true]);

        $table->create();
    }
}
// src/Phinx/Seeders/UserSeeder.php

use Phinx\Seed\AbstractSeed;

class UserSeeder extends AbstractSeed
{
    protected $items =
    [
        ['name' => 'Harry Jonathans Potter', 'email' => 'hjpotter@hogwarts.co.uk'],
        ['name' => 'Hermione Jane Granger', 'email' => 'hjgranger@hogwarts.co.uk'],
        ['name' => 'Ronald Bilius Weasley', 'email' => 'rbweasley@hogwarts.co.uk'],
    ];

    public function run(): void
    {
        $data = array();

        foreach ($this->items as $item)
        {
            $item['created_at'] = date('Y-m-d H:i:s');

            $data[] = $item;
        }

        $this->table('users')->insert($data)->save();
    }
}

The said directory will be used for running the database migrations and seeders. To migrate the database scripts, kindly run the migrate command:

$ vendor/bin/phinx migrate -c app/config/phinx.php

Note

Before running scripts from Phinx, kindly update the database credentials first in .env:

$ cp .env.example .env

The seed:run command can be used for populating data in a database:

$ vendor/bin/phinx seed:run -c app/config/phinx.php

Note

The command above will load the seeders in alphabetical order.

Routes

src/
├─ Routes/

The gateway of the project wherein the routes are stored. The said class can call or instantiate the classes found from the previously mentioned directories.

namespace App\Routes;

use Rougin\Slytherin\Template\RendererInterface;

class Hello
{
    /**
     * Returns the "Hello, Muggle!" text.
     *
     * @return string
     */
    public function index(RendererInterface $renderer)
    {
        return $renderer->render('index');
    }
}

Note

In other frameworks, Routes is commonly known as Controllers.

Scripts

src/
├─ Scripts/

The directory where the scripts are stored. These scripts can be executed directly using the php command in the terminal:

// src/Scripts/HelloWorld.php

echo 'Hello world!';
$ php src/Scripts/HelloWorld.php

Hello world!

Running the application

The PHP's built-in web server can be used for running the project during development:

$ php -S localhost:8000 -t app/public

Then open a web browser and proceed to go to http://localhost:8000.

Changelog

Please see CHANGELOG for more information what has changed recently.

Testing

$ vendor/bin/phpunit

License

The MIT License (MIT). Please see LICENSE for more information.