DynamicEchoService::buildHtmlStack()   A
last analyzed

Complexity

Conditions 5
Paths 16

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
c 1
b 0
f 0
dl 0
loc 20
ccs 0
cts 11
cp 0
rs 9.6111
cc 5
nc 16
nop 2
crap 30
1
<?php
2
3
namespace MallardDuck\DynamicEcho;
4
5
use MallardDuck\DynamicEcho\Collections\{
6
    ChannelEventCollection,
7
    ChannelAwareEventCollection
8
};
9
use MallardDuck\DynamicEcho\Loader\LoadedEventDTO;
10
use MallardDuck\DynamicEcho\ScriptGenerator\{
11
    ScriptGenerator,
12
    ScriptNodeBuilder
13
};
14
15
class DynamicEchoService
16
{
17
    /**
18
     * @var ChannelManager
19
     */
20
    private ChannelManager $channelManager;
21
22
    /**
23
     * @var ScriptGenerator
24
     */
25
    private ScriptGenerator $scriptGenerator;
26
27 1
    public function __construct(
28
        ChannelManager $channelManager,
29
        ScriptGenerator $scriptGenerator
30
    ) {
31 1
        $this->channelManager = $channelManager;
32 1
        $this->scriptGenerator = $scriptGenerator;
33 1
    }
34
35
    public function context(): string
36
    {
37
        $context = $this->compiledJSContext();
38
        $html = $this->buildHtmlStack($context, ucfirst(__FUNCTION__));
39
40
        return implode("\n", $html);
41
    }
42
43
    /**
44
     * Internally compile the necessary JS context for the current Request/User.
45
     *
46
     * This method calls on the ChannelManager to fetch channels and events that need to be registered.
47
     * Then it pushes the equivalent ScriptNodes into the generator and creates the JS listeners.
48
     *
49
     * @return string
50
     */
51
    protected function compiledJSContext(): string
52
    {
53
        $warning = null;
54
55
        // TODO: Figure out what a "GenericContextNode" might look like, so I can push the "active: false" variable in.
56
        /**
57
         * @var ChannelEventCollection $channelGroup
58
         */
59
        foreach ($this->channelManager->getChannelEventCollection() as $channelName => $channelGroup) {
60
            $channelContext = $this->resolveChannelContextBindings($channelGroup->getChannelContextBindingCallback());
61
62
            $this->scriptGenerator->pushContextNode(ScriptNodeBuilder::getChannelContextNode(
63
                $channelGroup->getChannelJsVarKey(),
64
                $channelContext
65
            ));
66
        }
67
68
69
        $generatedContext = $this->scriptGenerator->getRootContext();
70
71
        return view('dynamicEcho::context', compact('warning', 'generatedContext'))->render();
0 ignored issues
show
Bug Best Practice introduced by
The expression return view('dynamicEcho...tedContext'))->render() could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
72
    }
73
74
    private function resolveChannelContextBindings($callback): array
75
    {
76
        return $callback(request());
77
    }
78
79
    // NOTE: Ideally the static content could be "compiled" more consistently to a cache.
80
    // CONT: Then the dynamic ones would just be injected to the page for each user's request.
81
    public function scripts(): string
82
    {
83
        $scripts = $this->compiledJSScripts();
84
        $html = $this->buildHtmlStack($scripts, ucfirst(__FUNCTION__));
85
86
        return implode("\n", $html);
87
    }
88
89
    /**
90
     * Internally compile the necessary JS code to subscribe to channels and events.
91
     *
92
     * This method calls on the ChannelManager to fetch channels and events that need to be registered.
93
     * Then it pushes the equivalent ScriptNodes into the generator and creates the JS listeners.
94
     *
95
     * @return string
96
     */
97
    protected function compiledJSScripts(): string
98
    {
99
        /**
100
         * @var ChannelEventCollection $channelGroup
101
         */
102
        foreach ($this->channelManager->getChannelEventCollection() as $channelName => $channelGroup) {
103
            // Push the channel subscription in first...
104
            $this->scriptGenerator->pushScriptNode(ScriptNodeBuilder::getPrivateChannelNode(
105
                $channelGroup->getChannelJsIdentifier()
106
            ));
107
108
            /**
109
             * @var LoadedEventDTO $eventDTO
110
             */
111
            foreach ($channelGroup as $key => $eventDTO) {
112
                // Then push each of the channels events into the stack too.
113
                $this->scriptGenerator->pushScriptNode(ScriptNodeBuilder::getListenNode(
114
                    $eventDTO->eventName,
115
                    $eventDTO->jsEventCallback
116
                ));
117
            }
118
        }
119
120
        $generatedScript = $this->scriptGenerator->getRootScript();
121
122
        return view('dynamicEcho::scripts', compact('generatedScript'))->render();
0 ignored issues
show
Bug Best Practice introduced by
The expression return view('dynamicEcho...atedScript'))->render() could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
123
    }
124
125
    protected function buildHtmlStack(string $content, string $renderType): array
126
    {
127
        /**
128
         * @var ?bool $debug
129
         */
130
        static $debug;
131
        if (null === $debug) {
132
            $debug = config('app.debug');
133
        }
134
135
        $html = [];
136
        if ($debug) {
137
            $html[] = '<!-- Start DynamicEcho ' . $renderType . ' -->';
138
        }
139
        $html[] = $debug ? $content : $this->minify($content);
140
        if ($debug) {
141
            $html[] = '<!-- End DynamicEcho ' . $renderType . ' -->';
142
        }
143
144
        return $html;
145
    }
146
147
    protected function minify(string $subject): string
148
    {
149
        return preg_replace('~(\v|\t|\s{2,})~m', '', $subject);
150
    }
151
152
    public function getDiscoveredChannels(): ChannelAwareEventCollection
153
    {
154
        return $this->channelManager->registeredChannelNames();
155
    }
156
157
    public function getExtendedChannelInfo()
158
    {
159
        return $this->channelManager->registeredChannelInfo();
160
    }
161
}
162