AbstractModel::getDroppedFields()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 1
cts 1
cp 1
crap 1
rs 10
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
	    'dct'       => 'http://purl.org/dc/terms/',
49
	    'void'      => 'http://rdfs.org/ns/void#',
50
	    'foaf'      => 'http://xmlns.com/foaf/0.1/'
51
	);
52
	
53
54
	protected $options ;
55
	
56
	protected $data;
57
	protected $rdf =null; //lazy created
58
	protected $tripleCount=0; //lazy created
59
	protected $uniqueIdGenerator=null; // dependency injections
60
	protected $droppedFields = array();
61
	protected $globalStorage = null;
62
	
63 12
64
	protected static function mergeOptions( array $options1, array $options2 )
65 12
	{
66
    	foreach($options2 as $property=>$option){
67 12
			
68 5
			$options1[$property]=isset($options1[$property])
69 8
				?array_merge($options1[$property], $option)
70
				:$option;
71
    	}
72 12
		
73
		return $options1;
74
	}
75
76 12
77
	protected static function constructOptions()
78
	{
79 12
		//http://stackoverflow.com/questions/22377022/using-array-merge-to-initialize-static-class-variable-in-derived-class-based-on
80 12
		$thisClass = get_called_class();
81 12
		$parentClass = get_parent_class($thisClass);
82 12
		$exists = $parentClass?method_exists($parentClass, __FUNCTION__):false; 
83 12
		return $exists ? 
84 12
			self::mergeOptions($parentClass::constructOptions(), $thisClass::$DEFAULT_OPTIONS) : 
0 ignored issues
show
Bug introduced by
The property DEFAULT_OPTIONS does not exist on string.
Loading history...
85
			$thisClass::$DEFAULT_OPTIONS;		
86
	}
87
88
89
	/**
90
	 * Do not call directlty constructor, use fromArray or other factory methodsinstead
91 12
	 */
92
	protected function __construct(array $data =  [], array $customOptions = [], object $globalStorage = null) 
