Completed
Push — master ( 5776a0...605463 )
by Daniel
23s
created

ViewableData::setField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 5
rs 9.4285
c 1
b 1
f 0
1
<?php
2
3
use SilverStripe\ORM\FieldType\DBField;
4
5
/**
6
 * A ViewableData object is any object that can be rendered into a template/view.
7
 *
8
 * A view interrogates the object being currently rendered in order to get data to render into the template. This data
9
 * is provided and automatically escaped by ViewableData. Any class that needs to be available to a view (controllers,
10
 * {@link DataObject}s, page controls) should inherit from this class.
11
 *
12
 * @package framework
13
 * @subpackage view
14
 */
15
class ViewableData extends Object implements IteratorAggregate {
16
17
	/**
18
	 * An array of objects to cast certain fields to. This is set up as an array in the format:
19
	 *
20
	 * <code>
21
	 * public static $casting = array (
22
	 *     'FieldName' => 'ClassToCastTo(Arguments)'
23
	 * );
24
	 * </code>
25
	 *
26
	 * @var array
27
	 * @config
28
	 */
29
	private static $casting = array(
30
		'CSSClasses' => 'Varchar'
31
	);
32
33
	/**
34
	 * The default object to cast scalar fields to if casting information is not specified, and casting to an object
35
	 * is required.
36
	 *
37
	 * @var string
38
	 * @config
39
	 */
40
	private static $default_cast = 'Text';
41
42
	/**
43
	 * @var array
44
	 */
45
	private static $casting_cache = array();
46
47
	// -----------------------------------------------------------------------------------------------------------------
48
49
	/**
50
	 * A failover object to attempt to get data from if it is not present on this object.
51
	 *
52
	 * @var ViewableData
53
	 */
54
	protected $failover;
55
56
	/**
57
	 * @var ViewableData
58
	 */
59
	protected $customisedObject;
60
61
	/**
62
	 * @var array
63
	 */
64
	private $objCache = array();
65
66
	// -----------------------------------------------------------------------------------------------------------------
67
68
	// FIELD GETTERS & SETTERS -----------------------------------------------------------------------------------------
69
70
	/**
71
	 * Check if a field exists on this object or its failover.
72
	 *
73
	 * @param string $property
74
	 * @return bool
75
	 */
76
	public function __isset($property) {
77
		return $this->hasField($property) || ($this->failover && $this->failover->hasField($property));
78
	}
79
80
	/**
81
	 * Get the value of a property/field on this object. This will check if a method called get{$property} exists, then
82
	 * check if a field is available using {@link ViewableData::getField()}, then fall back on a failover object.
83
	 *
84
	 * @param string $property
85
	 * @return mixed
86
	 */
87
	public function __get($property) {
88
		if($this->hasMethod($method = "get$property")) {
89
			return $this->$method();
90
		} elseif($this->hasField($property)) {
91
			return $this->getField($property);
92
		} elseif($this->failover) {
93
			return $this->failover->$property;
94
		}
95
		return null;
96
	}
97
98
	/**
99
	 * Set a property/field on this object. This will check for the existence of a method called set{$property}, then
100
	 * use the {@link ViewableData::setField()} method.
101
	 *
102
	 * @param string $property
103
	 * @param mixed $value
104
	 */
105
	public function __set($property, $value) {
106
		$this->objCacheClear();
107
		if($this->hasMethod($method = "set$property")) {
108
			$this->$method($value);
109
		} else {
110
			$this->setField($property, $value);
111
		}
112
	}
113
114
	/**
115
	 * Set a failover object to attempt to get data from if it is not present on this object.
116
	 *
117
	 * @param ViewableData $failover
118
	 */
119
	public function setFailover(ViewableData $failover) {
120
		// Ensure cached methods from previous failover are removed
121
		if ($this->failover) {
122
			$this->removeMethodsFrom('failover');
123
		}
124
125
		$this->failover = $failover;
126
		$this->defineMethods();
127
	}
128
129
	/**
130
	 * Get the current failover object if set
131
	 *
132
	 * @return ViewableData|null
133
	 */
134
	public function getFailover() {
135
		return $this->failover;
136
	}
137
138
	/**
139
	 * Check if a field exists on this object. This should be overloaded in child classes.
140
	 *
141
	 * @param string $field
142
	 * @return bool
143
	 */
144
	public function hasField($field) {
145
		return property_exists($this, $field);
146
	}
147
148
	/**
149
	 * Get the value of a field on this object. This should be overloaded in child classes.
150
	 *
151
	 * @param string $field
152
	 * @return mixed
153
	 */
154
	public function getField($field) {
155
		return $this->$field;
156
	}
157
158
	/**
159
	 * Set a field on this object. This should be overloaded in child classes.
160
	 *
161
	 * @param string $field
162
	 * @param mixed $value
163
	 * @return $this
164
	 */
165
	public function setField($field, $value) {
166
		$this->objCacheClear();
167
		$this->$field = $value;
168
		return $this;
169
	}
170
171
	// -----------------------------------------------------------------------------------------------------------------
172
173
	/**
174
	 * Add methods from the {@link ViewableData::$failover} object, as well as wrapping any methods prefixed with an
175
	 * underscore into a {@link ViewableData::cachedCall()}.
176
	 *
177
	 * @throws LogicException
178
	 */
179
	public function defineMethods() {
0 ignored issues
show
Coding Style introduced by
defineMethods uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
180
		if($this->failover && !is_object($this->failover)) {
181
			throw new LogicException("ViewableData::\$failover set to a non-object");
182
		}
183
		if($this->failover) {
184
			$this->addMethodsFrom('failover');
185
186
			if(isset($_REQUEST['debugfailover'])) {
187
				Debug::message("$this->class created with a failover class of {$this->failover->class}");
188
			}
189
		}
190
191
		parent::defineMethods();
192
	}
193
194
	/**
195
	 * Merge some arbitrary data in with this object. This method returns a {@link ViewableData_Customised} instance
196
	 * with references to both this and the new custom data.
197
	 *
198
	 * Note that any fields you specify will take precedence over the fields on this object.
199
	 *
200
	 * @param array|ViewableData $data
201
	 * @return ViewableData_Customised
202
	 */
203
	public function customise($data) {
204
		if(is_array($data) && (empty($data) || ArrayLib::is_associative($data))) {
205
			$data = new ArrayData($data);
206
		}
207
208
		if($data instanceof ViewableData) {
209
			return new ViewableData_Customised($this, $data);
210
		}
211
212
		throw new InvalidArgumentException (
213
			'ViewableData->customise(): $data must be an associative array or a ViewableData instance'
214
		);
215
	}
216
217
	/**
218
	 * @return ViewableData
219
	 */
220
	public function getCustomisedObj() {
221
		return $this->customisedObject;
222
	}
223
224
	/**
225
	 * @param ViewableData $object
226
	 */
227
	public function setCustomisedObj(ViewableData $object) {
228
		$this->customisedObject = $object;
229
	}
230
231
	// CASTING ---------------------------------------------------------------------------------------------------------
232
233
	/**
234
	 * Return the "casting helper" (a piece of PHP code that when evaluated creates a casted value object)
235
	 * for a field on this object. This helper will be a subclass of DBField.
236
	 *
237
	 * @param string $field
238
	 * @return string Casting helper As a constructor pattern, and may include arguments.
239
	 */
240
	public function castingHelper($field) {
241
		$specs = $this->config()->casting;
0 ignored issues
show
Documentation introduced by
The property casting does not exist on object<Config_ForClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
242
		if(isset($specs[$field])) {
243
			return $specs[$field];
244
		}
245
246
		// If no specific cast is declared, fall back to failover.
247
		// Note that if there is a failover, the default_cast will always
248
		// be drawn from this object instead of the top level object.
249
		$failover = $this->getFailover();
250
		if($failover) {
251
			$cast = $failover->castingHelper($field);
252
			if($cast) {
253
				return $cast;
254
		}
255
	}
256
257
		// Fall back to default_cast
258
		return $this->config()->get('default_cast');
259
	}
260
261
	/**
262
	 * Get the class name a field on this object will be casted to.
263
	 *
264
	 * @param string $field
265
	 * @return string
266
	 */
267
	public function castingClass($field) {
268
		// Strip arguments
269
		$spec = $this->castingHelper($field);
270
		return trim(strtok($spec, '('));
271
	}
272
273
	/**
274
	 * Return the string-format type for the given field.
275
	 *
276
	 * @param string $field
277
	 * @return string 'xml'|'raw'
278
	 */
279
	public function escapeTypeForField($field) {
280
		$class = $this->castingClass($field) ?: $this->config()->default_cast;
281
282
		// TODO: It would be quicker not to instantiate the object, but to merely
283
		// get its class from the Injector
284
		return Injector::inst()->get($class, true)->config()->escape_type;
285
	}
286
287
	// TEMPLATE ACCESS LAYER -------------------------------------------------------------------------------------------
288
289
	/**
290
	 * Render this object into the template, and get the result as a string. You can pass one of the following as the
291
	 * $template parameter:
292
	 *  - a template name (e.g. Page)
293
	 *  - an array of possible template names - the first valid one will be used
294
	 *  - an SSViewer instance
295
	 *
296
	 * @param string|array|SSViewer $template the template to render into
297
	 * @param array $customFields fields to customise() the object with before rendering
298
	 * @return DBHTMLText
299
	 */
300
	public function renderWith($template, $customFields = null) {
301
		if(!is_object($template)) {
302
			$template = new SSViewer($template);
303
		}
304
305
		$data = ($this->customisedObject) ? $this->customisedObject : $this;
306
307
		if($customFields instanceof ViewableData) {
308
			$data = $data->customise($customFields);
309
		}
310
		if($template instanceof SSViewer) {
311
			return $template->process($data, is_array($customFields) ? $customFields : null);
312
		}
313
314
		throw new UnexpectedValueException (
315
			"ViewableData::renderWith(): unexpected $template->class object, expected an SSViewer instance"
316
		);
317
	}
318
319
	/**
320
	 * Generate the cache name for a field
321
	 *
322
	 * @param string $fieldName Name of field
323
	 * @param array $arguments List of optional arguments given
324
	 * @return string
325
	 */
326
	protected function objCacheName($fieldName, $arguments) {
327
		return $arguments
328
			? $fieldName . ":" . implode(',', $arguments)
329
			: $fieldName;
330
	}
331
332
	/**
333
	 * Get a cached value from the field cache
334
	 *
335
	 * @param string $key Cache key
336
	 * @return mixed
337
	 */
338
	protected function objCacheGet($key) {
339
		if(isset($this->objCache[$key])) {
340
			return $this->objCache[$key];
341
		}
342
		return null;
343
	}
344
345
	/**
346
	 * Store a value in the field cache
347
	 *
348
	 * @param string $key Cache key
349
	 * @param mixed $value
350
	 * @return $this
351
	 */
352
	protected function objCacheSet($key, $value) {
353
		$this->objCache[$key] = $value;
354
		return $this;
355
	}
356
357
	/**
358
	 * Clear object cache
359
	 *
360
	 * @return $this
361
	 */
362
	protected function objCacheClear() {
363
		$this->objCache = [];
364
		return $this;
365
	}
366
367
	/**
368
	 * Get the value of a field on this object, automatically inserting the value into any available casting objects
369
	 * that have been specified.
370
	 *
371
	 * @param string $fieldName
372
	 * @param array $arguments
373
	 * @param bool $cache Cache this object
374
	 * @param string $cacheName a custom cache name
375
	 * @return Object|DBField
376
	 */
377
	public function obj($fieldName, $arguments = [], $cache = false, $cacheName = null) {
378
		if(!$cacheName && $cache) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cacheName of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
379
			$cacheName = $this->objCacheName($fieldName, $arguments);
380
		}
381
382
		// Check pre-cached value
383
		$value = $cache ? $this->objCacheGet($cacheName) : null;
384
		if($value !== null) {
385
			return $value;
386
		}
387
388
		// Load value from record
389
		if($this->hasMethod($fieldName)) {
390
			$value = call_user_func_array(array($this, $fieldName), $arguments ?: []);
391
			} else {
392
				$value = $this->$fieldName;
393
			}
394
395
		// Cast object
396
		if(!is_object($value)) {
397
			// Force cast
398
			$castingHelper = $this->castingHelper($fieldName);
399
			$valueObject = Object::create_from_string($castingHelper, $fieldName);
400
			$valueObject->setValue($value, $this);
401
			$value = $valueObject;
402
		}
403
404
		// Record in cache
405
		if($cache) {
406
			$this->objCacheSet($cacheName, $value);
407
		}
408
409
		return $value;
410
	}
