1 <?php
2
3 /**
4 * @copyright Copyright (c) 2016 Junaid Atari
5 * @link http://junaidatari.com Website
6 * @see http://www.github.com/blacksmoke26/yii2-cdn
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
8 */
9
10 namespace yii2cdn;
11
12 use yii\base\InvalidParamException;
13 use yii\base\InvalidValueException;
14 use yii\base\UnknownPropertyException;
15
16 /**
17 * Yii2 CDN Component object
18 *
19 * @package yii2cdn
20 * @author Junaid Atari <mj.atari@gmail.com>
21 *
22 * @access public
23 * @version 0.1
24 */
25 class Component {
26
27 /**
28 * Component ID
29 * @var string
30 */
31 protected $id;
32
33 /**
34 * Component's base url
35 * @var string
36 */
37 protected $baseUrl;
38
39 /**
40 * Sections list
41 * @var Section[]
42 */
43 protected $sections = [];
44
45 /**
46 * CDN sections name
47 * @var array
48 */
49 protected $sectionsName = [];
50
51 /**
52 * Component constructor.
53 *
54 * @param string $id Component ID
55 * @param array $config Configuration
56 */
57 public function __construct ( array $config ) {
58 $this->baseUrl = $config['baseUrl'];
59 $this->id = $config['id'];
60 $this->sectionsName = $config['sections'];
61 $this->buildSections($config);
62 }
63
64 /**
65 * Create the component section object from config<br>
66 * Note: Empty sections will be removed
67 *
68 * @param array $config Configuration object
69 */
70 protected function buildSections ( array $config ) {
71 foreach ( $this->sectionsName as $name ) {
72
73 if ( !array_key_exists($name, $config) || empty($config[$name]) ) {
74 continue;
75 }
76
77 $_attributes = isset ($config['fileAttrs'])
78 ? isset($config['fileAttrs'][$name]) ? $config['fileAttrs'][$name] : []
79 : [];
80
81 // Create section(s) component
82 /** @var Section $section */
83 $this->sections[$name] = \Yii::createObject($config['sectionClass'], [[
84 'componentId' => $this->id,
85 'section' =>$name,
86 'files' => $config[$name],
87 'baseUrl' => rtrim($this->baseUrl, '/'). "/{$name}",
88 'attributes' => $_attributes,
89 'fileClass' => $config['fileClass'],
90 ]]);
91 }
92 }
93
94 /**
95 * Get the component's base Url
96 *
97 * @param null|string|array $str (optional) Append string at end of url (/ is optional) | List of strings to append url with (default: null)
98 * @return string|array
99 */
100 public function getUrl ( $str = null ) {
101 if ( $str === null || empty($str) ) {
102 return $this->baseUrl;
103 }
104
105 if ( !is_string ($str) && !is_array($str) ) {
106 throw new InvalidParamException ("Parameter 'str' should be string or an array.");
107 }
108
109 $list = is_string ( $str)
110 ? [$str]
111 : $str;
112
113 $newList = [];
114
115 foreach ( $list as $itm ) {
116 $newList[] = $this->baseUrl . (substr ( $itm,0,1) !== '/' ? '/' . $itm : $itm);
117 }
118
119 return count($newList) === 1
120 ? array_shift($newList)
121 : $newList;
122 }
123
124 /**
125 * Get a javaScript files list
126 * @param boolean $asUrl (optional) True will return files url only (default: false)
127 * @param boolean $unique (optional) True will remove duplicate elements (default: true)
128 * @return array List of js section files
129 */
130 public function getJsFiles ( $asUrl = false, $unique = true ) {
131 $files = $this->getSection ( 'js' )->getFiles ( true, $unique );
132
133 if ( !$asUrl ) {
134 return $files;
135 }
136
137 return array_values ( $files );
138 }
139
140 /**
141 * Get a section(s) object by ID
142 * @param string|array Section name|List of sections name
143 * @param boolean $throwException (optional) True will throw exception when section name not found (default: true)
144 * @throws \yii\base\InvalidParamException When null given as section
145 * @throws \yii\base\UnknownPropertyException When section name not found
146 * @return Section|array|null Section | Sections List | Null when not found
147 */
148 public function getSection ( $name, $throwException = true ) {
149 $sections = $name;
150
151 if ( !is_array($name) ) {
152 $sections = [$name];
153 }
154
155 $list = [];
156
157 foreach ( $sections as $name ) {
158 if ( !$this->sectionExists($name, $throwException ) ) {
159 continue;
160 }
161
162 $list[] = $this->sections[$name];
163 }
164
165 return count($list) == 1 ? array_shift($list) : $list;
166 }
167
168 /**
169 * Check that given section exists
170 * @param string $name Section name to check
171 * @param boolean $throwException (optional) True will throw exception when section name not found (default: false)
172 * @throws \yii\base\InvalidValueException When section name is empty
173 * @throws \yii\base\UnknownPropertyException When section name not found
174 * @return True on exist | False when not found
175 */
176 public function sectionExists ( $name, $throwException = true ) {
177 if ( empty($name) ) {
178 if ( $throwException ) {
179 throw new InvalidValueException ('Section name cannot be empty');
180 }
181
182 return false;
183 }
184
185 if ( !array_key_exists($name, $this->sections) ) {
186
187 if ( $throwException ) {
188 throw new UnknownPropertyException ("Section '{$name}' not found");
189 }
190
191 return false;
192 }
193
194 return true;
195 }
196
197 /**
198 * Get style files list
199 * @param boolean $asUrl (optional) True will return files url only (default: false)
200 * @param boolean $unique (optional) True will remove duplicate elements (default: true)
201 * @return array List of css section files
202 */
203 public function getCssFiles ( $asUrl = true, $unique = true ) {
204 $files = $this->getSection('css')->getFiles(true, $unique);
205
206 if ( !$asUrl ) {
207 return $files;
208 }
209
210 return array_values($files);
211 }
212
213 /**
214 * Register css and js files into current view
215 * @see Component::registerCssFiles() for $cssOptions
216 * @see Component::registerJsFiles() for $jsOptions
217 *
218 * @param array $cssOptions (optional) Optional pass to css files
219 * @param array $jsOptions (optional) Optional pass to js files
220 * @param callable|null $callback (optional) Perform callback on each registering file
221 * <code>
222 * function ( string $fileUrl, string $fileId ) {
223 * // some logic here ...
224 * }
225 * </code>
226 */
227 public function register ( array $cssOptions = [], array $jsOptions = [], callable $callback = null ) {
228 $this->registerCssFiles ( $cssOptions, $callback );
229 $this->registerJsFiles ( $jsOptions, $callback );
230 }
231
232 /**
233 * Register component CSS files
234 * @see Section::registerFilesAs()
235 * @param array $options the HTML attributes for the link tag. Please refer to [[Html::cssFile()]] for
236 * the supported options. The following options are specially handled and are not treated as HTML attributes:
237 *
238 * - `depends`: array, specifies the names of the asset bundles that this CSS file depends on.
239 *
240 * @param callable|null $callback (optional) Perform callback on each registering file
241 * <code>
242 * function ( string &$fileUrl, string &$fileId ) {
243 * // some logic here ...
244 * }
245 * </code>
246 */
247 public function registerCssFiles( array $options = [], callable $callback = null ) {
248 if ( !$this->sectionExists('css', false ) ) {
249 return;
250 }
251
252 $this->getSection('css')->registerFilesAs ('css', null, $options, $callback );
253 }
254
255 /**
256 * Register component JavaScript files
257 * @see Section::registerFilesAs()
258 * @param array $options the HTML attributes for the script tag. The following options are specially handled
259 * and are not treated as HTML attributes:
260 *
261 * - `depends`: array, specifies the names of the asset bundles that this JS file depends on.
262 * - `position`: specifies where the JS script tag should be inserted in a page. The possible values are:
263 * * [[POS_HEAD]]: in the head section
264 * * [[POS_BEGIN]]: at the beginning of the body section
265 * * [[POS_END]]: at the end of the body section. This is the default value.
266 *
267 * Please refer to [[Html::jsFile()]] for other supported options.
268 *
269 * @param callable|null $callback (optional) Perform callback on each registering file
270 * <code>
271 * function ( string &$fileUrl, string &$fileId ) {
272 * // some logic here ...
273 * }
274 * </code>
275 */
276 public function registerJsFiles( array $options = [], callable $callback = null ) {
277 if ( !$this->sectionExists('js', false ) ) {
278 return;
279 }
280
281 $this->getSection('js')->registerFilesAs('js', null, $options, $callback );
282 }
283
284 /**
285 * Get the file by root
286 * Root example : section/file-id
287 * @see Section::getSection()
288 * @see Section::getFileById()
289 * @param string $root Root to file
290 * @param bool $asUrl True will return file url instead of object (default: false)
291 * @param bool $throwException True will throw exception (default: true)
292 * @throws \yii\base\InvalidParamException When null given as section
293 * @throws \yii\base\UnknownPropertyException When section name not found
294 * @throws \yii\base\UnknownPropertyException When file id not found
295 * @return \yii2cdn\File|string|null Section file | File Url | Null when not found
296 */
297 public function getFileByRoot ( $root, $asUrl = false, $throwException = true ) {
298 // validate the root
299 if ( !is_string($root) || substr_count($root, '/') != 1 ) {
300 throw new InvalidParamException ("Invalid root '{$root}' given");
301 }
302
303 list ($sectionId, $fileId) = explode('/', $root);
304
305 return $this->getSection($sectionId, $throwException)
306 ->getFileById ($fileId, $asUrl, $throwException);
307 }
308 }
309