Completed
Push — master ( d28de4...06dd5f )
by Enrico
02:07
created

AbstractModel::constructOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 0
crap 2
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
	protected static $VOCABULARY  = array(
58
		'rdf'		=> 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
59
		'rdfs'		=> 'http://www.w3.org/2000/01/rdf-schema#',
60
		'owl'		=> 'http://www.w3.org/2002/07/owl#',
61
		'xsd' 		=> 'http://www.w3.org/2001/XMLSchema#',
62
		'dct' 		=> 'http://purl.org/dc/terms/',
63
		'void' 		=> 'http://rdfs.org/ns/void#',
64
		'prov' 		=> 'http://www.w3.org/ns/prov#',
65
		'schema'	=> 'http://schema.org/',
66
		'wgs' 		=> 'http://www.w3.org/2003/01/geo/wgs84_pos#',
67
		'foaf' 		=> 'http://xmlns.com/foaf/0.1/',
68
		'dq'		=> 'http://purl.org/linked-data/cube#',
69
		'daq'		=> 'http://purl.org/eis/vocab/daq#',
70
	);
71
	
72
73
	protected $options ;
74
	
75
	protected $data;
76
	protected $rdf =null; //lazy created
77
	protected $tripleCount=0; //lazy created
78
	protected $uniqueIdGenerator=null; // dependency injections
79
	protected $droppedFields = array();
80
	
81
	abstract public function asTurtle();
82
	
83
84 24
	protected static function mergeOptions( array $options1, array $options2 )
85
	{
86 24
    	foreach($options2 as $property=>$option){
87
			
88 24
			$options1[$property]=isset($options1[$property])
89 12
				?array_merge($options1[$property], $option)
90 24
				:$option;
91
    	}
92
		
93 24
		return $options1;
94
	}
95
96
97 24
	protected static function constructOptions()
98
	{
99
		//http://stackoverflow.com/questions/22377022/using-array-merge-to-initialize-static-class-variable-in-derived-class-based-on
100 24
		$thisClass = get_called_class();
101 24
		$parentClass = get_parent_class($thisClass);
102 24
		$exists = method_exists($parentClass, __FUNCTION__); 
103 24
		return $exists ? 
104 24
			self::mergeOptions($parentClass::constructOptions(), $thisClass::$DEFAULT_OPTIONS) : 
105 24
			$thisClass::$DEFAULT_OPTIONS;		
106
	}
107
108
109 24
    public function __construct(array $data = array(), array $customOptions = array()) 
110
    { 		
111 24
 		$options = self::mergeOptions(self::constructOptions(),$customOptions);
112
		
113
		// set default values
114 24
		foreach( $options as $property=>$option){	
115 24
			if(empty($data[$property]) && isset($option['default'])){
116 24
				$data[$property] = $option['default'];
117
			}
118
		}
119
120
		// ensure data are sanitized and validated
121 24
		$sanitizedData = array_filter( filter_var_array($data, $options));
122
		
123
		// find and register dropped fields
124 24
		foreach($data as $property=>$value){
125 24
			if($value && empty($sanitizedData[$property])){
126 24
				$this->droppedFields[]=$property;
127
			}
128
		}
129
130 24
		$this->options = $options;
131 24
		$this->data = $sanitizedData;
132
		$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...
133 24
    }
134
	
135
136
137 4
	public static function getVocabularies()
138
	{
139
		//http://stackoverflow.com/questions/22377022/using-array-merge-to-initialize-static-class-variable-in-derived-class-based-on
140 4
		$thisClass = get_called_class();
141 4
		$parentClass = get_parent_class($thisClass);
142 4
		$exists = method_exists($parentClass, __FUNCTION__); 
143 4
		return $exists ? 
144 4
			array_merge($parentClass::getVocabularies(), $thisClass::$VOCABULARY) : 
145 4
			$thisClass::$VOCABULARY;
146
	}
147
148
	
149 3
	public static function getTurtleHeader($base=null)
150
	{
151 3
		$vocabulariers = static::getVocabularies();
152 3
		$header = empty($base)?'': "@base <$base> .\n";
153 3
		foreach( $vocabulariers as $prefix=>$ns ){
154 3
			$header.="@prefix $prefix: <$ns> .\n";
155
		}
156
		
157 3
		return $header;
158
	}
159
160
	
161 1
	public function getDroppedFields()
162
	{
163 1
		return $this->droppedFields;
164
	}
165
166
	
167
	/**
168
	 * dependecy injection setter 
169
	 */
170 24
	public function setIdGenerator($generator)
171
	{
172 24
		assert( is_callable($generator));
173 24
		$this->uniqueIdGenerator = $generator;
174
		
175 24
		return $this;
176
	}
177
178
179
	/**
180
	 * a generic implementation that use uri, base and id property (all optionals)
181
	 */
182 8
	public function getUri()
183
	{
184 8
		if(!empty($this->data['uri'])){
185 2
			$uri =  $this->data['uri'];
186 6
		} elseif(!empty($this->data['base'])) {
187 6
			$idGenerator=$this->uniqueIdGenerator;
188 6
			$uri = $this->data['base'];
189 6
			$uri.=empty($this->data['id'])?$idGenerator($this->data):$this->data['id'];
190
		} else{
191
			$idGenerator=$this->uniqueIdGenerator;
192
			$uri = 'urn:local:botk:'.$idGenerator($this->data);
193
		}
194
		
195 8
		return $uri;
196
	}
197
		
198
199 10
	public function asArray()
200
	{
201 10
		return $this->data;
202
	}
203
204
	
205 2
	public function getOptions()
206
	{
207 2
		return $this->options;
208
	}
209
210
	
211 4
	public function getTripleCount()
212
	{
213
		// triple count is computed during rdf creation
214 4
		if (is_null($this->rdf)){
215 1
			$this->asTurtle();
216
		}
217
		
218 4
		return $this->tripleCount;
219
	}
220
	
221
		
222 1
	public function __toString() 
223
	{
224 1
		return $this->getTurtleHeader() ."\n". $this->asTurtle();
225
	}
226
}