411
412
	/**
413
	 * A simple wrapper around {@link ViewableData::obj()} that automatically caches the result so it can be used again
414
	 * without re-running the method.
415
	 *
416
	 * @param string $field
417
	 * @param array $arguments
418
	 * @param string $identifier an optional custom cache identifier
419
	 * @return Object|DBField
420
	 */
421
	public function cachedCall($field, $arguments = [], $identifier = null) {
422
		return $this->obj($field, $arguments, true, $identifier);
423
	}
424
425
	/**
426
	 * Checks if a given method/field has a valid value. If the result is an object, this will return the result of the
427
	 * exists method, otherwise will check if the result is not just an empty paragraph tag.
428
	 *
429
	 * @param string $field
430
	 * @param array $arguments
431
	 * @param bool $cache
432
	 * @return bool
433
	 */
434
	public function hasValue($field, $arguments = [], $cache = true) {
435
		$result = $this->obj($field, $arguments, $cache);
436
			return $result->exists();
437
		}
438
439
	/**
440
	 * Get the string value of a field on this object that has been suitable escaped to be inserted directly into a
441
	 * template.
442
	 *
443
	 * @param string $field
444
	 * @param array $arguments
445
	 * @param bool $cache
446
	 * @return string
447
	 */
448
	public function XML_val($field, $arguments = [], $cache = false) {
449
		$result = $this->obj($field, $arguments, $cache);
450
		// Might contain additional formatting over ->XML(). E.g. parse shortcodes, nl2br()
451
		return $result->forTemplate();
452
	}
