xref: /plugin/combo/ComboStrap/Snippet.php (revision c3437056399326d621a01da73b649707fbb0ae69)
137748cd8SNickeau<?php
237748cd8SNickeau/**
337748cd8SNickeau * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved.
437748cd8SNickeau *
537748cd8SNickeau * This source code is licensed under the GPL license found in the
637748cd8SNickeau * COPYING  file in the root directory of this source tree.
737748cd8SNickeau *
837748cd8SNickeau * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
937748cd8SNickeau * @author   ComboStrap <support@combostrap.com>
1037748cd8SNickeau *
1137748cd8SNickeau */
1237748cd8SNickeau
1337748cd8SNickeaunamespace ComboStrap;
1437748cd8SNickeau
1537748cd8SNickeau
16*c3437056SNickeauuse JsonSerializable;
17*c3437056SNickeau
18*c3437056SNickeauclass Snippet implements JsonSerializable
1937748cd8SNickeau{
2037748cd8SNickeau    /**
2137748cd8SNickeau     * The head in css format
2237748cd8SNickeau     * We need to add the style node
2337748cd8SNickeau     */
2437748cd8SNickeau    const TYPE_CSS = "css";
2537748cd8SNickeau
26*c3437056SNickeau
2737748cd8SNickeau    /**
2837748cd8SNickeau     * The head in javascript
2937748cd8SNickeau     * We need to wrap it in a script node
3037748cd8SNickeau     */
3137748cd8SNickeau    const TYPE_JS = "js";
3237748cd8SNickeau    /**
3337748cd8SNickeau     * A tag head in array format
3437748cd8SNickeau     * No need
3537748cd8SNickeau     */
3637748cd8SNickeau    const TAG_TYPE = "tag";
37*c3437056SNickeau    const JSON_SNIPPET_ID_PROPERTY = "id";
38*c3437056SNickeau    const JSON_TYPE_PROPERTY = "type";
39*c3437056SNickeau    const JSON_CRITICAL_PROPERTY = "critical";
40*c3437056SNickeau    const JSON_CONTENT_PROPERTY = "content";
41*c3437056SNickeau    const JSON_HEAD_PROPERTY = "head";
4237748cd8SNickeau
4337748cd8SNickeau    private $snippetId;
4437748cd8SNickeau    private $type;
4537748cd8SNickeau
4637748cd8SNickeau    /**
4737748cd8SNickeau     * @var bool
4837748cd8SNickeau     */
49*c3437056SNickeau    private $critical;
5037748cd8SNickeau
5137748cd8SNickeau    /**
5237748cd8SNickeau     * @var string the text script / style (may be null if it's an external resources)
5337748cd8SNickeau     */
5437748cd8SNickeau    private $content;
5537748cd8SNickeau    /**
5637748cd8SNickeau     * @var array
5737748cd8SNickeau     */
5837748cd8SNickeau    private $headsTags;
5937748cd8SNickeau
6037748cd8SNickeau    /**
6137748cd8SNickeau     * Snippet constructor.
6237748cd8SNickeau     */
6337748cd8SNickeau    public function __construct($snippetId, $snippetType)
6437748cd8SNickeau    {
6537748cd8SNickeau        $this->snippetId = $snippetId;
6637748cd8SNickeau        $this->type = $snippetType;
6737748cd8SNickeau    }
6837748cd8SNickeau
69*c3437056SNickeau    public static function createJavascriptSnippet($snippetId): Snippet
7037748cd8SNickeau    {
7137748cd8SNickeau        return new Snippet($snippetId, self::TYPE_JS);
7237748cd8SNickeau    }
7337748cd8SNickeau
74*c3437056SNickeau    public static function createCssSnippet($snippetId): Snippet
7537748cd8SNickeau    {
7637748cd8SNickeau        return new Snippet($snippetId, self::TYPE_CSS);
7737748cd8SNickeau    }
7837748cd8SNickeau
7937748cd8SNickeau    /**
8037748cd8SNickeau     * @param $snippetId
8137748cd8SNickeau     * @return Snippet
82*c3437056SNickeau     * @deprecated You should create a snippet with a known type, this constructor was created for refactoring
8337748cd8SNickeau     */
84*c3437056SNickeau    public static function createUnknownSnippet($snippetId): Snippet
8537748cd8SNickeau    {
8637748cd8SNickeau        return new Snippet($snippetId, "unknwon");
8737748cd8SNickeau    }
8837748cd8SNickeau
8937748cd8SNickeau
9037748cd8SNickeau    /**
9137748cd8SNickeau     * @param $bool - if the snippet is critical, it would not be deferred or preloaded
9237748cd8SNickeau     * @return Snippet for chaining
9337748cd8SNickeau     * All css that are for animation or background for instance
9437748cd8SNickeau     * should not be set as critical as they are not needed to paint
9537748cd8SNickeau     * exactly the page
9637748cd8SNickeau     */
97*c3437056SNickeau    public function setCritical($bool): Snippet
9837748cd8SNickeau    {
9937748cd8SNickeau        $this->critical = $bool;
10037748cd8SNickeau        return $this;
10137748cd8SNickeau    }
10237748cd8SNickeau
10337748cd8SNickeau    /**
10437748cd8SNickeau     * @param $content - Set an inline content for a script or stylesheet
10537748cd8SNickeau     * @return Snippet for chaining
10637748cd8SNickeau     */
107*c3437056SNickeau    public function setContent($content): Snippet
10837748cd8SNickeau    {
10937748cd8SNickeau        $this->content = $content;
11037748cd8SNickeau        return $this;
11137748cd8SNickeau    }
11237748cd8SNickeau
11337748cd8SNickeau    /**
11437748cd8SNickeau     * @return string
11537748cd8SNickeau     */
11637748cd8SNickeau    public function getContent()
11737748cd8SNickeau    {
11837748cd8SNickeau        if ($this->content == null) {
11937748cd8SNickeau            switch ($this->type) {
12037748cd8SNickeau                case self::TYPE_CSS:
12137748cd8SNickeau                    $this->content = $this->getCssRulesFromFile($this->snippetId);
12237748cd8SNickeau                    break;
12337748cd8SNickeau                case self::TYPE_JS:
12437748cd8SNickeau                    $this->content = $this->getJavascriptContentFromFile($this->snippetId);
12537748cd8SNickeau                    break;
12637748cd8SNickeau                default:
12737748cd8SNickeau                    LogUtility::msg("The snippet ($this) has no content", LogUtility::LVL_MSG_ERROR, "support");
12837748cd8SNickeau            }
12937748cd8SNickeau        }
13037748cd8SNickeau        return $this->content;
13137748cd8SNickeau    }
13237748cd8SNickeau
13337748cd8SNickeau    /**
13437748cd8SNickeau     * @param $tagName
13537748cd8SNickeau     * @return false|string - the css content of the css file
13637748cd8SNickeau     */
13737748cd8SNickeau    private function getCssRulesFromFile($tagName)
13837748cd8SNickeau    {
13937748cd8SNickeau
14037748cd8SNickeau        $path = Resources::getSnippetResourceDirectory() . "/style/" . strtolower($tagName) . ".css";
14137748cd8SNickeau        if (file_exists($path)) {
14237748cd8SNickeau            return file_get_contents($path);
14337748cd8SNickeau        } else {
14437748cd8SNickeau            LogUtility::msg("The css file ($path) was not found", LogUtility::LVL_MSG_WARNING, $tagName);
14537748cd8SNickeau            return "";
14637748cd8SNickeau        }
14737748cd8SNickeau
14837748cd8SNickeau    }
14937748cd8SNickeau
15037748cd8SNickeau    /**
15137748cd8SNickeau     * @param $tagName - the tag name
15237748cd8SNickeau     * @return false|string - the specific javascript content for the tag
15337748cd8SNickeau     */
15437748cd8SNickeau    private function getJavascriptContentFromFile($tagName)
15537748cd8SNickeau    {
15637748cd8SNickeau
15737748cd8SNickeau        $path = Resources::getSnippetResourceDirectory() . "/js/" . strtolower($tagName) . ".js";
15837748cd8SNickeau        if (file_exists($path)) {
15937748cd8SNickeau            return file_get_contents($path);
16037748cd8SNickeau        } else {
16137748cd8SNickeau            LogUtility::msg("The javascript file ($path) was not found", LogUtility::LVL_MSG_WARNING, $tagName);
16237748cd8SNickeau            return "";
16337748cd8SNickeau        }
16437748cd8SNickeau
16537748cd8SNickeau    }
16637748cd8SNickeau
16737748cd8SNickeau    public function __toString()
16837748cd8SNickeau    {
16937748cd8SNickeau        return $this->snippetId . "-" . $this->type;
17037748cd8SNickeau    }
17137748cd8SNickeau
17237748cd8SNickeau    /**
17337748cd8SNickeau     * Set all tags at once.
17437748cd8SNickeau     * @param array $tags
17537748cd8SNickeau     * @return Snippet
17637748cd8SNickeau     */
177*c3437056SNickeau    public function setTags(array $tags): Snippet
17837748cd8SNickeau    {
17937748cd8SNickeau        $this->headsTags = $tags;
18037748cd8SNickeau        return $this;
18137748cd8SNickeau    }
18237748cd8SNickeau
183*c3437056SNickeau    public function getTags(): array
18437748cd8SNickeau    {
18537748cd8SNickeau        return $this->headsTags;
18637748cd8SNickeau    }
18737748cd8SNickeau
188*c3437056SNickeau    public function getCritical(): bool
18937748cd8SNickeau    {
190*c3437056SNickeau
191*c3437056SNickeau        if ($this->critical === null) {
192*c3437056SNickeau            if ($this->type == self::TYPE_CSS) {
193*c3437056SNickeau                // All CSS should be loaded first
194*c3437056SNickeau                // The CSS animation / background can set this to false
195*c3437056SNickeau                return true;
196*c3437056SNickeau            }
197*c3437056SNickeau            return false;
198*c3437056SNickeau        }
19937748cd8SNickeau        return $this->critical;
20037748cd8SNickeau    }
20137748cd8SNickeau
202*c3437056SNickeau    public function getClass(): string
20337748cd8SNickeau    {
20437748cd8SNickeau        /**
20537748cd8SNickeau         * The class for the snippet is just to be able to identify them
20637748cd8SNickeau         *
20737748cd8SNickeau         * The `snippet` prefix was added to be sure that the class
20837748cd8SNickeau         * name will not conflict with a css class
20937748cd8SNickeau         * Example: if you set the class to `combo-list`
21037748cd8SNickeau         * and that you use it in a inline `style` tag with
21137748cd8SNickeau         * the same class name, the inline `style` tag is not applied
21237748cd8SNickeau         *
21337748cd8SNickeau         */
21437748cd8SNickeau        return "snippet-" . $this->snippetId . "-" . SnippetManager::COMBO_CLASS_SUFFIX;
21537748cd8SNickeau
21637748cd8SNickeau    }
21737748cd8SNickeau
21837748cd8SNickeau    /**
21937748cd8SNickeau     * @return string the HTML of the tag (works for now only with CSS content)
22037748cd8SNickeau     */
221*c3437056SNickeau    public function getHtmlStyleTag(): string
22237748cd8SNickeau    {
22337748cd8SNickeau        $content = $this->getContent();
22437748cd8SNickeau        $class = $this->getClass();
22537748cd8SNickeau        return <<<EOF
22637748cd8SNickeau<style class="$class">
22737748cd8SNickeau$content
22837748cd8SNickeau</style>
22937748cd8SNickeauEOF;
23037748cd8SNickeau
23137748cd8SNickeau    }
23237748cd8SNickeau
23337748cd8SNickeau    public function getId()
23437748cd8SNickeau    {
23537748cd8SNickeau        return $this->snippetId;
23637748cd8SNickeau    }
23737748cd8SNickeau
23837748cd8SNickeau
239*c3437056SNickeau    public function jsonSerialize(): array
240*c3437056SNickeau    {
241*c3437056SNickeau        $dataToSerialize = [
242*c3437056SNickeau            self::JSON_SNIPPET_ID_PROPERTY => $this->snippetId,
243*c3437056SNickeau            self::JSON_TYPE_PROPERTY => $this->type
244*c3437056SNickeau        ];
245*c3437056SNickeau        if ($this->critical !== null) {
246*c3437056SNickeau            $dataToSerialize[self::JSON_CRITICAL_PROPERTY] = $this->critical;
247*c3437056SNickeau        }
248*c3437056SNickeau        if ($this->content !== null) {
249*c3437056SNickeau            $dataToSerialize[self::JSON_CONTENT_PROPERTY] = $this->content;
250*c3437056SNickeau        }
251*c3437056SNickeau        if ($this->headsTags !== null) {
252*c3437056SNickeau            $dataToSerialize[self::JSON_HEAD_PROPERTY] = $this->headsTags;
253*c3437056SNickeau        }
254*c3437056SNickeau        return $dataToSerialize;
255*c3437056SNickeau
256*c3437056SNickeau    }
257*c3437056SNickeau
258*c3437056SNickeau    /**
259*c3437056SNickeau     * @throws ExceptionCombo
260*c3437056SNickeau     */
261*c3437056SNickeau    public static function createFromJson($array): Snippet
262*c3437056SNickeau    {
263*c3437056SNickeau        $snippetId = $array[self::JSON_SNIPPET_ID_PROPERTY];
264*c3437056SNickeau        if ($snippetId === null) {
265*c3437056SNickeau            throw new ExceptionCombo("The snippet id property was not found in the json array");
266*c3437056SNickeau        }
267*c3437056SNickeau        $type = $array[self::JSON_TYPE_PROPERTY];
268*c3437056SNickeau        if ($type === null) {
269*c3437056SNickeau            throw new ExceptionCombo("The snippet type property was not found in the json array");
270*c3437056SNickeau        }
271*c3437056SNickeau        $snippet = new Snippet($snippetId, $type);
272*c3437056SNickeau        $critical = $array[self::JSON_CRITICAL_PROPERTY];
273*c3437056SNickeau        if ($critical !== null) {
274*c3437056SNickeau            $snippet->setCritical($critical);
275*c3437056SNickeau        }
276*c3437056SNickeau
277*c3437056SNickeau        $content = $array[self::JSON_CONTENT_PROPERTY];
278*c3437056SNickeau        if ($content !== null) {
279*c3437056SNickeau            $snippet->setContent($content);
280*c3437056SNickeau        }
281*c3437056SNickeau
282*c3437056SNickeau        $heads = $array[self::JSON_HEAD_PROPERTY];
283*c3437056SNickeau        if ($heads !== null) {
284*c3437056SNickeau            $snippet->setTags($heads);
285*c3437056SNickeau        }
286*c3437056SNickeau        return $snippet;
287*c3437056SNickeau
288*c3437056SNickeau    }
28937748cd8SNickeau}
290