/php-framework

Greg Framework provides a lightweight engine for fast creating powerful apps.

Primary LanguagePHPMIT LicenseMIT

Greg PHP Framework

StyleCI Build Status Total Downloads Latest Stable Version Latest Unstable Version License

Greg Framework provides a lightweight engine for fast creating powerful apps.

Greg PHP Application is a prepared and deploy-ready application that you can use to achieve maximum productivity of that framework.

Table of Contents

Requirements

  • PHP Version ^7.1

Installation

composer require greg-md/php-framework

How It Works

All you need is to instantiate a new Application and run it from your chosen environment.

<?php

require_once __DIR__ . '/vendor/autoload.php';

$app = new \Greg\Framework\Application();

$app->run(function () {
    echo 'Hello World!';
});

You can also construct the Application with custom Config and an IoC Container.

<?php

require_once __DIR__ . '/vendor/autoload.php';

$config = new \Greg\Framework\Config([
    'name' => 'John',
]);

$ioc = new \Greg\DependencyInjection\IoCContainer();

$ioc->register($config);

$app = new \Greg\Framework\Application($config, $ioc);

$app->run(function (\Greg\Framework\Config $config) {
    echo 'Hello ' . $config['name'] . '!';
});

Yeah, the previous example practically doesn't do nothing because you didn't use any features. But let's look on the next examples when we want to create an Application that should be run in Browser or in Console.

Running for HTTP Requests

For HTTP Requests we can use the builtin \Greg\Framework\Http\HttpKernel that is working with HTTP Routes.

In the next example we will instantiate the kernel and create a router that will say hello.

Providing the Application and Router to the kernel is optional. If you will not provide them, the kernel will instantiate them by itself.

$httpKernel = new \Greg\Framework\Http\HttpKernel($app);

$router = $httpKernel->router();

$router->get('/', function() {
    return 'Hello World!';
});

$httpResponse = $httpKernel->run();

$httpResponse->send();

Running for Console Requests

For Console Requests we can use the builtin \Greg\Framework\Console\ConsoleKernel that is working with Symfony Console Component.

In the next example we will instantiate the kernel and create a command that will say hello.

Providing the Application and Symfony Console Application to the kernel is optional. If you will not provide them, the kernel will instantiate them by itself.

$consoleKernel = new \Greg\Framework\Console\ConsoleKernel($app);

$helloCommand = new Symfony\Component\Console\Command\Command();
$helloCommand->setName('hello');
$helloCommand->setDescription('Say Hello.');
$helloCommand->setCode(function(Symfony\Component\Console\Input\InputInterface $input, Symfony\Component\Console\Output\OutputInterface $output) {
    $output->writeln('Hello World!');
});

$consoleKernel->addCommand($helloCommand);

$responseCode = $consoleKernel->run();

exit($responseCode);

Config

You can define application configurations using the \Greg\Framework\Config class. It uses the ArrayAccessTrait and can act as an array.

$config = new \Greg\Framework\Config([
    'foo' => 'FOO',
    'bar' => 'BAR',
    'db' => [
        'username' => 'foousername',
        'password' => 'foosecret',
    ],
]);

$config->get('foo'); // result: 'FOO'
// or
$config['bar']; // result: 'BAR'

$config->getIndex('db.username'); // result: 'foousername'
// or
$config['db.password']; // result: 'foosecret'

Bootstrapping

To keep the consistency of the application, you can define/register/load it's components into the bootstrap classes.

A bootstrap class should be an instance of \Greg\Framework\BootstrapStrategy that requires the boot method.

class AppBootstrap extends \Greg\Framework\BootstrapAbstract
{
    public function boot(\Greg\Framework\Application $app)
    {
        $app->inject('redis.client', function() {
            return new Redis();
        });
    }
}

For a better experience you can extend the \Greg\Framework\BootstrapAbstract class. It will allow you to define multiple boots in a specific order. Each method in this class that starts with boot in a lowerCamelCase format will be called.

class AppBootstrap extends \Greg\Framework\BootstrapAbstract
{
    public function bootFoo()
    { 
        $this->dependsOn('redis'); // Call `bootRedis` method first.

        $redis = $this->app()->get('redis.client');

        // ...
    }

    public function bootRedis()
    {
        $redis = new Redis();

        $this->app()->inject('redis.client', $redis);
    }
}

Next, you have to add the bootstrap to the application.

$app->addBootstrap(new AppBootstrap());

The same way you can define and create bootstraps only for the HTTP and Console kernels, using the Greg\Framework\Console\BootstrapStrategy and Greg\Framework\Http\BootstrapStrategy strategies, or extending the Greg\Framework\Console\BootstrapAbstract and Greg\Framework\Http\BootstrapAbstract classes.

$httpKernel->addBootstrap(new AppHttpBootstrap());
$consoleKernel->addBootstrap(new AppConsoleBootstrap());

Events

You can define and fire events in your application.

Listeners

Listeners could be a callable, an object or a class name.

$app->listen('my.event', function() {
    // do the bussiness logic...
});

Objects and class names requires the handle method that will be fired.

class MyListener
{
    public function handle() {
        // do the bussiness logic...
    }
}
$app->listen('my.event', MyListener::class);
// or
$app->listen('my.event', new MyListener());

Fire Events

You can fire events with or without custom arguments.

$app->fire('my.event');

// or

$user = new User();

$app->fire('my.event', $user);

// or

$app->fireArgs('my.event', [new User()]);

Events Objects

Following the best practices, you can define events as objects.

Let say we have a LoginEvent class that requires an User.

class LoginEvent
{
    private $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }
    
    public function user()
    {
        return $this->user;
    }
}

You can define listeners using the class name as event name.

$app->listen(LoginEvent::class, function(LoginEvent $event) {
    // do the bussiness logic...
});

And fire event in application.

$app->event(new LoginEvent($user));
// or
$app->fire(LoginEvent::class, ...[new LoginEvent($user)]);

Builtin Events

Application

  • \Greg\Framework\Application::EVENT_RUN - Fired before the application is ran;
  • \Greg\Framework\Application::EVENT_FINISHED - Fired after the application is ran.

HTTP Kernel

  • \Greg\Framework\Http\HttpKernel::EVENT_RUN - Fired before the kernel is ran;
  • \Greg\Framework\Http\HttpKernel::EVENT_DISPATCHING - Fired before the route is dispatched;
  • \Greg\Framework\Http\HttpKernel::EVENT_DISPATCHED - Fired after the route is dispatched;
  • \Greg\Framework\Http\HttpKernel::EVENT_FINISHED - Fired after the kernel is ran.

Console Kernel

  • \Greg\Framework\Console\ConsoleKernel::EVENT_RUN - Fired before the kernel is ran;
  • \Greg\Framework\Console\ConsoleKernel::EVENT_FINISHED - Fired v the kernel is ran.

License

MIT © Grigorii Duca

Huuuge Quote

I fear not the man who has practiced 10,000 programming languages once, but I fear the man who has practiced one programming language 10,000 times. © #horrorsquad