Passed
Pull Request — master (#59)
by
unknown
12:23
created

StreamedController   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 15
eloc 80
dl 0
loc 134
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A pageDirectEchoWithoutBufferingBetweenYields() 0 15 3
A pagePageWithEchoAndOutputBufferingBetweenYields() 0 9 3
A pageIndex() 0 26 4
A pageAllPosts() 0 23 2
A pageAllPostsWithInterval() 0 6 1
A pageFewPostsAndError() 0 16 2
1
<?php
2
3
namespace App\LazyRendering\Http;
4
5
use App\Blog\Entity\Post;
6
use App\Blog\Post\PostRepository;
7
use App\Blog\Widget\PostCard;
8
use App\LazyRendering\View\MainLayout;
9
use Cycle\ORM\ORMInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use RuntimeException;
12
use Yiisoft\Html\Html;
13
14
class StreamedController extends BaseController
15
{
16
    public const PAGE_ROUTE   = 'streamed';
17
    public const ACTION_ROUTE = 'streamedAction';
18
19
    protected $pageLayout = MainLayout::class;
20
21
    public function pageIndex(): iterable
22
    {
23
        foreach (get_class_methods($this) as $method) {
24
            $isPage = strpos($method, 'page') === 0;
25
            if (!$isPage || $method === __FUNCTION__) {
26
                continue;
27
            }
28
            $page =  substr($method, 4);
29
            $pageName = ltrim(preg_replace('/([A-Z][a-z])/u', ' $1', $page));
30
31
            yield '<li>'
32
                . "{$pageName} :: "
33
                . Html::a('Lazy', $this->urlGenerator->generate(static::PAGE_ROUTE, ['page' => $page]))
34
                . ' :: '
35
                . Html::a(
36
                    'Classic Mode',
37
                    $this->urlGenerator->generate(static::PAGE_ROUTE, ['page' => $page, 'forceBuffering' => 1])
38
                )
39
                . ' :: '
40
                . Html::a(
41
                    'Combined Mode',
42
                    $this->urlGenerator->generate(static::PAGE_ROUTE, ['page' => $page, 'forceBuffering' => 2])
43
                )
44
                . '</li>';
45
        } ?>
46
        <div class="mt-5">
47
            <p>
48
                <b>Lazy Mode</b> - deferred rendering pages. Page renders as it emits.
49
            </p>
50
            <p>
51
                <b>Classic Mode</b> (imitation) - page is rendered and buffered before the response object is sent back
52
                via pipeline.
53
            </p>
54
            <p>
55
                <b>Combined Mode</b> - deferred rendering pages. First yielded value will be emitted immediately,
56
                the rest of the contents will be buffered and emitted in one piece
57
            </p>
58
            <p>
59
                <a href="https://github.com/yiisoft/yii-demo/pull/59">About this on GitHub</a>
60
            </p>
61
        </div>
62
        <?php
63
    }
64
65
    /**
66
     * All posts
67
     */
68
    public function pageAllPosts(ORMInterface $orm, int $interval = 0): iterable
69
    {
70
        yield '<h1>Streamed out</h1>';
71
        $t1 = microtime(true);
72
        /** @var PostRepository $postRepo */
73
        $postRepo = $orm->getRepository(Post::class);
74
        $pages = $postRepo->findAllPreloaded();
75
        yield '<h2>Total posts: ' . $pages->count() . '</h2>';
76
        $t2 = microtime(true);
77
        yield '<h5>Time to a count query: ' . intval(1_000_000 * ($t2 - $t1)) . 'μs</h5>';
0 ignored issues
show
Bug introduced by
The constant App\LazyRendering\Http\1_000_000 was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
78
79
        $card = PostCard::widget();
80
        $t3 = microtime(true);
81
82
        # type $stream->read() instead of $stream->getIterator()
83
        # to disable lazy loading and load all posts in buffer:
84
        /** @var Post $post */
85
        foreach ($pages->getIterator() as $post) {
86
            $t4 = microtime(true);
87
            yield (string)$card->post($post)
0 ignored issues
show
Bug introduced by
The method post() does not exist on Yiisoft\Widget\Widget. It seems like you code against a sub-type of Yiisoft\Widget\Widget such as App\Blog\Widget\PostCard. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

87
            yield (string)$card->/** @scrutinizer ignore-call */ post($post)
Loading history...
88
                . '<h5>Getting item time: ' . intval(1_000_000 * ($t4 - $t3)) . 'μs</h5>';
89
            usleep($interval);
90
            $t3 = microtime(true);
91
        }
92
    }
93
94
    public function pageAllPostsWithInterval(ORMInterface $orm): iterable
95
    {
96
        # disable time limit
97
        set_time_limit(0);
98
99
        return $this->pageAllPosts($orm, 150_000);
0 ignored issues
show
Bug introduced by
The constant App\LazyRendering\Http\150_000 was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
100
    }
101
102
    public function pageFewPostsAndError(ORMInterface $orm): iterable
103
    {
104
        yield '<h1>Streamed out with error after 5 posts</h1>';
105
        /** @var PostRepository $postRepo */
106
        $postRepo = $orm->getRepository(Post::class);
107
108
        $pages = $postRepo->findAllPreloaded()->withLimit(5);
109
        yield '<h2>Total posts: ' . $pages->count() . '</h2>';
110
111
        $card = PostCard::widget();
112
        /** @var Post $post */
113
        foreach ($pages->read() as $post) {
114
            yield (string)$card->post($post);
115
        }
116
117
        throw new RuntimeException('Just error');
118
    }
119
120
    public function pagePageWithEchoAndOutputBufferingBetweenYields(): iterable
121
    {
122
        yield '<h1>Page With Echo And Output Buffering Between Yields</h1>';
123
124
        for ($i = 1, $j = 20; $i < $j; ++$i) {
125
            if ($i % 2 === 0) {
126
                yield "<div>{$i} - yielded</div>";
127
            } else {
128
                echo "<div>{$i} - <b>printed</b></div>";
129
            }
130
        }
131
    }
132
133
    public function pageDirectEchoWithoutBufferingBetweenYields(): ResponseInterface
134
    {
135
        $generator = function () {
136
            echo '<h1>Direct Echo Without Buffering Between Yields</h1>';
137
138
            for ($i = 1, $j = 20; $i < $j; ++$i) {
139
                if ($i % 2 === 0) {
140
                    yield "<div>{$i} - yielded</div>";
141
                } else {
142
                    echo "<div>{$i} - <b>printed</b></div>";
143
                }
144
            }
145
        };
146
        $stream = new GeneratorStream($generator());
147
        return $this->responseFactory->createResponse()->withBody($stream);
148
    }
149
}
150