Completed
Push — master ( 02e326...506f7f )
by Joas
14:02
created

Manager::setRequirePNG()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 * @copyright Copyright (c) 2016 Joas Schilling <[email protected]>
5
 *
6
 * @author Björn Schießle <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Roeland Jago Douma <[email protected]>
9
 * @author Thomas Müller <[email protected]>
10
 *
11
 * @license AGPL-3.0
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
namespace OC\Activity;
27
28
29
use OCP\Activity\IConsumer;
30
use OCP\Activity\IEvent;
31
use OCP\Activity\IExtension;
32
use OCP\Activity\IFilter;
33
use OCP\Activity\IManager;
34
use OCP\Activity\IProvider;
35
use OCP\Activity\ISetting;
36
use OCP\IConfig;
37
use OCP\IRequest;
38
use OCP\IUser;
39
use OCP\IUserSession;
40
use OCP\RichObjectStrings\IValidator;
41
42
class Manager implements IManager {
43
	/** @var IRequest */
44
	protected $request;
45
46
	/** @var IUserSession */
47
	protected $session;
48
49
	/** @var IConfig */
50
	protected $config;
51
52
	/** @var IValidator */
53
	protected $validator;
54
55
	/** @var string */
56
	protected $formattingObjectType;
57
58
	/** @var int */
59
	protected $formattingObjectId;
60
61
	/** @var bool */
62
	protected $requirePNG;
63
64
	/** @var string */
65
	protected $currentUserId;
66
67
	/**
68
	 * constructor of the controller
69
	 *
70
	 * @param IRequest $request
71
	 * @param IUserSession $session
72
	 * @param IConfig $config
73
	 * @param IValidator $validator
74
	 */
75
	public function __construct(IRequest $request,
76
								IUserSession $session,
77
								IConfig $config,
78
								IValidator $validator) {
79
		$this->request = $request;
80
		$this->session = $session;
81
		$this->config = $config;
82
		$this->validator = $validator;
83
	}
84
85
	/** @var \Closure[] */
86
	private $consumersClosures = array();
87
88
	/** @var IConsumer[] */
89
	private $consumers = array();
90
91
	/** @var \Closure[] */
92
	private $extensionsClosures = array();
93
94
	/** @var IExtension[] */
95
	private $extensions = array();
96
97
	/** @var array list of filters "name" => "is valid" */
98
	protected $validFilters = array(
99
		'all'	=> true,
100
		'by'	=> true,
101
		'self'	=> true,
102
	);
103
104
	/** @var array list of type icons "type" => "css class" */
105
	protected $typeIcons = array();
106
107
	/** @var array list of special parameters "app" => ["text" => ["parameter" => "type"]] */
108
	protected $specialParameters = array();
109
110
	/**
111
	 * @return \OCP\Activity\IConsumer[]
112
	 */
113 View Code Duplication
	protected function getConsumers() {
114
		if (!empty($this->consumers)) {
115
			return $this->consumers;
116
		}
117
118
		$this->consumers = [];
119
		foreach($this->consumersClosures as $consumer) {
120
			$c = $consumer();
121
			if ($c instanceof IConsumer) {
122
				$this->consumers[] = $c;
123
			} else {
124
				throw new \InvalidArgumentException('The given consumer does not implement the \OCP\Activity\IConsumer interface');
125
			}
126
		}
127
128
		return $this->consumers;
129
	}
130
131
	/**
132
	 * @return \OCP\Activity\IExtension[]
133
	 */
134 View Code Duplication
	protected function getExtensions() {
135
		if (!empty($this->extensions)) {
136
			return $this->extensions;
137
		}
138
139
		$this->extensions = [];
140
		foreach($this->extensionsClosures as $extension) {
141
			$e = $extension();
142
			if ($e instanceof IExtension) {
143
				$this->extensions[] = $e;
144
			} else {
145
				throw new \InvalidArgumentException('The given extension does not implement the \OCP\Activity\IExtension interface');
146
			}
147
		}
148
149
		return $this->extensions;
150
	}
151
152
	/**
153
	 * Generates a new IEvent object
154
	 *
155
	 * Make sure to call at least the following methods before sending it to the
156
	 * app with via the publish() method:
157
	 *  - setApp()
158
	 *  - setType()
159
	 *  - setAffectedUser()
160
	 *  - setSubject()
161
	 *
162
	 * @return IEvent
163
	 */
164
	public function generateEvent() {
165
		return new Event($this->validator);
166
	}
167
168
	/**
169
	 * Publish an event to the activity consumers
170
	 *
171
	 * Make sure to call at least the following methods before sending an Event:
172
	 *  - setApp()
173
	 *  - setType()
174
	 *  - setAffectedUser()
175
	 *  - setSubject()
176
	 *
177
	 * @param IEvent $event
178
	 * @throws \BadMethodCallException if required values have not been set
179
	 */
180
	public function publish(IEvent $event) {
181
		if ($event->getAuthor() === '') {
182
			if ($this->session->getUser() instanceof IUser) {
183
				$event->setAuthor($this->session->getUser()->getUID());
184
			}
185
		}
186
187
		if (!$event->getTimestamp()) {
188
			$event->setTimestamp(time());
189
		}
190
191
		if (!$event->isValid()) {
192
			throw new \BadMethodCallException('The given event is invalid');
193
		}
194
195
		foreach ($this->getConsumers() as $c) {
196
			$c->receive($event);
197
		}
198
	}
199
200
	/**
201
	 * In order to improve lazy loading a closure can be registered which will be called in case
202
	 * activity consumers are actually requested
203
	 *
204
	 * $callable has to return an instance of OCA\Activity\IConsumer
205
	 *
206
	 * @param \Closure $callable
207
	 */
208
	public function registerConsumer(\Closure $callable) {
209
		$this->consumersClosures[] = $callable;
210
		$this->consumers = [];
211
	}
212
213
	/**
214
	 * In order to improve lazy loading a closure can be registered which will be called in case
215
	 * activity consumers are actually requested
216
	 *
217
	 * $callable has to return an instance of OCA\Activity\IExtension
218
	 *
219
	 * @param \Closure $callable
220
	 */
221
	public function registerExtension(\Closure $callable) {
222
		$this->extensionsClosures[] = $callable;
223
		$this->extensions = [];
224
	}
225
226
	/** @var string[] */
227
	protected $filterClasses = [];
228
229
	/** @var IFilter[] */
230
	protected $filters = [];
231
232
	/** @var bool */
233
	protected $loadedLegacyFilters = false;
234
235
	/**
236
	 * @param string $filter Class must implement OCA\Activity\IFilter
237
	 * @return void
238
	 */
239
	public function registerFilter($filter) {
240
		$this->filterClasses[$filter] = false;
241
	}
242
243
	/**
244
	 * @return IFilter[]
245
	 * @throws \InvalidArgumentException
246
	 */
247
	public function getFilters() {
248
		if (!$this->loadedLegacyFilters) {
249
			$legacyFilters = $this->getNavigation();
250
251 View Code Duplication
			foreach ($legacyFilters['top'] as $filter => $data) {
252
				$this->filters[$filter] = new LegacyFilter(
253
					$this, $filter, $data['name'], true
254
				);
255
			}
256
257 View Code Duplication
			foreach ($legacyFilters['apps'] as $filter => $data) {
258
				$this->filters[$filter] = new LegacyFilter(
259
					$this, $filter, $data['name'], false
260
				);
261
			}
262
			$this->loadedLegacyFilters = true;
263
		}
264
265 View Code Duplication
		foreach ($this->filterClasses as $class => $false) {
266
			/** @var IFilter $filter */
267
			$filter = \OC::$server->query($class);
268
269
			if (!$filter instanceof IFilter) {
270
				throw new \InvalidArgumentException('Invalid activity filter registered');
271
			}
272
273
			$this->filters[$filter->getIdentifier()] = $filter;
274
275
			unset($this->filterClasses[$class]);
276
		}
277
		return $this->filters;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->filters; (array<*,OCP\Activity\IFilter>) is incompatible with the return type declared by the interface OCP\Activity\IManager::getFilters of type OCP\Activity\IFilter[].

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...
278
	}
279
280
	/**
281
	 * @param string $id
282
	 * @return IFilter
283
	 * @throws \InvalidArgumentException when the filter was not found
284
	 * @since 11.0.0
285
	 */
286
	public function getFilterById($id) {
287
		$filters = $this->getFilters();
288
289
		if (isset($filters[$id])) {
290
			return $filters[$id];
291
		}
292
293
		throw new \InvalidArgumentException('Requested filter does not exist');
294
	}
295
296
	/** @var string[] */
297
	protected $providerClasses = [];
298
299
	/** @var IProvider[] */
300
	protected $providers = [];
301
302
	/**
303
	 * @param string $provider Class must implement OCA\Activity\IProvider
304
	 * @return void
305
	 */
306
	public function registerProvider($provider) {
307
		$this->providerClasses[$provider] = false;
308
	}
309
310
	/**
311
	 * @return IProvider[]
312
	 * @throws \InvalidArgumentException
313
	 */
314
	public function getProviders() {
315
		foreach ($this->providerClasses as $class => $false) {
316
			/** @var IProvider $provider */
317
			$provider = \OC::$server->query($class);
318
319
			if (!$provider instanceof IProvider) {
320
				throw new \InvalidArgumentException('Invalid activity provider registered');
321
			}
322
323
			$this->providers[] = $provider;
324
325
			unset($this->providerClasses[$class]);
326
		}
327
		return $this->providers;
328
	}
329
330
	/** @var string[] */
331
	protected $settingsClasses = [];
332
333
	/** @var ISetting[] */
334
	protected $settings = [];
335
336
	/** @var bool */
337
	protected $loadedLegacyTypes = false;
338
339
	/**
340
	 * @param string $setting Class must implement OCA\Activity\ISetting
341
	 * @return void
342
	 */
343
	public function registerSetting($setting) {
344
		$this->settingsClasses[$setting] = false;
345
	}
346
347
	/**
348
	 * @return ISetting[]
349
	 * @throws \InvalidArgumentException
350
	 */
351
	public function getSettings() {
352
		if (!$this->loadedLegacyTypes) {
353
			$l = \OC::$server->getL10N('core');
354
			$legacyTypes = $this->getNotificationTypes($l->getLanguageCode());
355
			$streamTypes = $this->getDefaultTypes(IExtension::METHOD_STREAM);
356
			$mailTypes = $this->getDefaultTypes(IExtension::METHOD_MAIL);
357
			foreach ($legacyTypes as $type => $data) {
358
				if (is_string($data)) {
359
					$desc = $data;
360
					$canChangeStream = true;
361
					$canChangeMail = true;
362
				} else {
363
					$desc = $data['desc'];
364
					$canChangeStream = in_array(IExtension::METHOD_STREAM, $data['methods']);
365
					$canChangeMail = in_array(IExtension::METHOD_MAIL, $data['methods']);
366
				}
367
368
				$this->settings[$type] = new LegacySetting(
369
					$type, $desc,
370
					$canChangeStream, in_array($type, $streamTypes),
371
					$canChangeMail, in_array($type, $mailTypes)
372
				);
373
			}
374
			$this->loadedLegacyTypes = true;
375
		}
376
377 View Code Duplication
		foreach ($this->settingsClasses as $class => $false) {
378
			/** @var ISetting $setting */
379
			$setting = \OC::$server->query($class);
380
381
			if (!$setting instanceof ISetting) {
382
				throw new \InvalidArgumentException('Invalid activity filter registered');
383
			}
384
385
			$this->settings[$setting->getIdentifier()] = $setting;
386
387
			unset($this->settingsClasses[$class]);
388
		}
389
		return $this->settings;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->settings; (array<*,OCP\Activity\ISetting>) is incompatible with the return type declared by the interface OCP\Activity\IManager::getSettings of type OCP\Activity\ISetting[].

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...
390
	}
391
392
	/**
393
	 * @param string $id
394
	 * @return ISetting
395
	 * @throws \InvalidArgumentException when the setting was not found
396
	 * @since 11.0.0
397
	 */
398
	public function getSettingById($id) {
399
		$settings = $this->getSettings();
400
401
		if (isset($settings[$id])) {
402
			return $settings[$id];
403
		}
404
405
		throw new \InvalidArgumentException('Requested setting does not exist');
406
	}
407
408
	/**
409
	 * @param string $type
410
	 * @return string
411
	 */
412
	public function getTypeIcon($type) {
413
		if (isset($this->typeIcons[$type])) {
414
			return $this->typeIcons[$type];
415
		}
416
417
		foreach ($this->getExtensions() as $c) {
418
			$icon = $c->getTypeIcon($type);
419
			if (is_string($icon)) {
420
				$this->typeIcons[$type] = $icon;
421
				return $icon;
422
			}
423
		}
424
425
		$this->typeIcons[$type] = '';
426
		return '';
427
	}
428
429
	/**
430
	 * @param string $type
431
	 * @param string $id
432
	 */
433
	public function setFormattingObject($type, $id) {
434
		$this->formattingObjectType = $type;
435
		$this->formattingObjectId = (string) $id;
0 ignored issues
show
Documentation Bug introduced by
The property $formattingObjectId was declared of type integer, but (string) $id is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
436
	}
437
438
	/**
439
	 * @return bool
440
	 */
441
	public function isFormattingFilteredObject() {
442
		return $this->formattingObjectType !== null && $this->formattingObjectId !== null
443
			&& $this->formattingObjectType === $this->request->getParam('object_type')
444
			&& $this->formattingObjectId === $this->request->getParam('object_id');
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->formattingObjectId (integer) and $this->request->getParam('object_id') (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
445
	}
446
447
	/**
448
	 * @param bool $status Set to true, when parsing events should not use SVG icons
449
	 */
450
	public function setRequirePNG($status) {
451
		$this->requirePNG = $status;
452
	}
453
454
	/**
455
	 * @return bool
456
	 */
457
	public function getRequirePNG() {
458
		return $this->requirePNG;
459
	}
460
461
	/**
462
	 * @param string $app
463
	 * @param string $text
464
	 * @param array $params
465
	 * @param boolean $stripPath
466
	 * @param boolean $highlightParams
467
	 * @param string $languageCode
468
	 * @return string|false
469
	 */
470
	public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) {
471
		foreach ($this->getExtensions() as $c) {
472
			$translation = $c->translate($app, $text, $params, $stripPath, $highlightParams, $languageCode);
473
			if (is_string($translation)) {
474
				return $translation;
475
			}
476
		}
477
478
		return false;
479
	}
480
481
	/**
482
	 * @param string $app
483
	 * @param string $text
484
	 * @return array|false
485
	 */
486
	public function getSpecialParameterList($app, $text) {
487
		if (isset($this->specialParameters[$app][$text])) {
488
			return $this->specialParameters[$app][$text];
489
		}
490
491
		if (!isset($this->specialParameters[$app])) {
492
			$this->specialParameters[$app] = array();
493
		}
494
495
		foreach ($this->getExtensions() as $c) {
496
			$specialParameter = $c->getSpecialParameterList($app, $text);
497
			if (is_array($specialParameter)) {
498
				$this->specialParameters[$app][$text] = $specialParameter;
499
				return $specialParameter;
500
			}
501
		}
502
503
		$this->specialParameters[$app][$text] = false;
504
		return false;
505
	}
506
507
	/**
508
	 * @param array $activity
509
	 * @return integer|false
510
	 */
511
	public function getGroupParameter($activity) {
512
		foreach ($this->getExtensions() as $c) {
513
			$parameter = $c->getGroupParameter($activity);
514
			if ($parameter !== false) {
515
				return $parameter;
516
			}
517
		}
518
519
		return false;
520
	}
521
522
	/**
523
	 * Set the user we need to use
524
	 *
525
	 * @param string|null $currentUserId
526
	 * @throws \UnexpectedValueException If the user is invalid
527
	 */
528
	public function setCurrentUserId($currentUserId) {
529
		if (!is_string($currentUserId) && $currentUserId !== null) {
530
			throw new \UnexpectedValueException('The given current user is invalid');
531
		}
532
		$this->currentUserId = $currentUserId;
533
	}
534
535
	/**
536
	 * Get the user we need to use
537
	 *
538
	 * Either the user is logged in, or we try to get it from the token
539
	 *
540
	 * @return string
541
	 * @throws \UnexpectedValueException If the token is invalid, does not exist or is not unique
542
	 */
543
	public function getCurrentUserId() {
544
		if ($this->currentUserId !== null) {
545
			return $this->currentUserId;
546
		} else if (!$this->session->isLoggedIn()) {
547
			return $this->getUserFromToken();
548
		} else {
549
			return $this->session->getUser()->getUID();
550
		}
551
	}
552
553
	/**
554
	 * Get the user for the token
555
	 *
556
	 * @return string
557
	 * @throws \UnexpectedValueException If the token is invalid, does not exist or is not unique
558
	 */
559
	protected function getUserFromToken() {
560
		$token = (string) $this->request->getParam('token', '');
561
		if (strlen($token) !== 30) {
562
			throw new \UnexpectedValueException('The token is invalid');
563
		}
564
565
		$users = $this->config->getUsersForUserValue('activity', 'rsstoken', $token);
566
567
		if (count($users) !== 1) {
568
			// No unique user found
569
			throw new \UnexpectedValueException('The token is invalid');
570
		}
571
572
		// Token found login as that user
573
		return array_shift($users);
574
	}
575
576
	/**
577
	 * @return array
578
	 * @deprecated 11.0.0 - Use getFilters() instead
579
	 */
580
	public function getNavigation() {
581
		$entries = array(
582
			'apps' => array(),
583
			'top' => array(),
584
		);
585
		foreach ($this->getExtensions() as $c) {
586
			$additionalEntries = $c->getNavigation();
587
			if (is_array($additionalEntries)) {
588
				$entries['apps'] = array_merge($entries['apps'], $additionalEntries['apps']);
589
				$entries['top'] = array_merge($entries['top'], $additionalEntries['top']);
590
			}
591
		}
592
593
		return $entries;
594
	}
595
596
	/**
597
	 * @param string $filterValue
598
	 * @return boolean
599
	 * @deprecated 11.0.0 - Use getFilterById() instead
600
	 */
601
	public function isFilterValid($filterValue) {
602
		if (isset($this->validFilters[$filterValue])) {
603
			return $this->validFilters[$filterValue];
604
		}
605
606
		foreach ($this->getExtensions() as $c) {
607
			if ($c->isFilterValid($filterValue) === true) {
608
				$this->validFilters[$filterValue] = true;
609
				return true;
610
			}
611
		}
612
613
		$this->validFilters[$filterValue] = false;
614
		return false;
615
	}
616
617
	/**
618
	 * @param array $types
619
	 * @param string $filter
620
	 * @return array
621
	 * @deprecated 11.0.0 - Use getFilterById()->filterTypes() instead
622
	 */
623
	public function filterNotificationTypes($types, $filter) {
624
		if (!$this->isFilterValid($filter)) {
625
			return $types;
626
		}
627
628
		foreach ($this->getExtensions() as $c) {
629
			$result = $c->filterNotificationTypes($types, $filter);
630
			if (is_array($result)) {
631
				$types = $result;
632
			}
633
		}
634
		return $types;
635
	}
636
637
	/**
638
	 * @param string $filter
639
	 * @return array
640
	 * @deprecated 11.0.0 - Use getFilterById() instead
641
	 */
642
	public function getQueryForFilter($filter) {
643
		if (!$this->isFilterValid($filter)) {
644
			return [null, null];
645
		}
646
647
		$conditions = array();
648
		$parameters = array();
649
650
		foreach ($this->getExtensions() as $c) {
651
			$result = $c->getQueryForFilter($filter);
652
			if (is_array($result)) {
653
				list($condition, $parameter) = $result;
654
				if ($condition && is_array($parameter)) {
655
					$conditions[] = $condition;
656
					$parameters = array_merge($parameters, $parameter);
657
				}
658
			}
659
		}
660
661
		if (empty($conditions)) {
662
			return array(null, null);
663
		}
664
665
		return array(' and ((' . implode(') or (', $conditions) . '))', $parameters);
666
	}
667
668
	/**
669
	 * Will return additional notification types as specified by other apps
670
	 *
671
	 * @param string $languageCode
672
	 * @return array
673
	 * @deprecated 11.0.0 - Use getSettings() instead
674
	 */
675
	public function getNotificationTypes($languageCode) {
676
		$notificationTypes = $sharingNotificationTypes = [];
677
		foreach ($this->getExtensions() as $c) {
678
			$result = $c->getNotificationTypes($languageCode);
679
			if (is_array($result)) {
680
				$notificationTypes = array_merge($notificationTypes, $result);
681
			}
682
		}
683
684
		return array_merge($sharingNotificationTypes, $notificationTypes);
685
	}
686
687
	/**
688
	 * @param string $method
689
	 * @return array
690
	 * @deprecated 11.0.0 - Use getSettings()->isDefaulEnabled<method>() instead
691
	 */
692
	public function getDefaultTypes($method) {
693
		$defaultTypes = array();
694
		foreach ($this->getExtensions() as $c) {
695
			$types = $c->getDefaultTypes($method);
696
			if (is_array($types)) {
697
				$defaultTypes = array_merge($types, $defaultTypes);
698
			}
699
		}
700
		return $defaultTypes;
701
	}
702
}
703