An Introduction to CodefyPHP: A Domain-Driven Framework

An Introduction to CodefyPHP: A Domain-Driven Framework

A PHP Domain-Driven Framework for building complex applications with CQRS and Event Sourcing

What is CodefyPHP?

You might not have heard of a new framework that was released a few weeks ago called CodefyPHP. The framework was created specifically for one of my legacy projects that needs refactoring and would benefit from Domain-Driven Design. I released it to the world in the hope that others may find it beneficial as well.

As with any new library and project, naming things is always the most difficult. But when trying to think of a name, I wanted it to be meaningful and representative of its goal and mission. Therefore, I came up with CodefyPHP.

The name Codefy is a derivative of the word codify which means to arrange into a systematic code according to a plan or system. This is the purpose of CodefyPHP as it pertains to Domain-Driven Design, ubiquitous language and complex applications.

Codefy is not a full-stack framework such as the likes of Symfony, Codeigniter, Yii2, FuelPHP, or Laravel. Nevertheless, it contains components such as routing, database migrations, multiple PSR implementations, and templating. All the things you need to start building a project.

The Purpose of CodefyPHP

The philosophy of Codefy is that code should be systematized, maintainable, and follow OOP (Object-Oriented Programming). CodefyPHP tries not to be too opinionated, yet encourages best practices and coding standards by following Qubus Coding Standards. Nevertheless, you can use Codefy as you see fit. You can tap into all, some or none of the features and instead use the interfaces to build your implementations for a domain-driven project.

Highlighted Features

CodefyPHP has several noted features outside of the domain-driven scope. Let's take a look at some of them.

Codex CLI

When you use the skeleton package, you have access to Codex which allows you to generate migrations, controllers, middleware, service providers, start the dev server and more.

Here are some example commands:

❯ php codex serve //This command starts the dev server

❯ php codex stub:make Users_controller //Creates UsersController

❯ php codex password:hash 'jsx82kjsks9273js'
Your hashed password is: $2y$10$4A3iA5z.qyi6DZ5bibKXUujbqYdjH.QjpbO/lUDR9dalaN1IbEZtm 

❯ php codex ddd:ulid //Generates a random Ulid string

Database Migrations

Placing your database under version control is easy with CodefyPHP's database migrations:

❯ php codex migrate:generate CreateUsersTable
+f ./database/migrations/20230908035134_CreateUsersTable.php

❯ php codex migrate:status
+--------+------------------+-----------------------+                                                                                                                 
| Status | Migration ID     | Migration Name        |
+--------+------------------+-----------------------+
| down   |  20230908035134  | CreateUsersTable   |
+--------+------------------+-----------------------+

❯ php codex migrate
 == 20230908035134 CreateUsersTable migrating
 == 20230908035134 CreateUsersTable migrated 0.0090s

❯ php codex migrate:status
+--------+------------------+-----------------------+                                                                                                                  
| Status | Migration ID     | Migration Name        |
+--------+------------------+-----------------------+
| up     |  20230908035134  | CreateUsersTable   |
+--------+------------------+-----------------------+
//Example from migration file
    public function up(): void
    {
        if (!$this->schema()->hasTable(table: 'users')) {
            $this->schema()
                ->create(table: 'users', callback: function (CreateTable $table) {
                    $table->string(name: 'user_id', length: 36)
                        ->primary()
                        ->unique(name: 'userId');
                    $table->string(name: 'first_name', length: 191);
                    $table->string(name: 'last_name', length: 191);
                    $table->string(name: 'email', length: 191)
                        ->unique(name: 'email')
                        ->notNull();
                });
        }
    }

Dual Templating Engines

CodefyPHP comes with dual templating engines. The templating engine is called Scaffold, and there is a native engine and compiler engine. The native engine can be used if you are a PHP purist and only want to write PHP code. Here is an example:

<?php

$this->parent('main::layout');
$this->block('content', function ($params) {

?>
<article>
    <header>
        <h1><?=$this->esc($this->ucfirst($params['title']));?></h1>
    </header>
    <main>
        <?php foreach($params['paragraphs'] as $paragraph): ?>
            <p>
                <?=$this->esc($paragraph);?>
            </p>
        <?php endforeach; ?>
    </main>
</article>
<?php }); ?>



<html>
    <head>
        <title><?=$this->esc($title);?></title>
    </head>
    <body>
        <?=$this->block('content');?>
    </body>
</html>

The compiler engine is similar to that of Twig and Blade. Nevertheless, the framework includes adapters for a few other templating engines as well.

Test-Driven Development (TDD)

When you create a new project with the app starter (skeleton), it will include PestPHP which is great for test-driven development. One of the main advantages of TDD is the high test coverage by writing the tests for each feature before the implementation. While coding your implementation, you run your tests until all of them pass. It is a slow but rewarding process.

Along with the ones previously mentioned, a few other highlighted features are the dual query builders, sanitizing helpers, injector for bootstrapping, routing engine, and adapters for cookies, sessions and cache storage.

In Conclusion

But what if you are not interested in the framework, but the domain-driven stuff is all you need? Well, the framework is built on what's called the domain-driven core. The Domain-Driven Core includes the abstractions and interfaces you can use to build your domain-driven project without the dependencies found in the framework, and it includes a lot of tests you can check out. You can even integrate it into your Laravel, Symfony, or Codeigniter project.

If you are a PHP developer who loves Domain-Driven Design and Test-Driven Development as much as I do, then head on over to the project's GitHub page. After such a short time, it already has 7 stars.

Did you find this article valuable?

Support Joshua Parker by becoming a sponsor. Any amount is appreciated!