Completed
Push — master ( 8a8054...9b4fee )
by Roberto
03:20
created

Component::getActiveOption()   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
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 25 and the first side effect is on line 18.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Joomla! component.
4
 *
5
 * @copyright  Copyright (C) 2017 Roberto Segura López, Inc. All rights reserved.
6
 * @license    See COPYING.txt
7
 */
8
9
namespace Phproberto\Joomla\Component;
10
11
use Joomla\Registry\Registry;
12
use Phproberto\Joomla\Client\Client;
13
use Phproberto\Joomla\Client\Site;
14
use Phproberto\Joomla\Client\Administrator;
15
use Phproberto\Joomla\Client\ClientInterface;
16
use Phproberto\Joomla\Traits;
17
18 1
defined('JPATH_PLATFORM') || die;
19
20
/**
21
 * Table finder.
22
 *
23
 * @since  __DEPLOY_VERSION__
24
 */
25
class Component
26
{
27
	use Traits\HasExtension, Traits\HasParams;
28
29
	/**
30
	 * Component option. Example: com_content
31
	 *
32
	 * @var  string
33
	 */
34
	protected $option;
35
36
	/**
37
	 * Component prefix for classes, etc.
38
	 *
39
	 * @var  string
40
	 */
41
	protected $prefix;
42
43
	/**
44
	 * Active client.
45
	 *
46
	 * @var  ClientInterface
47
	 */
48
	protected $client;
49
50
	/**
51
	 * Cached instances.
52
	 *
53
	 * @var  array
54
	 */
55
	protected static $instances = array();
56
57
	/**
58
	 * Constructor
59
	 *
60
	 * @param   string           $option  Component option
61
	 * @param   ClientInterface  $client  Client
62
	 *
63
	 * @throws  \InvalidArgumentException
64
	 */
65 24
	public function __construct($option, ClientInterface $client = null)
66
	{
67 24
		$option = trim(strtolower($option));
68
69 24
		if (empty($option))
70
		{
71 1
			throw new \InvalidArgumentException(__CLASS__ . ': Empty component option.');
72
		}
73
74 23
		$this->client = $client ?: Client::active();
75 23
		$this->option = $option;
76 23
	}
77
78
	/**
79
	 * Switch to admin client.
80
	 *
81
	 * @return  self
82
	 */
83 5
	public function admin()
84
	{
85 5
		$this->client = new Administrator;
86
87 5
		return $this;
88
	}
89
90
	/**
91
	 * Clear a singleton instance.
92
	 *
93
	 * @param   string  $option  Component option
94
	 *
95
	 * @return  void
96
	 */
97 4
	public static function clear($option)
98
	{
99 4
		unset(static::$instances[get_called_class()][$option]);
100 4
	}
101
102
	/**
103
	 * Clears all the statically cached instances.
104
	 *
105
	 * @return  void
106
	 */
107 24
	public static function clearAll()
108
	{
109 24
		static::$instances = array();
110 24
	}
111
112
	/**
113
	 * Get a singleton instance.
114
	 *
115
	 * @param   string  $option  Component option
116
	 *
117
	 * @return  $this
118
	 */
119 23
	public static function get($option)
120
	{
121 23
		$option = trim(strtolower($option));
122
123 23
		$class = get_called_class();
124
125 23
		if (empty(static::$instances[$class][$option]))
126
		{
127 23
			static::$instances[$class][$option] = new static($option);
128
		}
129
130 23
		return static::$instances[$class][$option];
131
	}
132
133
	/**
134
	 * Get the active component.
135
	 *
136
	 * @return  $this
137
	 *
138
	 * @throws  \InvalidArgumentException
139
	 */
140 1
	public static function getActive()
141
	{
142 1
		return static::get(static::getActiveOption());
143
	}
144
145
	/**
146
	 * Get the active component option. Isolated for testing purposes.
147
	 *
148
	 * @return  string
149
	 *
150
	 * @codeCoverageIgnore
151
	 */
152
	protected static function getActiveOption()
153
	{
154
		return \JApplicationHelper::getComponentName();
155
	}
156
157
	/**
158
	 * Get the active client.
159
	 *
160
	 * @return  ClientInterface
161
	 */
162 5
	public function getClient()
163
	{
164 5
		return $this->client;
165
	}
166
167
	/**
168
	 * Ensure that we retrieve a non-statically-cached instance.
169
	 *
170
	 * @param   string  $option   Component option
171
	 *
172
	 * @return  $this
173
	 */
174 2
	public static function getFresh($option)
175
	{
176 2
		static::clear($option);
177
178 2
		return static::get($option);
179
	}
180
181
	/**
182
	 * Get a model of this component.
183
	 *
184
	 * @param   string  $name    Name of the model.
185
	 * @param   array   $config  Optional array of configuration for the model
186
	 *
187
	 * @return  \JModelLegacy
188
	 *
189
	 * @throws  \InvalidArgumentException  If not found
190
	 */
191 5
	public function model($name, array $config = array('ignore_request' => true))
192
	{
193 5
		$prefix = $this->getPrefix() . 'Model';
194
195 5
		\JModelLegacy::addIncludePath($this->getModelsFolder(), $prefix);
196
197
		try
198
		{
199 4
			\JTable::addIncludePath($this->getTablesFolder());
200
		}
201 4
		catch (\Exception $e)
202
		{
203
			// There are models with no associated tables
204
		}
205
206 4
		$model = \JModelLegacy::getInstance($name, $prefix, $config);
0 ignored issues
show
Bug Compatibility introduced by
The expression \JModelLegacy::getInstan...ame, $prefix, $config); of type ? adds the type JModel to the return on line 215 which is incompatible with the return type documented by Phproberto\Joomla\Component\Component::model of type JModelLegacy.
Loading history...
207
208 4
		if (!$model instanceof \JModel && !$model instanceof \JModelLegacy)
0 ignored issues
show
Bug introduced by
The class JModel does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
Bug introduced by
The class JModelLegacy does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
209
		{
210 1
			throw new \InvalidArgumentException(
211 1
				sprintf("Cannot find the model `%s` in `%s` component's %s folder.", $name, $this->option, $this->client->getName())
212
			);
213
		}
214
215 3
		return $model;
216
	}
