Passed
Push — master ( 38f174...a4048f )
by Enrico
04:21
created

AbstractModel::asTurtleFragment()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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