Passed
Pull Request — master (#59)
by Alexander
26:34 queued 11:31
created

StreamedController::pageAllPosts()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 23
rs 9.7666
c 0
b 0
f 0
cc 2
nc 2
nop 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 ROUTE_NAME = 'lazy-render';
17
18
    protected $pageLayout = MainLayout::class;
19
20
    public function pageIndex(): iterable
21
    {
22
        foreach (get_class_methods($this) as $method) {
23
            $isPage = strpos($method, 'page') === 0;
24
            if (!$isPage || $method === __FUNCTION__) {
25
                continue;
26
            }
27
            $page =  substr($method, 4);
28
            $pageName = ltrim(preg_replace('/([A-Z][a-z])/u', ' $1', $page));
29
30
            yield '<li>'
31
                . "{$pageName} :: "
32
                . Html::a('Lazy', $this->urlGenerator->generate(static::ROUTE_NAME, ['page' => $page]))
33
                . ' :: '
34
                . Html::a(
35
                    'Classic Mode',
36
                    $this->urlGenerator->generate(static::ROUTE_NAME, ['page' => $page, 'forceBuffering' => 1])
37
                )
38
                . ' :: '
39
                . Html::a(
40
                    'Combined Mode',
41
                    $this->urlGenerator->generate(static::ROUTE_NAME, ['page' => $page, 'forceBuffering' => 2])
42
                )
43
                . '</li>';
44
        } ?>
45
        <div class="mt-5">
46
            <p>
47
                <b>Lazy Mode</b> - deferred rendering pages. Page renders as it emits.
48
            </p>
49
            <p>
50
                <b>Classic Mode</b> (imitation) - page is rendered and buffered before the response object is sent back
51
                via pipeline.
52
            </p>
53
            <p>
54
                <b>Combined Mode</b> - deferred rendering pages. First yielded value will be emitted immediately,
55
                the rest of the contents will be buffered and emitted in one piece
56
            </p>
57
            <p>
58
                <a href="https://github.com/yiisoft/yii-demo/pull/59">About this on GitHub</a>
59
            </p>
60
        </div>
61
        <?php
62
    }
63
64
    public function pageAllPosts(ORMInterface $orm, int $interval = 0): iterable
65
    {
66
        yield '<h1>Streamed out</h1>';
67
        $t1 = microtime(true);
68
        /** @var PostRepository $postRepo */
69
        $postRepo = $orm->getRepository(Post::class);
70
        $pages = $postRepo->findAllPreloaded();
71
        yield '<h2>Total posts: ' . $pages->count() . '</h2>';
72
        $t2 = microtime(true);
73
        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...
74
75
        $card = PostCard::widget();
76
        $t3 = microtime(true);
77
78
        # type $stream->read() instead of $stream->getIterator()
79
        # to disable lazy loading and load all posts in buffer:
80
        /** @var Post $post */
81
        foreach ($pages->getIterator() as $post) {
82
            $t4 = microtime(true);
83
            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

83
            yield (string)$card->/** @scrutinizer ignore-call */ post($post)
Loading history...
84
                . '<h5>Getting item time: ' . (int)(1_000_000 * ($t4 - $t3)) . 'μs</h5>';
85
            usleep($interval);
86
            $t3 = microtime(true);
87
        }
88
    }
89
90
    public function pageAllPostsWithInterval(ORMInterface $orm): iterable
91
    {
92
        # disable time limit
93
        set_time_limit(0);
94
95
        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...
96
    }
97
98
    public function pageFewPostsAndError(ORMInterface $orm): iterable
99
    {
100
        yield '<h1>Streamed out with error after 3 posts</h1>';
101
        /** @var PostRepository $postRepo */
102
        $postRepo = $orm->getRepository(Post::class);
103
104
        $pages = $postRepo->findAllPreloaded()->withLimit(3);
105
        yield '<h2>Total posts: ' . $pages->count() . '</h2>';
106
107
        $card = PostCard::widget();
108
        /** @var Post $post */
109
        foreach ($pages->read() as $post) {
110
            yield (string)$card->post($post);
111
        }
112
113
        throw new RuntimeException('Just error');
114
    }
115
116
    public function pagePageWithEchoAndOutputBufferingBetweenYields(): iterable
117
    {
118
        yield '<h1>Page With Echo And Output Buffering Between Yields</h1>';
119
120
        for ($i = 1, $j = 20; $i < $j; ++$i) {
121
            if ($i % 2 === 0) {
122
                yield "<div>{$i} - yielded</div>";
123
            } else {
124
                echo "<div>{$i} - <b>printed</b></div>";
125
            }
126
        }
127
    }
128
129
    public function pageDirectEchoWithoutBufferingBetweenYields(): ResponseInterface
130
    {
131
        $generator = static function () {
132
            echo '<h1>Direct Echo Without Buffering Between Yields</h1>';
133
134
            for ($i = 1, $j = 20; $i < $j; ++$i) {
135
                if ($i % 2 === 0) {
136
                    yield "<div>{$i} - yielded</div>";
137
                } else {
138
                    echo "<div>{$i} - <b>printed</b></div>";
139
                }
140
            }
141
        };
142
        $stream = new GeneratorStream($generator());
143
        return $this->responseFactory->createResponse()->withBody($stream);
144
    }
145
}
146