Theme::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
rs 9.4285
cc 2
eloc 10
nc 2
nop 4
1
<?php
2
/**
3
 * Theme
4
 *
5
 * @package     erdiko/core
6
 * @copyright   2012-2017 Arroyo Labs, Inc. http://www.arroyolabs.com
7
 * @author      John Arroyo <[email protected]>
8
 */
9
namespace erdiko\core;
10
11
12
/**
13
 * @note the data array in this class uses a sort of NOSQL style approach to the theming
14
 */
15
class Theme extends Container
16
{
17
    /** Theme root folder */
18
    protected $_themeRootFolder;
19
    /** Name */
20
    protected $_name = null;
21
    /** Context */
22
    protected $_context = null;
23
    /** Context Config (application config) */
24
    protected $_contextConfig = null;
25
    /** Theme Config */
26
    protected $_themeConfig = null;
27
    /** Content */
28
    protected $_content = null;
29
30
    /**
31
     * Constructor
32
     *
33
     * @param string $themeName
34
     * @param mixed $data
35
     * @param string $template Theme Object (Contanier)
36
     * @param string $context context to theme against (defaults to current environment context)
37
     */
38
    public function __construct($themeName = 'default', $data = null, 
39
        $template = 'default', $context = null)
40
    {
41
        $this->initiate($template, $data);
42
        $this->setThemeRootFolder('themes');
43
        $this->setName($themeName);
44
        $this->_data = array(
45
            'js' =>array(),
46
            'css' => array(),
47
            'meta' => array()
48
            );
49
50
        // Context can only be set at instantiation (for theme stability)
51
        $this->_context = ($context === null) ? getenv('ERDIKO_CONTEXT') : $context;
52
    }
53
54
    /**
55
     * Get context config
56
     * This is the application config for the given context (e.g. default site)
57
     * Context is determined by environment variable ERDIKO_CONTEXT, getenv('ERDIKO_CONTEXT')
58
     *
59
     * @return array $config application config
60
     */
61
    public function getContextConfig()
62
    {
63
        if (empty($this->_contextConfig))
64
            $this->_contextConfig = Helper::getConfig('application', $this->_context);
65
        
66
        return $this->_contextConfig;
67
    }
68
69
    /**
70
     * Get Theme configuration (default theme)
71
     *
72
     * @return array $config
73
     */
74
    public function getThemeConfig()
75
    {
76
        if (empty($this->_themeConfig)) {
77
            $file = $this->getThemeFolder() . 'theme.json';
78
            $this->_themeConfig = Helper::getConfigFile($file);
79
        }
80
        return $this->_themeConfig;
81
    }
82
83
    /**
84
     * Get Meta
85
     *
86
     * @return string $meta
87
     */
88 View Code Duplication
    public function getMeta()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
89
    {
90
        if (isset($this->_contextConfig['site']['meta'])) {
91
            return array_merge($this->_contextConfig['site']['meta'],$this->_data['meta']);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array_merge($this... $this->_data['meta']); (array) is incompatible with the return type documented by erdiko\core\Theme::getMeta of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
92
        } else {
93
            return $this->_data['meta'];
94
        }
95
    }
96
97
    /**
98
     * Add meta file to page
99
     *
100
     * @param string $name
101
     * @param string $content
102
     */
103
    public function addMeta($name, $content)
104
    {
105
        $this->_data['meta'][$name] = $content;
106
    }
107
108
    /**
109
     * Add meta tag data to page
110
     *
111
     * @param array $meta format: array("name" => "content", "author" => "content", ...)
112
     */
113
    public function setMeta($meta)
114
    {
115
        $this->_data['meta'] = $meta;
116
    }
117
118
    /**
119
     * Get SEO meta data and render as html (meta tags)
120
     * @return string html meta tags
121
     */
122
    public function getMetaMarkup()
123
    {
124
        $html = "";
125
126
        foreach ($this->getMeta() as $name => $content)
0 ignored issues
show
Bug introduced by
The expression $this->getMeta() of type string is not traversable.
Loading history...
127
        {
128
            if(is_array($content)) {
129
                foreach($content as $cont)
130
                    $html .= "<meta name=\"{$name}\" content=\"{$cont}\">\n";
131
            } else {
132
                $html .= "<meta name=\"{$name}\" content=\"{$content}\">\n";
133
            }
134
        }
135
136
        return $html;
137
    }
138
139
    /**
140
     * Get page title
141
     *
142
     * @return string page title
143
     */
144
    public function getPageTitle()
145
    {
146
        if (isset($this->_data['page_title'])) {
147
            return $this->_data['page_title'];
148
        } else {
149
            return null;
150
        }
151
    }
152
153
    /**
154
     * Set page title
155
     *
156
     * @param string $title
157
     */
158
    public function setPageTitle($title)
159
    {
160
        $this->_data['page_title'] = $title;
161
    }
162
163
    /**
164
     * Get body title
165
     *
166
     * @return string body title
167
     */
168
    public function getBodyTitle()
169
    {
170
        if (isset($this->_data['body_title'])) {
171
            return $this->_data['body_title'];
172
        } else {
173
            return null;
174
        }
175
    }
176
177
    /**
178
     * Set body title
179
     *
180
     * @param string $title
181
     */
182
    public function setBodyTitle($title)
183
    {
184
        $this->_data['body_title'] = $title;
185
    }
186
187
    /**
188
     * Get array of css files to include in theme
189
     *
190
     * @return array css file paths
191
     * @todo sort by the 'order' value
192
     */
193 View Code Duplication
    public function getCss()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
194
    {
195
        if (isset($this->_themeConfig['css'])) {
196
            return array_merge($this->_themeConfig['css'], $this->_data['css']);
197
        } else {
198
            return $this->_data['css'];
199
        }
200
    }
201
202
    /**
203
     * Add css file to page
204
     * @note there are collisions with using addCss and data['css']
205
     *
206
     * @param string $name
207
     * @param string $cssFile URL of injected css file
208
     * @param int $order 
209
     * @param boolean $active defaults to 1
210
     * @todo need to resolve order of merging and/or eliminate/refactor this function
211
     */
212
    public function addCss($name, $cssFile, $order = 10, $active = 1)
213
    {
214
       $this->_data['css'][$name] = array(
215
            'file' => $cssFile,
216
            'order' => $order,
217
            'active' => $active
218
            );
219
    }
220
221
    /**
222
     * Get array of js files to include
223
     *
224
     * @return array js file paths
225
     * @todo sort by the 'order' value
226
     */
227 View Code Duplication
    public function getJs()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
228
    {
229
        if (isset($this->_themeConfig['js'])) {
230
            return array_merge($this->_themeConfig['js'], $this->_data['js']);
231
        } else {
232
            return $this->_data['js'];
233
        }
234
    }
235
236
    /**
237
     * Add js file to page
238
     *
239
     * @param string $name
240
     * @param string $jsFile URL of js file
241
     * @param int $order 
242
     * @param boolean $active defaults to 1
243
     * @todo same issue as addCss
244
     */
245
    public function addJs($name, $jsFile, $order = 10, $active = 1)
246
    {
247
        $this->_data['js'][$name] = array(
248
            'file' => $jsFile,
249
            'order' => $order,
250
            'active' => $active
251
            );
252
    }
253
254
     /**
255
     * Get Theme Root Folder
256
     *
257
     * @param string $folder
0 ignored issues
show
Bug introduced by
There is no parameter named $folder. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
258
     */
259
    public function getThemeRootFolder()
260
    {
261
        return $this->_themeRootFolder;
262
    }
263
264
    /**
265
     * Set Theme Root Folder
266
     *
267
     * @param string $folder
268
     */
269
    public function setThemeRootFolder($folder)
270
    {
271
        $this->_themeRootFolder = $folder;
272
    }
273
274
    /**
275
     * Get the theme folder
276
     *
277
     * @return string $folder
278
     */
279
    public function getThemeFolder()
280
    {
281
        return $this->getTemplateFolderPath().$this->getThemeRootFolder().'/'.$this->getName().'/';
282
    }
283
284
    /**
285
     * Get template folder relative to the theme root
286
     *
287
     * @return string
288
     */
289
    public function getTemplateFolder()
290
    {
291
        return $this->getThemeFolder().'templates/';
292
    }
293
294
295
    /**
296
     * Set content
297
     *
298
     * @param string|Container $content any string or object that implements __toString()
299
     */
300
    public function setContent($content)
301
    {
302
        $this->_content = $content;
303
    }
304
305
    /**
306
     * Get content
307
     *
308
     * @return string|Container content
309
     */
310
    public function getContent()
311
    {
312
        return $this->_content;
313
    }
314
315
    /**
316
     * Set the theme name, the name is also the id of the theme
317
     *
318
     * @param string Theme name
319
     */
320
    public function setName($name)
321
    {
322
        $this->_name = $name;
323
    }
324
325
    /**
326
     * Get name.
327
     * Return Theme name
328
     *
329
     * @return string name
330
     */
331
    public function getName()
332
    {
333
        return $this->_name;
334
    }
335
336
    /**
337
     * Get template file populated by the config
338
     *
339
     * @usage Partial render need to be declared in theme.json
340
     * e.g. get header/footer
341
     * @param string $partial
342
     * @return string html
343
     */
344
    public function getTemplateHtml($partial)
345
    {
346
        $config = $this->getThemeConfig();
347
        // @todo add check here to make sure partial exists, if missing log error
348
        $filename = $this->getTemplateFolder().$config['templates'][$partial]['file'];
349
350
        $html = $this->getTemplateFile($filename, $this->getContextConfig());
351
        
352
        return $html;
353
    }
354
355
    /**
356
     * Output content to html
357
     *
358
     * @return string html
359
     */
360
    public function toHtml()
361
    {
362
        // load the theme and context (site) configs
363
        $this->getContextConfig();
364
        $this->getThemeConfig();
365
366
        $filename = $this->getTemplateFolder().$this->getTemplate();
367
        $html = $this->getTemplateFile($filename, $this);
0 ignored issues
show
Documentation introduced by
$this is of type this<erdiko\core\Theme>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
368
        
369
        return $html;
370
    }
371
}
372