Skip to content
Robert Pustułka edited this page Sep 21, 2017 · 6 revisions

IO Abstraction API

This is a proposition for CakePHP Input/Output abstraction for Web and CLI environments.

Follow-up to #10202 comment and #11137 comments: 1 and 2

Idea

CakePHP does not provide a common pattern for business logic reusability (such as Laravel Command Bus). The business code is usually coupled to the controllers and/or shell commands which also act as a communication layer for Web/CLI. There are PHP libraries that help to seperate business logic into reusable classes (command pattern implementations such as Tactician) that can be integrated into CakePHP, but the framework itself does not provide the tools that would make this integration easier. The abstraction of the IO layer could help implement business classes that would work both in CLI and Web.

I propose to seperate communication/IO layer into Input and Output.

Example:

use Cake\Core\InputInterface;
use Cake\Core\OutputInterface;

//business logic
class LogicHandler
{
    public function _invoke(InputInterface $input, OutputInterface $output)
    {
        $data = $input->getData('key');
        //process data
        if ($ok) {
            $output->success('All good');
        } else {
            $output->error('Something went wrong');
        }
    }
}

//3.6 command class
class LogicCommand extends Command
{

    public function execute(ConsoleInput $input, ConsoleOutput $output) 
    { 
        $handler = new LogicHandler();
        $handler($input, $output);
    }
}

//controller
class LogicController extends Controller
{
    public function initialize()
    {
        $this->loadComponent('Input'); //implements InputInterface
        $this->loadComponent('Flash'); //implements OutputInterface
    }

    public function execute()
    {
        $handler = new LogicHandler();
        $handler($this->Input, $this->Flash);
    }
}

Input

This is a proposition for InputInterface:

namespace Cake\Core;

interface InputInterface
{
    public function getOption(string $key, $default = null);

    public function getAllOptions(): array;

    public function getData(string $key, $default = null);

    public function getAllData(): array;
}

Implementation

In pre 3.6 Shells the interface can be implemented by ConsoleIO class. getOption() method could translate to arguments and named parameters and getData() method could be implemented using a wrapper for ConsoleIO::in().

In 3.6 Commands the new ConsoleInput class would implement the interface.

In Web the new InputComponent can be introduced with wrappers for request methods that would implement the interface. getOption() method could retrieve options from request url query and getData() method would proxy to the request data.

Output

This is a proposition for OutputInterface:

namespace Cake\Core;

interface OutputInterface
{
    const INFO = 1;
    const SUCCESS = 2;
    const ERROR = 3;

    public function message(string $message, int $type = self::INFO);

    public function success(string $message);

    public function error(string $message);
}

Implementation:

In CLI the interface can be implemented by ConsoleIO class for pre 3.6 Shells and a new ConsoleInput class for +3.6 Commands.

In Web the interface can be implemented by FlashComponent.

Both the ConsoleIO and FlashComponent currently have methods with similar repsonsibility, so the implementation should be straightforward.

Clone this wiki locally