Completed
Push — master ( 081071...48c049 )
by Enrico
01:58
created

AbstractModel   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 275
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 97.3%

Importance

Changes 0
Metric Value
wmc 34
lcom 1
cbo 0
dl 0
loc 275
ccs 72
cts 74
cp 0.973
rs 9.2
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A mergeOptions() 0 11 3
A constructOptions() 0 10 2
C __construct() 0 25 7
A fromArray() 0 4 1
A fromStdObject() 0 4 1
A getVocabularies() 0 10 2
A getTurtleHeader() 0 10 3
A getDroppedFields() 0 4 1
A setIdGenerator() 0 7 1
A getUri() 0 15 4
A getOptions() 0 4 1
A getTripleCount() 0 9 3
A asArray() 0 4 1
A asStdObject() 0 4 1
A asLinkedData() 0 4 1
A asString() 0 4 1
A __toString() 0 4 1
asTurtleFragment() 0 1 ?
1
<?php
2
namespace BOTK\Model;
3
4
abstract class AbstractModel 
5
{
6
	
7
	/**
8
	 * 
9
	 * MUST be redefined by concrete class with the model schema 
10
	 * Each array element is composed by a propery name and and property options.
11
	 * Property option is an array with following (optional) fields:
12
	 * 		'default' 	a value to be used for the propery
13
	 * 		'filter' 	a php filter 
14
	 * 		'options' 	php filter options
15
	 * 		'flags'		php filter flags
16
	 * 
17
	 * Example:array (
18
	 *	'legalName'			=> array(
19
	 *							'filter'    => FILTER_CALLBACK,	
20
	 *	                        'options' 	=> '\BOTK\Filters::FILTER_NORMALIZZE_ADDRESS',
21
	 *		                   ),
22
	 *	'alternateName'		=> array(		
23
                            	'flags'  	=> FILTER_FORCE_ARRAY,
24
	 * 						),
25
	 * 	'postalCode'		=> array(	// italian rules
26
	 *							'filter'    => FILTER_VALIDATE_REGEXP,	
27
	 *	                        'options' 	=> array('regexp'=>'/^[0-9]{5}$/'),
28
	 *                      	'flags'  	=> FILTER_REQUIRE_SCALAR,
29
	 *		                   ),
30
	 * )
31
	 */
32
	protected static $DEFAULT_OPTIONS  = array(
33
		'uri'				=> array(
34
								'filter'    => FILTER_SANITIZE_URL,
35
                            	'flags'  	=> FILTER_REQUIRE_SCALAR,
36
			                   ),
37
		'base'				=> array(
38
								'default'	=> 'http://linkeddata.center/botk/resource/',
39
								'filter'    => FILTER_SANITIZE_URL,
40
                            	'flags'  	=> FILTER_REQUIRE_SCALAR,
41
			                   ),
42
		'id'				=> array(		
43
								'filter'    => FILTER_CALLBACK,
44
		                        'options' 	=> '\BOTK\Filters::FILTER_SANITIZE_ID',
45
                            	'flags'  	=> FILTER_REQUIRE_SCALAR,
46
			                   ),
47
		'page'				=> array(	
48
								'filter'    => FILTER_SANITIZE_URL,
49
                            	'flags'  	=> FILTER_FORCE_ARRAY,
50
			                   ),
51
		'homepage'			=> array(	
52
								'filter'    => FILTER_SANITIZE_URL,
53
                            	'flags'  	=> FILTER_FORCE_ARRAY,
54
			                   ),
55
	);
56
	
57
	/**
58
	 * known vocabularies
59
	 */
60
	protected static $VOCABULARY  = array(
61
		'rdf'		=> 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
62
		'rdfs'		=> 'http://www.w3.org/2000/01/rdf-schema#',
63
		'owl'		=> 'http://www.w3.org/2002/07/owl#',
64
		'xsd' 		=> 'http://www.w3.org/2001/XMLSchema#',
65
		'dct' 		=> 'http://purl.org/dc/terms/',
66
		'void' 		=> 'http://rdfs.org/ns/void#',
67
		'prov' 		=> 'http://www.w3.org/ns/prov#',
68
		'sd'		=> 'http://www.w3.org/ns/sparql-service-description#',
69
		'schema'	=> 'http://schema.org/',
70
		'wgs' 		=> 'http://www.w3.org/2003/01/geo/wgs84_pos#',
71
		'foaf' 		=> 'http://xmlns.com/foaf/0.1/',
72
		'dq'		=> 'http://purl.org/linked-data/cube#',
73
		'daq'		=> 'http://purl.org/eis/vocab/daq#',
74
		'kees'		=> 'http://linkeddata.center/kees/v1#',
75
	);
76
	
77
78
	protected $options ;
79
	
80
	protected $data;
81
	protected $rdf =null; //lazy created
82
	protected $tripleCount=0; //lazy created
83
	protected $uniqueIdGenerator=null; // dependency injections
84
	protected $droppedFields = array();
85
	
86
87 27
	protected static function mergeOptions( array $options1, array $options2 )
88
	{
89 27
    	foreach($options2 as $property=>$option){
90
			
91 27
			$options1[$property]=isset($options1[$property])
92 14
				?array_merge($options1[$property], $option)
93 27
				:$option;
94
    	}
95
		
96 27
		return $options1;
97
	}
98
99
100 27
	protected static function constructOptions()
101
	{
102
		//http://stackoverflow.com/questions/22377022/using-array-merge-to-initialize-static-class-variable-in-derived-class-based-on
103 27
		$thisClass = get_called_class();
104 27
		$parentClass = get_parent_class($thisClass);
105 27
		$exists = method_exists($parentClass, __FUNCTION__); 
106 27
		return $exists ? 
107 27
			self::mergeOptions($parentClass::constructOptions(), $thisClass::$DEFAULT_OPTIONS) : 
108 27
			$thisClass::$DEFAULT_OPTIONS;		
109
	}
110
111
112
	/**
113
	 * Do not call directlty constructor, use fromArray or other factory methodsinstead
114
	 */
115 27
    protected function __construct(array $data = array(), array $customOptions = array()) 
116
    { 		
117 27
 		$options = self::mergeOptions(self::constructOptions(),$customOptions);
118
		
119
		// set default values
120 27
		foreach( $options as $property=>$option){	
121 27
			if(empty($data[$property]) && isset($option['default'])){
122 27
				$data[$property] = $option['default'];
123
			}
124
		}
125
126
		// ensure data are sanitized and validated
127 27
		$sanitizedData = array_filter( filter_var_array($data, $options));
128
		
129
		// find and register dropped fields
130 27
		foreach($data as $property=>$value){
131 27
			if($value && empty($sanitizedData[$property])){
132 27
				$this->droppedFields[]=$property;
133
			}
134
		}
135
136 27
		$this->options = $options;
137 27
		$this->data = $sanitizedData;
138
		$this->setIdGenerator(function($data){return uniqid();});
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
139 27
    }
140
	
141
	
142
	
143
	/**
144
	 * Create an instance from an associative array
145
	 */
146 27
	public static function fromArray(array $data, array $customOptions = array())
147
	{
148 27
		return new static($data,$customOptions);
149
	}
150
	
151
	
152
	/**
153
	 * Create an instance from an generic standard object
154
	 */
155 3
	public static function fromStdObject( \stdClass $obj, array $customOptions = array())
0 ignored issues
show
Unused Code introduced by
The parameter $customOptions is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
156
	{
157 3
		return static::fromArray((array)$obj);
158
	}
159
160
161 4
	public static function getVocabularies()
162
	{
163
		//http://stackoverflow.com/questions/22377022/using-array-merge-to-initialize-static-class-variable-in-derived-class-based-on
164 4
		$thisClass = get_called_class();
165 4
		$parentClass = get_parent_class($thisClass);
166 4
		$exists = method_exists($parentClass, __FUNCTION__); 
167 4
		return $exists ? 
168 4
			array_merge($parentClass::getVocabularies(), $thisClass::$VOCABULARY) : 
169 4
			$thisClass::$VOCABULARY;
170
	}
171
172
	
173 3
	public static function getTurtleHeader($base=null)
174
	{
175 3
		$vocabulariers = static::getVocabularies();
176 3
		$header = empty($base)?'': "@base <$base> .\n";
177 3
		foreach( $vocabulariers as $prefix=>$ns ){
178 3
			$header.="@prefix $prefix: <$ns> .\n";
179
		}
180
		
181 3
		return $header;
182
	}
183
184
	
185 1
	public function getDroppedFields()
186
	{
187 1
		return $this->droppedFields;
188
	}
189
190
	
191
	/**
192
	 * dependecy injection setter 
193
	 */
194 27
	public function setIdGenerator($generator)
195
	{
196 27
		assert( is_callable($generator));
197 27
		$this->uniqueIdGenerator = $generator;
198
		
199 27
		return $this;
200
	}
201
202
203
	/**
204
	 * a generic implementation that use uri, base and id property (all optionals)
205
	 */
206 8
	public function getUri()
207
	{
208 8
		if(!empty($this->data['uri'])){
209 2
			$uri =  $this->data['uri'];
210 6
		} elseif(!empty($this->data['base'])) {
211 6
			$idGenerator=$this->uniqueIdGenerator;
212 6
			$uri = $this->data['base'];
213 6
			$uri.=empty($this->data['id'])?$idGenerator($this->data):$this->data['id'];
214
		} else{
215
			$idGenerator=$this->uniqueIdGenerator;
216
			$uri = 'urn:local:botk:'.$idGenerator($this->data);
217
		}
218
		
219 8
		return $uri;
220
	}
221
222
	
223 2
	public function getOptions()
224
	{
225 2
		return $this->options;
226
	}
227
228
229 4
	public function getTripleCount()
230
	{
231
		// triple count is computed during rdf creation
232 4
		if (!empty($this->data) && is_null($this->rdf)){
233 1
			$this->asTurtleFragment();
234
		}
235
		
236 4
		return $this->tripleCount;
237
	}
238
		
239
240 13
	public function asArray()
241
	{
242 13
		return $this->data;
243
	}	
244
245
246
247 1
	public function asStdObject()
248
	{
249 1
		return (object) $this->asArray();
250
	}
251
	
252
	
253
	/**
254
	 * metadata not yet implemented
255
	 */		
256 1
	public function asLinkedData() 
257
	{
258 1
		return $this->getTurtleHeader() ."\n". $this->asTurtleFragment();
259
	}
260
	
261
	
262 1
	public function asString() 
263
	{
264 1
		return $this->asLinkedData();
265
	}
266
	
267
		
268 1
	public function __toString() 
269
	{
270 1
		return $this->asString();
271
	}
272
	
273
274
	/**
275
	 * this must be implemented
276
	 */
277
	abstract public function asTurtleFragment();
278
}