217
218
	/**
219
	 * Get the folder where the models are.
220
	 *
221
	 * @return  string
222
	 *
223
	 * @throws  \RuntimeException  If not found
224
	 */
225 5 View Code Duplication
	protected function getModelsFolder()
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...
226
	{
227 5
		$folder = $this->client->getFolder() . '/components/' . $this->option . '/models';
228
229 5
		if (is_dir($folder))
230
		{
231 4
			return $folder;
232
		}
233
234 1
		throw new \RuntimeException(
235 1
			sprintf("Cannot find the models folder for `%s` component in `%s` folder.", $this->option, $this->client->getName())
236
		);
237
	}
238
239
	/**
240
	 * Get the folder where the tables are.
241
	 *
242
	 * @return  string
243
	 *
244
	 * @throws  \RuntimeException  If not found
245
	 */
246 7 View Code Duplication
	protected function getTablesFolder()
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...
247
	{
248 7
		$folder = $this->client->getFolder() . '/components/' . $this->option . '/tables';
249
250 7
		if (is_dir($folder))
251
		{
252 3
			return $folder;
253
		}
254
255 4
		throw new \RuntimeException(
256 4
			sprintf("Cannot find the tables folder for `%s` component in `%s` folder.", $this->option, $this->client->getName())
257
		);
258
	}
259
260
	/**
261
	 * Get the component prefix.
262
	 *
263
	 * @return  string
264
	 */
265 11
	public function getPrefix()
266
	{
267 11
		if (null === $this->prefix)
268
		{
269 11
			$parts = array_map(
270 11
				function ($part)
271
				{
272 11
					return ucfirst(strtolower($part));
273 11
				},
274 11
				explode('_', substr($this->option, 4))
275
			);
276
277 11
			$this->prefix = implode('_', $parts);
278
		}
279
280 11
		return $this->prefix;
281
	}
282
283
	/**
284
	 * Get a component table.
285
	 *
286
	 * @param   string   $name     Name of the table to load. Example: Article
287
	 * @param   array    $config   Optional array of configuration for the table
288
	 *
289
	 * @return  \JTable
290
	 *
291
	 * @throws  \InvalidArgumentException  If not found
292
	 */
293 3
	public function table($name, array $config = array())
294
	{
295 3
		$prefix = $this->getPrefix() . 'Table';
296
297 3
		\JTable::addIncludePath($this->getTablesFolder());
298
299 3
		$table = \JTable::getInstance($name, $prefix, $config);
300
301 3
		if (!$table instanceof \JTable)
0 ignored issues
show
Bug introduced by
The class JTable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
302
		{
303 1
			throw new \InvalidArgumentException(
304 1
				sprintf("Cannot find the table `%s` in `%s` component's `%s` folder.", $prefix . $name, $this->option, $this->client->getName())
305
			);
306
		}
307
308 2
		return $table;
309
	}
310
311
	/**
312
	 * Load extension from DB.
313
	 *
314
	 * @return  \stdClass
315
	 */
316 3
	protected function loadExtension()
317
	{
318 3
		$db = \JFactory::getDbo();
319 3
		$query = $db->getQuery(true)
320 3
			->select('*')
321 3
			->from('#__extensions')
322 3
			->where('type = ' . $db->quote('component'))
323 3
			->where('element = ' . $db->q($this->option));
324
325 3
		$db->setQuery($query);
326
327 3
		return $db->loadObject() ?: new \stdClass;
328
	}
329
330
	/**
331
	 * Load parameters from database.
332
	 *
333
	 * @return  Registry
334
	 */
335 2
	protected function loadParams()
336
	{
337 2
		return new Registry($this->getExtensionProperty('params', array()));
338
	}
339
340
	/**
341
	 * Save parameters to database.
342
	 *
343
	 * @return  boolean
344
	 */
345 1
	public function saveParams()
346
	{
347 1
		$db = \JFactory::getDbo();
348
349 1
		$query = $db->getQuery(true)
350 1
			->update('#__extensions')
351 1
			->set('params = ' . $db->q($this->getParams()->toString()))
352 1
			->where('type = ' . $db->quote('component'))
353 1
			->where('element = ' . $db->q($this->option));
354
355 1
		$db->setQuery($query);
356
357 1
		return $db->execute() ? true : false;
358
	}
359
360
	/**
361
	 * Switch to site client.
362
	 *
363
	 * @return  self
364
	 */
365 3
	public function site()
366
	{
367 3
		$this->client = new Site;
368
369 3
		return $this;
370
	}
371
}
372