Passed
Push — 2.7.11 ( ...beab38 )
by steve
18:35 queued 14s
created

App::publishThemeAssets()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
/**
3
 * @link http://www.newicon.net/neon
4
 * @copyright Copyright (c) 2008 Newicon Ltd
5
 * @license http://www.newicon.net/neon/license/
6
 */
7
8
namespace neon\cms;
9
10
use neon\cms\models\CmsPage;
11
use \neon\core\BaseApp;
12
use \neon\cms\components\CmsUrlRule;
13
use neon\core\interfaces\IDataMapProvider;
14
use neon\core\helpers\Str;
15
/**
16
 * The neon cms app class
17
 *
18
 * @property \neon\cms\components\Page $page
19
 * @property \neon\cms\services\cmsManager\CmsManager $ICmsStaticData 
20
 */
21
class App extends BaseApp
22
implements IDataMapProvider
23
{
24
	public $requires = 'dds';
25
26
	/**
27
	 * @var array of roles that can edit page content via cobe
28
	 */
29
	public $editingRoles = ['neon-administrator'];
30
31
	/**
32
	 * @throws \yii\base\InvalidConfigException
33
	 * @inheritdoc
34
	 */
35
	public function configure()
36
	{
37
		$this->set('page', [
38
			'class' => '\neon\cms\components\Page'
39
		]);
40
		$this->set('ICmsStaticData', [
41
			'class' => '\neon\cms\services\cmsManager\CmsManager'
42
		]);
43
	}
44
45
	/**
46
	 * @inheritdoc
47
	 */
48
	public function setup()
49
	{
50
		// Add the url rule to map urls to pages
51
		neon()->urlManager->rules[] = new CmsUrlRule();
52
		neon()->urlManager->addRules([
53
			'sitemap.xml' => 'cms/render/sitemap'
54
		]);
55
	}
56
57
	/**
58
	 * @inheritdoc
59
	 */
60
	public function getDefaultMenu()
61
	{
62
		// add menu item (to be deprecated)
63
		return [
64
			'label' => $this->getName(),
65
			'order' => 1100,
66
			'url' => ['/cms/index/index'],
67
			'active' => is_route('/cms/*'),
68
		];
69
	}
70
71
	/**
72
	 * Get the name for this app
73
	 * @return string
74
	 */
75
	public function getName()
76
	{
77
		return 'Cobe CMS';
78
	}
79
80
	/**
81
	 * @inheritdoc
82
	 */
83
	public function getSettings()
84
	{
85
		return [
86
			'google_code' => [
87
				'label' => 'Google Code',
88
				'hint' => 'Set the google analytics or tag manager code - this will install the google scripts.  For tag manager add the code that looks like: "GTM-XXXX".
89
				Use the UA-XXX code or other Google product codes if you are nit using tag manager
90
				If you need more control of the scripts installed then leave this field blank and copy the code into the script blocks below',
91
			],
92
			'canonical' => [
93
				'class' => '\neon\core\form\fields\UrlLink',
94
				'label' => 'Global Canonical tag domain',
95
				'hint' => 'Set the global URL to use in the canonical tag for this site so search engines know the proper URL to index and don\'t serve duplicate content.
96
				All site pages will use this global canonical tag URL as their starting point and append the page\'s unique URL slug after it. [Learn more about canonical tags](https://moz.com/learn/seo/canonicalization).',
97
				'placeholder' => 'e.g. domain.com'
98
			],
99
			'head'=>[
100
				'label' =>	'Code to be inserted before the </head> tag on every page',
101
				'class' => '\neon\core\form\fields\Ide'
102
			],
103
			'body'=>[
104
				'label' =>	'Code to be inserted just before the closing </body> tag on every page',
105
				'class' => '\neon\core\form\fields\Ide'
106
			],
107
			'favicon' => [
108
				'label' =>	'Favicon',
109
				'hint' => 'Upload a square image for the favicon. Use the ```{favicon}``` tag to render the html in the ```<head>``` part of the document',
110
				'class' => \neon\core\form\fields\Image::class,
111
				'crop'=>true,
112
				'cropWidth'=>1,
113
				'cropHeight'=>1
114
			]
115
		];
116
	}
117
118
	/**
119
	 * Get the page component
120
	 * @return \neon\cms\components\Page
121
	 */
122
	public function getPage()
123
	{
124
		return $this->get('page');
125
	}
126
127
	/**
128
	 * request an ICmsStaticData interface
129
	 * @return \neon\cms\services\cmsManager\interfaces\ICmsStaticData
130
	 */
131
	public function getICmsStaticData() {
132
		return $this->get('ICmsStaticData');
133
	}
134
135
	/** Setting and Getting the Theme information **/
136
	/***********************************************/
137
138
	/**
139
	 * Get the current theme name
140
	 * Will return the current theme if no theme hierarchy was set
141
	 * or the top item in the theme hierarchy if set
142
	 * @return string
143
	 */
144
	public function getThemeName()
145
	{
146
		if (count($this->_themeHierarchy)) {
147
			return $this->_themeHierarchy[0];
148
		}
149
		return $this->_themeName;
150
	}
151
152
	/**
153
	 * Set the theme name for site
154
	 * This can be done via the 'cms' => 'themeName' configuration information
155
	 * @param string $name  must be alphanumeric and _ - only
156
	 * @throws \InvalidArgumentException  if the name is not valid
157
	 */
158
	public function setThemeName($name)
159
	{
160
		$this->checkThemeName($name);
161
		$this->_themeName = $name;
162
	}
163
	private $_themeName = 'default';
164
165
	/**
166
	 * Get the current theme hierarchy
167
	 * Will return the current theme hierarchy if set or
168
	 * the [themeName] otherwise
169
	 * @return array [theme]
170
	 */
171
	public function getThemeHierarchy()
172
	{
173
		// if we have a theme hierarchy use that
174
		if (count($this->_themeHierarchy))
175
			return $this->_themeHierarchy;
176
		// otherwise drop back to the themeName
177
		if (!empty($this->_themeName))
178
			return [$this->_themeName];
179
		// otherwise return nothing
180
		return [];
181
	}
182
183
	/**
184
	 * Set the theme hierarchy for the site.
185
	 * This is an array of themes in reverse precedence
186
	 * i.e. first one overrides second etc
187
	 * @param array $themes
188
	 */
189
	public function setThemeHierarchy(array $themes)
190
	{
191
		$this->_themeHierarchy = [];
192
		foreach ($themes as $theme) {
193
			$this->checkThemeName($theme);
194
			$this->_themeHierarchy[] = $theme;
195
		}
196
	}
197
	private $_themeHierarchy = [];
198
199
200
	/** Setting and Getting site information **/
201
	/******************************************/
202
203
	/**
204
	 * @return array  information about the site
205
	 */
206
	public function getSiteData()
207
	{
208
		return $this->_siteData;
209
	}
210
211
	/**
212
	 * set site specific information
213
	 * This can be set via the 'cms' => 'siteData' adding
214
	 * whatever parameters are required.
215
	 * @param array $siteData
216
	 */
217
	public function setSiteData($siteData)
218
	{
219
		$this->_siteData = $siteData;
220
	}
221
	private $_siteData = [];
222
223
	/**
224
	 * path alias to the theme directory
225
	 * @return string
226
	 */
227
	public function getThemeAlias()
228
	{
229
		return '@root/themes/' . $this->getThemeName();
230
	}
231
232
	/**
233
	 * Get the basepath to the cms theme directory
234
	 * @return bool|string
235
	 */
236
	public function getThemeBasePath()
237
	{
238
		return neon()->getAlias($this->getThemeAlias());
239
	}
240
241
	/**
242
	 * Gets a public accessible url to the theme asset
243
	 * (Any file stored in the theme/assets folder)
244
	 * 
245
	 * @param string $path relative path from the theme assets folder
246
	 * @return string url to the asset
247
	 */
248
	public function themeAssetUrl($path)
249
	{
250
		// loading external resource so just return
251
		if (Str::startsWith($path, 'http')) return $path;
252
		list($assetPath, $assetUrl) = $this->publishThemeAssets();
253
		$path = ltrim($path, '/');
254
		$assetUrl = ltrim($assetUrl, '/');
255
		$timestamp = @filemtime("$assetPath/$path");
256
		return neon()->urlManager->getHostInfo().'/'.$assetUrl.'/'.$path.(($timestamp > 0) ? '?v='.$timestamp : '');
0 ignored issues
show
Bug introduced by
Are you sure $timestamp of type false|integer can be used in concatenation? ( Ignorable by Annotation )

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

256
		return neon()->urlManager->getHostInfo().'/'.$assetUrl.'/'.$path.(($timestamp > 0) ? '?v='./** @scrutinizer ignore-type */ $timestamp : '');
Loading history...
257
	}
258
259
	/**
260
	 * Publish the current theme assets
261
	 * 
262
	 * @return array 0 => path and 1 => the url is was published as
263
	 */
264
	public function publishThemeAssets()
265
	{
266
		$themeAssets = neon()->cms->getThemeAlias().'/assets';
267
		return neon()->assetManager->publish($themeAssets);
268
	}
269
270
	/**
271
	 * @deprecated user parent publishAssets function
272
	 * Publish this modules assets directory
273
	 * @return array
274
	 */
275
	public function assets()
276
	{
277
		return neon()->assetManager->publish('@neon/cms/assets');
278
	}
279
	/**
280
	 * @deprecated user parent publishAssets function
281
	 * @return mixed
282
	 */
283
	public function assetsUrl()
284
	{
285
		list($path, $url) = $this->assets();
0 ignored issues
show
Deprecated Code introduced by
The function neon\cms\App::assets() has been deprecated: user parent publishAssets function Publish this modules assets directory ( Ignorable by Annotation )

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

285
		list($path, $url) = /** @scrutinizer ignore-deprecated */ $this->assets();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
286
		return $url;
287
	}
288
	/**
289
	 * @deprecated user parent publishAssets function
290
	 * @return mixed
291
	 */
292
	public function assetsPath()
293
	{
294
		list($path, $url) = $this->assets();
0 ignored issues
show
Deprecated Code introduced by
The function neon\cms\App::assets() has been deprecated: user parent publishAssets function Publish this modules assets directory ( Ignorable by Annotation )

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

294
		list($path, $url) = /** @scrutinizer ignore-deprecated */ $this->assets();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
295
		return $path;
296
	}
297
298
	/**
299
	 * @inheritdoc
300
	 * @unsupported - $filters is not currently supported
301
	 */
302
	public function getDataMap($key, $query='',  $filters=[], $fields=[], $start = 0, $limit = 100)
303
	{
304
		if ($key === 'pages') {
305
			return $this->getPagesMap($query, $filters, $fields, $start, $limit);
306
		}
307
	}
308
309
	/**
310
	 * @var string[] - string requestKey to array of makeMapLookupRequest arguments
311
	 */
312
	private $_mapRequestKey = null;
313
314
	/**
315
	 * @inheritdoc
316
	 */
317
	public function getMapResults($requestKey)
318
	{
319
		if (!isset($this->_mapRequestKey[$requestKey]))
320
			throw new \InvalidArgumentException('The provided request key "'.$requestKey.'" does not exist');
321
		list($key, $ids, $fields) = $this->_mapRequestKey[$requestKey];
322
		if ($key === 'pages') {
323
			$pages = CmsPage::find()->select(array_merge(['id', 'nice_id', 'title'], $fields))
324
				->where(['id' => $ids])
325
				->orderBy('nice_id')
326
				->asArray()
327
				->all();
328
			return $this->formatPageMapResults($pages, $fields);
329
		}
330
		return [];
331
	}
332
333
	/**
334
	 * Format a list of page rows into a map
335
	 * @param array $pages - assoc db rows
336
	 * @return array - maps typically contain an id to a single string value however if additional fields have been
337
	 *   defined then the map needs to return the id => array of values keyed by field name
338
	 *   for e.g.
339
	 * ```php
340
	 *  // when additional $fields have been requested:
341
	 *  ['uuid' => [
342
	 *      'field1' => 'value',
343
	 *      'field2' => 'value2',
344
	 *   ]]
345
	 *
346
	 *  // when no additional fields defined:
347
	 *  ['uuid' => 'nice_id: title'],
348
	 * ```
349
	 *   Essentially there is a dual responsibility.
350
	 *   An advanced select box could specify additional map fields additional filters and even display the data in a
351
	 *   different format. However we want the maps to work well with no additional configuration
352
	 */
353
	public function formatPageMapResults($pages, $fields)
354
	{
355
		return collect($pages)->mapWithKeys(function ($item) use($fields) {
356
			if (empty($fields))
357
				return [$item['id'] => "$item[title]  (nice=$item[nice_id])"];
358
			return [$item['id'] => $item];
359
		})->all();
360
	}
361
362
	/**
363
	 * @inheritdoc
364
	 */
365
	public function makeMapLookupRequest($key, $ids, $fields = [])
366
	{
367
		$requestKey = md5(serialize(func_get_args()));
368
		$this->_mapRequestKey[$requestKey] = func_get_args();
369
		return $requestKey;
370
	}
371
372
	/**
373
	 * Perform a search to find a map - used for map searches - dropdown displays
374
	 * where a string search can be used as well as fixed array defined filters.
375
	 * @see \neon\core\form\fields\SelectDymaic
376
	 * @see \neon\core\form\fields\SelectDymaic\Link
377
	 * @see \neon\core\interfaces\IDataMapProvider::getDataMap()
378
	 * Note this is not used directly to perform the getDataMap but it is used specifically to provide the map for
379
	 * cms pages (the getDataMap interface supports multiple maps per object)
380
	 * @param string $query - a string based search
381
	 * @param array $filters - an array of search criteria key => value
382
	 * @param array $fields
383
	 * @return array - @see $this->formatPageMapResults();
384
	 */
385
	public function getPagesMap($query=null, $filters=[], $fields=[], $start=0, $limit=100)
0 ignored issues
show
Unused Code introduced by
The parameter $limit is not used and could be removed. ( Ignorable by Annotation )

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

385
	public function getPagesMap($query=null, $filters=[], $fields=[], $start=0, /** @scrutinizer ignore-unused */ $limit=100)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
386
	{
387
		$pages = CmsPage::find()
388
			->select(array_merge(['id', 'nice_id', 'title'], $fields))
389
			->where(['or', ['like', 'nice_id', $query], ['like', 'title', $query]])
390
			->andWhere($filters)
391
			->offset($start)
392
			->limit(100)
393
			->orderBy('nice_id')
394
			->asArray()
395
			->all();
396
		return $this->formatPageMapResults($pages, $fields);
397
	}
398
399
	/**
400
	 * @inheritdoc
401
	 */
402
	public function getDataMapTypes()
403
	{
404
		return [
405
			'pages' => 'Pages'
406
		];
407
	}
408
409
	/** ********** Private and Protected Methods ********** **/
410
411
	/**
412
	 * check a theme name is valid
413
	 * - consists of alphanumeric and _- chars only
414
	 * @param string $name
415
	 * @throws \InvalidArgumentException
416
	 */
417
	private function checkThemeName($name)
418
	{
419
		if ( preg_match('/[^A-Za-z0-9_-]/', $name, $matches) ) {
420
			throw new \InvalidArgumentException("Error trying to set the theme name to '$name'"
421
				."\n"."The theme name must consist of only 'a-z', '0-9', '_' and '-' characters."
422
				."\n".'The following character is not allowed in theme names: ' . \yii\helpers\VarDumper::dumpAsString($matches[0]) );
423
		}
424
	}
425
426
}
427