Passed
Pull Request — master (#59)
by
unknown
13:30
created

BaseController   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 18
eloc 51
dl 0
loc 101
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A prepareResponse() 0 18 6
B handle() 0 38 9
A process() 0 8 2
1
<?php
2
3
namespace App\LazyRendering\Http;
4
5
use Generator;
6
use Psr\Container\ContainerInterface as Container;
7
use Psr\Http\Message\ResponseFactoryInterface as ResponseFactory;
8
use Psr\Http\Message\ResponseInterface as Response;
9
use Psr\Http\Message\ServerRequestInterface as Request;
10
use Psr\Http\Message\StreamFactoryInterface;
11
use Psr\Http\Server\MiddlewareInterface;
12
use Psr\Http\Server\RequestHandlerInterface;
13
use Throwable;
14
use Yiisoft\Injector\Injector;
15
use Yiisoft\Router\UrlGeneratorInterface;
16
use Yiisoft\Widget\WidgetFactory;
17
18
abstract class BaseController implements MiddlewareInterface
19
{
20
    protected ResponseFactory $responseFactory;
21
    protected Request $request;
22
    protected UrlGeneratorInterface $urlGenerator;
23
    /** @var null|mixed Layout definition with method render() */
24
    protected $pageLayout = null;
25
    protected StreamFactoryInterface $streamFactory;
26
27
    private Container $container;
28
29
    /**
30
     * baseController constructor.
31
     * @param Container $container
32
     * @param mixed[]   $options
33
     */
34
    public function __construct(Container $container)
35
    {
36
        $this->container = $container;
37
        $this->responseFactory = $this->container->get(ResponseFactory::class);
38
        $this->urlGenerator = $this->container->get(UrlGeneratorInterface::class);
39
        $this->streamFactory = $this->container->get(StreamFactoryInterface::class);
40
        WidgetFactory::initialize($container);
41
    }
42
43
    /**
44
     * @param Request  $request
45
     * @param Response $response
46
     * @param array    $args
47
     * @return Response
48
     * @throws HttpException
49
     * @throws Throwable
50
     */
51
    public function process(Request $request, RequestHandlerInterface $handler): Response
52
    {
53
        # disable output buffering
54
        for ($j = ob_get_level(), $i = 0; $i < $j; ++$i) {
55
            ob_end_flush();
56
        }
57
58
        return $this->handle($request) ?? $handler->handle($request);
59
    }
60
61
    public function handle(Request $request): ?Response
62
    {
63
        $this->request = $request;
64
        $args = $request->getAttributes();
65
        $method = strtoupper($request->getMethod());
66
        $page = $args['page'] ?? 'index';
67
68
69
        $action = $args['action'] ?? $request->getParsedBody()['action'] ?? $request->getQueryParams()['action'] ?? null;
70
        # find action
71
        if ($action !== null or $method === 'POST') {
72
            $action = $action ?? $page;
73
            $method = 'action' . str_replace(' ', '', ucwords($action));
74
        } elseif ($method === 'GET') {
75
            $method = 'page' . str_replace(' ', '', ucwords($page));
76
        }
77
        if (!method_exists($this, $method)) {
78
            return null;
79
        }
80
        $data = (new Injector($this->container))->invoke([$this, $method]);
81
82
        $response = $data instanceof Response ? $data : $this->prepareResponse($data);
83
84
        // Force Buffering (classic mode)
85
        if (($this->request->getQueryParams()['forceBuffering'] ?? 0) === '1') {
86
            // Buffering from generator
87
            $content = $response->getBody()->getContents();
88
            $stream = $this->streamFactory->createStream($content);
89
            return $response->withBody($stream);
90
        } elseif (($this->request->getQueryParams()['forceBuffering'] ?? 0) === '2') {
91
            // Combined mode
92
            $stream = $response->getBody();
93
            if (!$stream instanceof GeneratorStream) {
94
                throw new \Exception('Combined mode not supported');
95
            }
96
            $stream->setReadMode(GeneratorStream::READ_MODE_FIRST_YIELD);
97
        }
98
        return $response;
99
    }
100
101
    protected function prepareResponse(iterable $page): Response
102
    {
103
        if (!$page instanceof Generator) {
104
            $page = (static function (iterable $iterable) {
105
                yield from $iterable;
106
            })($page);
107
        }
108
        // Add layout rendering
109
        if ($this->pageLayout !== null) {
110
            if (is_string($this->pageLayout)) {
111
                $this->pageLayout = $this->container->get($this->pageLayout);
112
            } elseif (!is_object($this->pageLayout) || !method_exists($this->pageLayout, 'render')) {
113
                throw new \RuntimeException('Bad Layout definition');
114
            }
115
            $page = (new Injector($this->container))->invoke([$this->pageLayout, 'render'], [$page, $this->request]);
116
        }
117
        $stream = new GeneratorStream($page);
118
        return $this->responseFactory->createResponse()->withBody($stream);
119
    }
120
}
121