93 12
    { 		
94
 		$options = self::mergeOptions(self::constructOptions(),$customOptions);
95
		
96 12
		// set default values
97 12
		foreach( $options as $property=>$option){	
98 10
			if(empty($data[$property]) && isset($option['default'])){
99
				$data[$property] = $option['default'];
100
			}
101
		}
102
103 12
		// ensure data are sanitized and validated
104 12
		$sanitizedData = array_filter( filter_var_array($data, $options), function ($var){
0 ignored issues
show
Bug introduced by
It seems like filter_var_array($data, $options) can also be of type null; however, parameter $array of array_filter() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
		$sanitizedData = array_filter( /** @scrutinizer ignore-type */ filter_var_array($data, $options), function ($var){
Loading history...
105 12
		    return !is_null($var);
106
		});
107
			
108 12
		// find and register dropped fields
109 12
		foreach($data as $property=>$value){
110
			if($value && empty($sanitizedData[$property])){
111
				$this->droppedFields[]=$property;
112
			}
113
		}
114
115 12
116 12
		$this->options = $options;
117 12
		$this->data = $sanitizedData;
118 12
		$this->setIdGenerator(function($data){return uniqid();});
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

118
		$this->setIdGenerator(function(/** @scrutinizer ignore-unused */ $data){return uniqid();});

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

Loading history...
119
		$this->globalStorage = $globalStorage;
120
    }
121
	
122
	
123
	
124
	/**
125 12
	 * Create an instance from an associative array
126
	 */
127 12
    public static function fromArray(array $data, array $customOptions = [] , object $globalStorage = null)
128
	{
129
	    return new static($data,$customOptions,$globalStorage);
130
	}
131
	
132
	
133
	/**
134 1
	 * Create an instance from an generic standard object
135
	 */
136 1
	public static function fromStdObject( \stdClass $obj, array $customOptions = array(), object $globalStorage = null)
137
	{
138
	    return static::fromArray((array)$obj,$customOptions,$globalStorage);
139
	}
140 4
141
	
142
	public function getStorageObject()
143 4
	{
144 4
	    return $this->globalStorage;
145 4
	}
146 4
	
147 4
	
148 4
	public static function getVocabularies()
149
	{
150
		//http://stackoverflow.com/questions/22377022/using-array-merge-to-initialize-static-class-variable-in-derived-class-based-on
151
		$thisClass = get_called_class();
152 3
		$parentClass = get_parent_class($thisClass);
153
		$exists = $parentClass?method_exists($parentClass, __FUNCTION__):false; 
154 3
		return $exists ? 
155 3
			array_merge($parentClass::getVocabularies(), $thisClass::$VOCABULARY) : 
0 ignored issues
show
Bug introduced by
The property VOCABULARY does not exist on string.
Loading history...
156 3
			$thisClass::$VOCABULARY;
157 3
	}
158
159
	
160 3
	public static function getTurtleHeader($base=null)
161
	{
162
		$vocabulariers = static::getVocabularies();
163
		$header = empty($base)?'': "@base <$base> .\n";
164
		foreach( $vocabulariers as $prefix=>$ns ){
165
	        $header.="@prefix $prefix: <$ns> .\n";
166
		}
167
		
168
		return $header;
169
	}
170
171
	
172
	public function getDroppedFields()
173 12
	{
174
		return $this->droppedFields;
175 12
	}
176 12
177
	
178 12
	/**
179
	 * dependecy injection setter 
180
	 */
181
	public function setIdGenerator($generator)
182
	{
183
		assert( is_callable($generator));
184
		$this->uniqueIdGenerator = $generator;
185 6
		
186
		return $this;
187 6
	}
188
189 6
190
	/**
191 6
	 * returns an uri
192 4
	 */
193 4
	public function getUri($id=null, $suffix='')
194
	{
195
	    assert(!empty($this->data['base'])) ;
196 6
	    
197
	    $base = (array)$this->data['base']; // base could be an array
198
	    
199
	    if (empty($id)) {
200 1
	        $idGenerator=$this->uniqueIdGenerator;
201
	        $id=$idGenerator($this->data);
202 1
	    }
203
204
	    return $base[0] . $id . $suffix;
205
	}
206 1
207
	
208
	public function getOptions()
209 1
	{
210 1
		return $this->options;
211
	}
212
213 1
214
	public function getTripleCount()
215
	{
216
		// triple count is computed during rdf creation
217 2
		if (!empty($this->data) && is_null($this->rdf)){
218
			$this->asTurtleFragment();
219 2
		}
220
		
221
		return $this->tripleCount;
222
	}
223
		
224 1
225
	public function asArray()
226 1
	{
227
		return $this->data;
228
	}	
229
230
231
232
	public function asStdObject()
233 1
	{
234
		return (object) $this->asArray();
235 1
	}
236 1
	
237
	
238
	/**
239
	 * metadata not yet implemented
240 1
	 */		
241
	public function asLinkedData() 
242 1
	{
243
	    $base = $this->data['base']?? null;
244
	    return $this->getTurtleHeader($base) ."\n". $this->asTurtleFragment();
245
	}
246 1
	
247
	
248 1
	public function asString() 
249
	{
250
		return $this->asLinkedData();
251
	}
252
	
253
		
254
	public function __toString() 
255 1
	{
256 1
		return $this->asString();
257 1
	}
258 1
259 1
260
	/**
261
	 * adds a turtle fragment managing cardinality > 1
262 1
	 */
263
	protected function addFragment($format, $var, $sanitize=true){
264
		foreach((array)$var as $v){
265
			if($var){
266
				$this->rdf .= sprintf($format, $sanitize?\BOTK\Filters::FILTER_SANITIZE_TURTLE_STRING($v):$v);
267
				$this->tripleCount++;
268
			}
269
		}
270
	}
271
272
	/**
273
	 * this must be implemented
274
	 */
275
	abstract public function asTurtleFragment();
276
}