453
454
	/**
455
	 * Get an array of XML-escaped values by field name
456
	 *
457
	 * @param array $fields an array of field names
458
	 * @return array
459
	 */
460
	public function getXMLValues($fields) {
461
		$result = array();
462
463
		foreach($fields as $field) {
464
			$result[$field] = $this->XML_val($field);
465
		}
466
467
		return $result;
468
	}
469
470
	// ITERATOR SUPPORT ------------------------------------------------------------------------------------------------
471
472
	/**
473
	 * Return a single-item iterator so you can iterate over the fields of a single record.
474
	 *
475
	 * This is useful so you can use a single record inside a <% control %> block in a template - and then use
476
	 * to access individual fields on this object.
477
	 *
478
	 * @return ArrayIterator
479
	 */
480
	public function getIterator() {
481
		return new ArrayIterator(array($this));
482
	}
483
484
	// UTILITY METHODS -------------------------------------------------------------------------------------------------
485
486
	/**
487
	 * When rendering some objects it is necessary to iterate over the object being rendered, to do this, you need
488
	 * access to itself.
489
	 *
490
	 * @return ViewableData
491
	 */
492
	public function Me() {
493
		return $this;
494
	}
495
496
	/**
497
	 * Return the directory if the current active theme (relative to the site root).
498
	 *
499
	 * This method is useful for things such as accessing theme images from your template without hardcoding the theme
500
	 * page - e.g. <img src="$ThemeDir/images/something.gif">.
501
	 *
502
	 * This method should only be used when a theme is currently active. However, it will fall over to the current
503
	 * project directory.
504
	 *
505
	 * @param string $subtheme the subtheme path to get
506
	 * @return string
507
	 */
