Completed
Push — master ( a288d0...6e0e40 )
by Enrico
07:58 queued 12s
created

AbstractModel::getTripleCount()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

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