Completed
Push — master ( b4cb56...2f2064 )
by Enrico
01:36
created

AbstractModel   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 267
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 87.5%

Importance

Changes 0
Metric Value
wmc 38
lcom 1
cbo 1
dl 0
loc 267
ccs 70
cts 80
cp 0.875
rs 8.3999
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A mergeOptions() 0 11 3
A constructOptions() 0 10 2
C __construct() 0 26 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
A addFragment() 0 8 4
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
	
34
	/**
35
	 * known vocabularies
36
	 */
37
	protected static $VOCABULARY  = array(
38
		'rdf'		=> 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
39
		'rdfs'		=> 'http://www.w3.org/2000/01/rdf-schema#',
40
		'owl'		=> 'http://www.w3.org/2002/07/owl#',
41
		'xsd' 		=> 'http://www.w3.org/2001/XMLSchema#',
42
		'dct' 		=> 'http://purl.org/dc/terms/',
43
		'void' 		=> 'http://rdfs.org/ns/void#',
44
		'prov' 		=> 'http://www.w3.org/ns/prov#',
45
		'sd'		=> 'http://www.w3.org/ns/sparql-service-description#',
46
		'schema'	=> 'http://schema.org/',
47
		'wgs' 		=> 'http://www.w3.org/2003/01/geo/wgs84_pos#',
48
		'foaf' 		=> 'http://xmlns.com/foaf/0.1/',
49
		'qb'		=> 'http://purl.org/linked-data/cube#',
50
		'daq'		=> 'http://purl.org/eis/vocab/daq#',
51
		'skos'		=> 'http://www.w3.org/2004/02/skos/core#',
52
		'kees'		=> 'http://linkeddata.center/kees/v1#',
53
		'botk'		=> 'http://linkeddata.center/botk/v1#',
54
	);
55
	
56
57
	protected $options ;
58
	
59
	protected $data;
60
	protected $rdf =null; //lazy created
61
	protected $tripleCount=0; //lazy created
62
	protected $uniqueIdGenerator=null; // dependency injections
63
	protected $droppedFields = array();
64
	
65
66 43
	protected static function mergeOptions( array $options1, array $options2 )
67
	{
68 43
    	foreach($options2 as $property=>$option){
69
			
70 34
			$options1[$property]=isset($options1[$property])
71 9
				?array_merge($options1[$property], $option)
72 34
				:$option;
73
    	}
74
		
75 43
		return $options1;
76
	}
77
78
79 43
	protected static function constructOptions()
80
	{
81
		//http://stackoverflow.com/questions/22377022/using-array-merge-to-initialize-static-class-variable-in-derived-class-based-on
82 43
		$thisClass = get_called_class();
83 43
		$parentClass = get_parent_class($thisClass);
84 43
		$exists = method_exists($parentClass, __FUNCTION__); 
85 43
		return $exists ? 
86 43
			self::mergeOptions($parentClass::constructOptions(), $thisClass::$DEFAULT_OPTIONS) : 
87 43
			$thisClass::$DEFAULT_OPTIONS;		
88
	}
89
90
91
	/**
92
	 * Do not call directlty constructor, use fromArray or other factory methodsinstead
93
	 */
94 43
    protected function __construct(array $data = array(), array $customOptions = array()) 
95
    { 		
96 43
 		$options = self::mergeOptions(self::constructOptions(),$customOptions);
97
		
98
		// set default values
99 43
		foreach( $options as $property=>$option){	
100 34
			if(empty($data[$property]) && isset($option['default'])){
101 34
				$data[$property] = $option['default'];
102
			}
103
		}
104
105
		// ensure data are sanitized and validated
106 43
		$sanitizedData = array_filter( filter_var_array($data, $options));
107
		
108
		// find and register dropped fields
109 43
		foreach($data as $property=>$value){
110 36
			if($value && empty($sanitizedData[$property])){
111 36
				$this->droppedFields[]=$property;
112
			}
113
		}
114
115
116 43
		$this->options = $options;
117 43
		$this->data = $sanitizedData;
118
		$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...
119 43
    }
120
	
121
	
122
	
123
	/**
124
	 * Create an instance from an associative array
125
	 */