508
	public function ThemeDir($subtheme = null) {
509
		if(
510
			Config::inst()->get('SSViewer', 'theme_enabled')
511
			&& $theme = Config::inst()->get('SSViewer', 'theme')
512
		) {
513
			return THEMES_DIR . "/$theme" . ($subtheme ? "_$subtheme" : null);
514
		}
515
516
		return project();
517
	}
518
519
	/**
520
	 * Get part of the current classes ancestry to be used as a CSS class.
521
	 *
522
	 * This method returns an escaped string of CSS classes representing the current classes ancestry until it hits a
523
	 * stop point - e.g. "Page DataObject ViewableData".
524
	 *
525
	 * @param string $stopAtClass the class to stop at (default: ViewableData)
526
	 * @return string
527
	 * @uses ClassInfo
528
	 */
529
	public function CSSClasses($stopAtClass = 'ViewableData') {
530
		$classes       = array();
531
		$classAncestry = array_reverse(ClassInfo::ancestry($this->class));
532
		$stopClasses   = ClassInfo::ancestry($stopAtClass);
533
534
		foreach($classAncestry as $class) {
535
			if(in_array($class, $stopClasses)) break;
536
			$classes[] = $class;
537
		}
538
539
		// optionally add template identifier
540
		if(isset($this->template) && !in_array($this->template, $classes)) {
541
			$classes[] = $this->template;
0 ignored issues
show
Documentation introduced by
The property template does not exist on object<ViewableData>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
542
		}
543
544
		return Convert::raw2att(implode(' ', $classes));
545
	}
546
547
	/**
548
	 * Return debug information about this object that can be rendered into a template
549
	 *
550
	 * @return ViewableData_Debugger
551
	 */
552
	public function Debug() {
553
		return new ViewableData_Debugger($this);
554
	}
555
556
}
557
558
/**
559
 * @package framework
560
 * @subpackage view
561
 */
