Completed
Push — master ( 09961e...377d07 )
by Jeroen De
24s
created

DataValueDeserializer::assertAreDataValueClasses()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 9
rs 8.8571
cc 5
eloc 5
nc 3
nop 1
1
<?php
2
3
namespace DataValues\Deserializers;
4
5
use DataValues\DataValue;
6
use Deserializers\DispatchableDeserializer;
7
use Deserializers\Exceptions\DeserializationException;
8
use Deserializers\Exceptions\MissingAttributeException;
9
use Deserializers\Exceptions\MissingTypeException;
10
use Deserializers\Exceptions\UnsupportedTypeException;
11
use InvalidArgumentException;
12
use RuntimeException;
13
14
/**
15
 * @since 0.1
16
 *
17
 * @license GPL-2.0+
18
 * @author Jeroen De Dauw < [email protected] >
19
 * @author Thiemo Mättig
20
 */
21
class DataValueDeserializer implements DispatchableDeserializer {
22
23
	const TYPE_KEY = 'type';
24
	const VALUE_KEY = 'value';
25
26
	/**
27
	 * @var array Associative array mapping data type IDs to either callables returning new
28
	 *  DataValue objects, or full qualified DataValue class names.
29
	 */
30
	private $builders;
31
32
	private $serialization;
33
34
	/**
35
	 * @since 0.1, callables are supported since 1.1
36
	 *
37
	 * @param array $builders Associative array mapping data type IDs to either callables, or full
38
	 *  qualified class names. Callables must accept a single value as specified by the
39
	 *  corresponding DataValue::getArrayValue, and return a new DataValue object. DataValue classes
40
	 *  given via class name must implement a static newFromArray method doing the same.
41
	 */
42
	public function __construct( array $builders = array() ) {
43
		$this->assertAreDataValueClasses( $builders );
44
		$this->builders = $builders;
45
	}
46
47
	private function assertAreDataValueClasses( array $builders ) {
48
		foreach ( $builders as $type => $builder ) {
49
			if ( !is_string( $type )
50
				|| ( !is_callable( $builder ) && !$this->isDataValueClass( $builder ) )
51
			) {
52
				throw new InvalidArgumentException( '$builders must map data types to callables or class names' );
53
			}
54
		}
55
	}
56
57
	private function isDataValueClass( $class ) {
58
		return is_string( $class )
59
			&& class_exists( $class )
60
			&& in_array( 'DataValues\DataValue', class_implements( $class ) );
61
	}
62
63
	/**
64
	 * @see DispatchableDeserializer::isDeserializerFor
65
	 *
66
	 * @param mixed $serialization
67
	 *
68
	 * @return bool
69
	 */
70
	public function isDeserializerFor( $serialization ) {
71
		$this->serialization = $serialization;
72
73
		try {
74
			$this->assertCanDeserialize();
75
			return true;
76
		}
77
		catch ( RuntimeException $ex ) {
78
			return false;
79
		}
80
	}
81
82
	/**
83
	 * @see Deserializer::deserialize
84
	 *
85
	 * @param mixed $serialization
86
	 *
87
	 * @throws DeserializationException
88
	 * @return DataValue
89
	 */
90
	public function deserialize( $serialization ) {
91
		$this->serialization = $serialization;
92
93
		$this->assertCanDeserialize();
94
		return $this->getDeserialization();
95
	}
96
97
	private function assertCanDeserialize() {
98
		$this->assertHasSupportedType();
99
		$this->assertHasValue();
100
	}
101
102
	private function assertHasSupportedType() {
103
		if ( !is_array( $this->serialization ) || !array_key_exists( self::TYPE_KEY, $this->serialization ) ) {
104
			throw new MissingTypeException();
105
		}
106
107
		if ( !$this->hasSupportedType() ) {
108
			throw new UnsupportedTypeException( $this->getType() );
109
		}
110
	}
111
112
	private function assertHasValue() {
113
		if ( !array_key_exists( self::VALUE_KEY, $this->serialization ) ) {
114
			throw new MissingAttributeException( self::VALUE_KEY );
115
		}
116
	}
117
118
	private function hasSupportedType() {
119
		return array_key_exists( $this->getType(), $this->builders );
120
	}
121
122
	private function getType() {
123
		return $this->serialization[self::TYPE_KEY];
124
	}
125
126
	/**
127
	 * @throws DeserializationException
128
	 * @return DataValue
129
	 */
130
	private function getDeserialization() {
131
		$builder = $this->builders[$this->getType()];
132
133
		if ( is_callable( $builder ) ) {
134
			return $builder( $this->getValue() );
135
		}
136
137
		try {
138
			return $builder::newFromArray( $this->getValue() );
139
		} catch ( InvalidArgumentException $ex ) {
140
			throw new DeserializationException( $ex->getMessage(), $ex );
141
		}
142
	}
143
144
	private function getValue() {
145
		return $this->serialization[self::VALUE_KEY];
146
	}
147
148
}
149