126 43
	public static function fromArray(array $data, array $customOptions = array())
127
	{
128 43
		return new static($data,$customOptions);
129
	}
130
	
131
	
132
	/**
133
	 * Create an instance from an generic standard object
134
	 */
135 4
	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...
136
	{
137 4
		return static::fromArray((array)$obj);
138
	}
139
140
141 4
	public static function getVocabularies()
142
	{
143
		//http://stackoverflow.com/questions/22377022/using-array-merge-to-initialize-static-class-variable-in-derived-class-based-on
144 4
		$thisClass = get_called_class();
145 4
		$parentClass = get_parent_class($thisClass);
146 4
		$exists = method_exists($parentClass, __FUNCTION__); 
147 4
		return $exists ? 
148 4
			array_merge($parentClass::getVocabularies(), $thisClass::$VOCABULARY) : 
149 4
			$thisClass::$VOCABULARY;
150
	}
151
152
	
153 3
	public static function getTurtleHeader($base=null)
154
	{
155 3
		$vocabulariers = static::getVocabularies();
156 3
		$header = empty($base)?'': "@base <$base> .\n";
157 3
		foreach( $vocabulariers as $prefix=>$ns ){
158 3
			$header.="@prefix $prefix: <$ns> .\n";
159
		}
160
		
161 3
		return $header;
162
	}
163
164
	
165 3
	public function getDroppedFields()
166
	{
167 3
		return $this->droppedFields;
168
	}
169
170
	
171
	/**
172
	 * dependecy injection setter 
173
	 */
174 43
	public function setIdGenerator($generator)
175
	{
176 43
		assert( is_callable($generator));
177 43
		$this->uniqueIdGenerator = $generator;
178
		
179 43
		return $this;
180
	}
181
182
183
	/**
184
	 * a generic implementation that use uri, base and id property (all optionals)
185
	 */
186
	public function getUri()
187
	{
188
		if(!empty($this->data['uri'])){
189
			$uri =  $this->data['uri'];
190
		} elseif(!empty($this->data['base'])) {
191
			$idGenerator=$this->uniqueIdGenerator;
192
			$uri = $this->data['base'];
193
			$uri.=empty($this->data['id'])?$idGenerator($this->data):$this->data['id'];
194
		} else{
195
			$idGenerator=$this->uniqueIdGenerator;
196
			$uri = 'urn:local:botk:'.$idGenerator($this->data);
197
		}
198
		
199
		return $uri;
200
	}
201
202
	
203 5
	public function getOptions()
204
	{
205 5
		return $this->options;
206
	}
207
208
209 10
	public function getTripleCount()
210
	{
211
		// triple count is computed during rdf creation
212 10
		if (!empty($this->data) && is_null($this->rdf)){
213 1
			$this->asTurtleFragment();
214
		}
215
		
216 10
		return $this->tripleCount;
217
	}
218
		
219
220 18
	public function asArray()
221
	{
222 18
		return $this->data;
223
	}	
224
225
226
227 2
	public function asStdObject()
228
	{
229 2
		return (object) $this->asArray();
230
	}
231
	
232
	
233
	/**
234
	 * metadata not yet implemented
235
	 */		
236 1
	public function asLinkedData() 
237
	{
238 1
		return $this->getTurtleHeader() ."\n". $this->asTurtleFragment();
239
	}
240
	
241
	
242 1
	public function asString() 
243
	{
244 1
		return $this->asLinkedData();
245
	}
246
	
247
		
248 1
	public function __toString() 
249
	{
250 1
		return $this->asString();
251
	}
252
253
254
	/**
255
	 * adds a turtle fragment managing cardinality > 1
256
	 */
257 10
	protected function addFragment($format, $var, $sanitize=true){
258 10
		foreach((array)$var as $v){
259 10
			if($var){
260 10
				$this->rdf .= sprintf($format, $sanitize?\BOTK\Filters::FILTER_SANITIZE_TURTLE_STRING($v):$v);
261 10
				$this->tripleCount++;
262
			}
263
		}
264 10
	}
265
266
	/**
267
	 * this must be implemented
268
	 */
269
	abstract public function asTurtleFragment();
270
}