562
class ViewableData_Customised extends ViewableData {
563
564
	/**
565
	 * @var ViewableData
566
	 */
567
	protected $original, $customised;
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
568
569
	/**
570
	 * Instantiate a new customised ViewableData object
571
	 *
572
	 * @param ViewableData $originalObject
573
	 * @param ViewableData $customisedObject
574
	 */
575
	public function __construct(ViewableData $originalObject, ViewableData $customisedObject) {
576
		$this->original   = $originalObject;
577
		$this->customised = $customisedObject;
578
579
		$this->original->setCustomisedObj($this);
580
581
		parent::__construct();
582
	}
583
584
	public function __call($method, $arguments) {
585
		if($this->customised->hasMethod($method)) {
586
			return call_user_func_array(array($this->customised, $method), $arguments);
587
		}
588
589
		return call_user_func_array(array($this->original, $method), $arguments);
590
	}
591
592
	public function __get($property) {
593
		if(isset($this->customised->$property)) {
594
			return $this->customised->$property;
595
		}
596
597
		return $this->original->$property;
598
	}
599
600
	public function __set($property, $value) {
601
		$this->customised->$property = $this->original->$property = $value;
602
	}
603
604
	public function hasMethod($method) {
605
		return $this->customised->hasMethod($method) || $this->original->hasMethod($method);
606
	}
607
608
	public function cachedCall($field, $arguments = null, $identifier = null) {
609
		if($this->customised->hasMethod($field) || $this->customised->hasField($field)) {
610
			return $this->customised->cachedCall($field, $arguments, $identifier);
611
		}
612
		return $this->original->cachedCall($field, $arguments, $identifier);
613
	}
614
615
	public function obj($fieldName, $arguments = null, $cache = false, $cacheName = null) {
616
		if($this->customised->hasField($fieldName) || $this->customised->hasMethod($fieldName)) {
617
			return $this->customised->obj($fieldName, $arguments, $cache, $cacheName);
618
		}
619
		return $this->original->obj($fieldName, $arguments,  $cache, $cacheName);
620
	}
621
622
}
623
624
/**
625
 * Allows you to render debug information about a {@link ViewableData} object into a template.
626
 *
627
 * @package framework
628
 * @subpackage view
629
 */
630
class ViewableData_Debugger extends ViewableData {
631
632
	/**
633
	 * @var ViewableData
634
	 */
635
	protected $object;
636
637
	/**
638
	 * @param ViewableData $object
639
	 */
640
	public function __construct(ViewableData $object) {
641
		$this->object = $object;
642
		parent::__construct();
643
	}
644
645
	/**
646
	 * @return string The rendered debugger
647
	 */
648
	public function __toString() {
649
		return (string)$this->forTemplate();
650
	}
651
652
	/**
653
	 * Return debugging information, as XHTML. If a field name is passed, it will show debugging information on that
654
	 * field, otherwise it will show information on all methods and fields.
655
	 *
656
	 * @param string $field the field name
657
	 * @return string
658
	 */
659
	public function forTemplate($field = null) {
660
		// debugging info for a specific field
661
		if($field) return "<b>Debugging Information for {$this->class}->{$field}</b><br/>" .
0 ignored issues
show
Bug Best Practice introduced by
The expression $field of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
662
			($this->object->hasMethod($field)? "Has method '$field'<br/>" : null)             .
663
			($this->object->hasField($field) ? "Has field '$field'<br/>"  : null)             ;
664
665
		// debugging information for the entire class
666
		$reflector = new ReflectionObject($this->object);
667
		$debug     = "<b>Debugging Information: all methods available in '{$this->object->class}'</b><br/><ul>";
668
669
		foreach($this->object->allMethodNames() as $method) {
670
			// check that the method is public
671
			if($method[0] === strtoupper($method[0]) && $method[0] != '_') {
672
				if($reflector->hasMethod($method) && $method = $reflector->getMethod($method)) {
673
					if($method->isPublic()) {
674
						$debug .= "<li>\${$method->getName()}";
675
676
						if(count($method->getParameters())) {
677
							$debug .= ' <small>(' . implode(', ', $method->getParameters()) . ')</small>';
678
						}
679
680
						$debug .= '</li>';
681
					}
682
				} else {
683
					$debug .= "<li>\$$method</li>";
684
				}
685
			}
686
		}
687
688
		$debug .= '</ul>';
689
690
		if($this->object->hasMethod('toMap')) {
691
			$debug .= "<b>Debugging Information: all fields available in '{$this->object->class}'</b><br/><ul>";
692
693
			foreach($this->object->toMap() as $field => $value) {
694
				$debug .= "<li>\$$field</li>";
695
			}
696
697
			$debug .= "</ul>";
698
		}
699
700
		// check for an extra attached data
701
		if($this->object->hasMethod('data') && $this->object->data() != $this->object) {
702
			$debug .= ViewableData_Debugger::create($this->object->data())->forTemplate();
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
703
		}
704
705
		return $debug;
706
	}
707
708
}
709