Andrew's Web Libraries (AWL)
vComponent.php
1 <?php
17  include_once('vObject.php');
18  //include_once('HeapLines.php');
19  include_once('vProperty.php');
20 
21  class vComponent extends vObject{
22 
23  private $components;
24  private $properties;
25  private $type;
26  private $iterator;
27  private $seekBegin;
28  private $seekEnd;
29  private $propertyLocation;
30 
31  const KEYBEGIN = 'BEGIN:';
32  const KEYBEGINLENGTH = 6;
33  const KEYEND = "END:";
34  const KEYENDLENGTH = 4;
35  const VEOL = "\r\n";
36 
37  public static $PREPARSED = false;
38 
39  function __construct($propstring=null, &$refData=null){
40  parent::__construct($master);
41 
42  unset($this->type);
43 
44  if(isset($propstring) && gettype($propstring) == 'string'){
45  $this->initFromText($propstring);
46  } else if(isset($refData)){
47  if(gettype($refData) == 'string'){
48  $this->initFromText($refData);
49  } else if(gettype($refData) == 'object') {
50  $this->initFromIterator($refData);
51  }
52  } else {
53  //$text = '';
54  //$this->initFromText($text);
55  }
56 
57 
58 // if(isset($this->iterator)){
59 // $this->parseFrom($this->iterator);
60 // }
61 
62 
63  }
64 
65  function initFromIterator(&$iterator, $begin = -1){
66  $this->iterator = &$iterator;
67 
68  //$this->seekBegin = $this->iterator->key();
69 
70 
71 
72  $iterator = $this->iterator;
73  do {
74  $line = $iterator->current();
75  $seek = $iterator->key();
76 
77  $posStart = strpos(strtoupper($line), vComponent::KEYBEGIN);
78  if($posStart !== false && $posStart == 0){
79  if(!isset($this->type)){
80  $this->seekBegin = $seek;
81 
82  $this->type = strtoupper(substr($line, vComponent::KEYBEGINLENGTH));
83  }
84  } else {
85 
86  $posEnd = strpos(strtoupper($line), vComponent::KEYEND);
87  if($posEnd !== false && $posEnd == 0){
88  $thisEnd = strtoupper(substr($line, vComponent::KEYENDLENGTH));
89  if($thisEnd == $this->type){
90  $this->seekEnd = $seek;
91  //$iterator->next();
92  $len = strlen($this->type);
93  $last = $this->type[$len-1];
94  if($last == "\r"){
95  $this->type = strtoupper(substr($this->type, 0, $len-1));
96  }
97  break;
98  }
99 
100  } else {
101  //$this->properties[] = new vProperty(null, $iterator, $seek);
102  }
103  }
104 
105 
106 
107 
108  $iterator->next();
109  } while($iterator->valid());
110  //$this->parseFrom($iterator);
111 
112  }
113 
114  public function getIterator(){
115  return $this->iterator;
116  }
117 
118  function initFromText(&$plainText){
119  $plain2 = $this->UnwrapComponent($plainText);
120 
121  //$file = fopen('data.out.tmp', 'w');
122  //$plain3 = preg_replace('{\r?\n}', '\r\n', $plain2 );
123  //fwrite($file, $plain2);
124  //fclose($file);
125  //$lines = &explode(PHP_EOL, $plain2);
126 // $arrayData = new ArrayObject($lines);
127 // $this->iterator = &$arrayData->getIterator();
128 // $this->initFromIterator($this->iterator, 0);
129 // unset($plain);
130 // unset($iterator);
131 // unset($arrayData);
132 // unset($lines);
133 
134  // Note that we can't use PHP_EOL here, since the line splitting should handle *either* of CR, CRLF or LF line endings.
135  $arrayOfLines = new ArrayObject(preg_split('{\r?\n}', $plain2));
136  $this->iterator = $arrayOfLines->getIterator();
137  unset($plain2);
138  //$this->initFromIterator($this->iterator);
139  //$this->iterator = new HeapLines($plain);
140 
141  //$this->initFromIterator(new HeapLines($plain), 0);
142  $this->parseFrom($this->iterator);
143 
144  }
145 
146  function rewind(){
147  if(isset($this->iterator) && isset($this->seekBegin)){
148  $this->iterator->seek($this->seekBegin);
149  }
150  }
151 
152 
163  function explode(){
164  if(!isset($this->properties) && !isset($this->components) && $this->isValid()){
165  unset($this->properties);
166  unset($this->components);
167  unset($this->type);
168  $this->rewind();
169  $this->parseFrom($this->iterator);
170  }
171  }
172 
173  function close(){
174 
175  if(isset($this->components)){
176  foreach($this->components as $comp){
177  $comp->close();
178  }
179  }
180 
181  if($this->isValid()){
182  unset($this->properties);
183  unset($this->components);
184  }
185 
186 
187 
188  }
189 
190  function parseFrom(&$iterator){
191 
192 
193  $begin = $iterator->key();
194  $typelen = 0;
195  //$count = $lines->count();
196 
197  do{
198  $line = $iterator->current();
199  //$line = substr($current, 0, strlen($current) -1);
200  $end = $iterator->key();
201 
202  $pos = strpos(strtoupper($line), vComponent::KEYBEGIN);
203  $callnext = true;
204  if($pos !== false && $pos == 0) {
205  $type = strtoupper(substr($line, vComponent::KEYBEGINLENGTH));
206 
207  if($typelen !== 0 && strncmp($this->type, $type, $typelen) !== 0){
208  $this->components[] = new vComponent(null, $iterator);
209  $callnext = false;
210  } else {
211  // in special cases when is "\r" on end remove it
212  // We should probably throw an error if we get here, because the
213  // thing that splits stuff should not be giving us this.
214  $typelen = strlen($type);
215  if($type[$typelen-1] == "\r"){
216  $typelen--;
217  $this->type = substr($type, 0, $typelen);
218  } else {
219  $this->type = $type;
220  }
221 
222 
223  //$iterator->offsetUnset($end);
224  //$iterator->seek($begin);
225  //$callnext = false;
226  }
227 
228  } else {
229  $pos = strpos(strtoupper($line), vComponent::KEYEND);
230 
231  if($pos !== false && $pos == 0) {
232  $this->seekBegin = $begin;
233  $this->seekEnd = $end;
234  //$iterator->offsetUnset($end);
235  //$iterator->seek($end-2);
236  //$line2 = $iterator->current();
237  //$this->seekEnd = $iterator->key();
238 
239  //$callnext = false;
240  //$newheap = $lines->createLineHeapFrom($start, $end);
241  //$testfistline = $newheap->substr(0);
242  //echo "end:" . $this->key . "[$start, $end]<br>";
243  //$lines->nextLine();
244  //$iterator->offsetUnset($end);
245  return;
246  } else {
247 // $prstart = $lines->getSwheretartLineOnHeap();
248 // $prend =
249 //$this->properties[] = new vProperty("AHOJ");
250  $parameters = preg_split( '(:|;)', $line);
251  $possiblename = strtoupper(array_shift( $parameters ));
252  $this->properties[] = new vProperty($possiblename, $this->master, $iterator, $end);
253  //echo $this->key . ' property line' . "[$prstart,$prend]<br>";
254 
255  }
256  }
257 
258 // if($callnext){
259 // $iterator->next();
260 // }
261  //if($callnext)
262  // $iterator->offsetUnset($end);
263  if($iterator->valid())
264  $iterator->next();
265 
266  } while($iterator->valid() && ( !isset($this->seekEnd) || $this->seekEnd > $end ) );
267  //$lines->getEndLineOnHeap();
268 
269 
270  }
271 
272 
273 
278  public function ComponentCount(){
279  $this->explode();
280  return isset($this->components) ? count($this->components) : 0;
281  }
282 
287  public function propertiesCount(){
288  $this->explode();
289  return isset($this->properties) ? count($this->properties) : 0;
290  }
291 
296  public function getComponentAt($position){
297  $this->explode();
298  if($this->ComponentCount() > $position){
299  return $this->components[$position];
300  } else {
301  return null;
302  }
303  }
304 
305  function getPropertyAt($position){
306  $this->explode();
307  if($this->propertiesCount() > $position){
308  return $this->properties[$position];
309  } else {
310  return null;
311  }
312 
313  }
314 
315  function clearPropertyAt($position) {
316  $this->explode();
317  if($this->isValid()){
318  $this->invalidate();
319  }
320 
321  $i=0; // property index/position is relative to current vComponent
322  foreach( $this->properties AS $k => $v ) {
323  if ( $i == $position ) {
324  unset($this->properties[$k]);
325  }
326  $i++;
327  }
328  $this->properties = array_values($this->properties);
329  }
330 
331 
335  function GetType() {
336  return $this->type;
337  }
338 
339 
343  function SetType( $type ) {
344  if ( $this->isValid() ) {
345  $this->invalidate();
346  };
347  $this->type = strtoupper($type);
348  return $this->type;
349  }
350 
351 
356  function CollectParameterValues( $parameter_name ) {
357  $this->explode();
358  $values = array();
359  if(isset($this->components)){
360  foreach( $this->components AS $k => $v ) {
361  $also = $v->CollectParameterValues($parameter_name);
362  $values = array_merge( $values, $also );
363  }
364  }
365  if(isset($this->properties)){
366  foreach( $this->properties AS $k => $v ) {
367  $also = $v->GetParameterValue($parameter_name);
368  if ( isset($also) && $also != "" ) {
369 // dbg_error_log( 'vComponent', "::CollectParameterValues(%s) : Found '%s'", $parameter_name, $also);
370  $values[$also] = 1;
371  }
372  }
373  }
374 
375  return $values;
376  }
377 
378 
382  function GetProperty( $type ) {
383  $this->explode();
384  foreach( $this->properties AS $k => $v ) {
385  if ( is_object($v) && $v->Name() == $type ) {
386  return $v;
387  }
388  else if ( !is_object($v) ) {
389  dbg_error_log("ERROR", 'vComponent::GetProperty(): Trying to get %s on %s which is not an object!', $type, $v );
390  }
391  }
393  return null;
394  }
395 
399  function GetPValue( $type ) {
400  $this->explode();
401  $p = $this->GetProperty($type);
402  if ( isset($p) ) return $p->Value();
403  return null;
404  }
405 
406 
411  function GetProperties( $type = null ) {
412  // the properties in base are with name
413  // it was setted in parseFrom(&interator)
414  if(!isset($this->properties)){
415  $this->explode();
416  }
417  $properties = array();
418 
419  if (isset($type)) {
420  if (gettype($type) == 'string') {
421  $testtypes = array( strtoupper($type) => true );
422  } else {
423  $testtypes = array();
424  foreach ($type as $propname => $val) {
425  $testtypes[strtoupper($propname)] = $val;
426  }
427  }
428  }
429 
430  foreach( $this->properties AS $k => $v ) {
431  $fullname = $v->Name(); //get Property name (string); will be uppercase
432  $propname = preg_replace( '/^.*[.]/', '', $fullname ); //for grouped properties we remove prefix itemX.
433 
434  // if asked for a groupless property (e.g. EMAIL), return all properties of that type including those
435  // with group prefix (-> $propname matches)
436  // if asked for a property with group prefix (e.g. item1.EMAIL), return only properties with that group
437  // (-> $fullname matches)
438  if ( $type == null
439  || (isset($testtypes[$propname]) && $testtypes[$propname])
440  || (isset($testtypes[$fullname]) && $testtypes[$fullname])
441  ) {
442  $properties[] = $v;
443  }
444  }
445  return $properties;
446  }
447 
457  function GetPropertiesByPath( $path ) {
458  $properties = array();
459  dbg_error_log( 'vComponent', "GetPropertiesByPath: Querying within '%s' for path '%s'", $this->type, $path );
460  if ( !preg_match( '#(/?)(!?)([^/]+)(/?.*)$#', $path, $matches ) ) return $properties;
461 
462  $anchored = ($matches[1] == '/');
463  $inverted = ($matches[2] == '!');
464  $ourtest = $matches[3];
465  $therest = $matches[4];
466  dbg_error_log( 'vComponent', "GetPropertiesByPath: Matches: %s -- %s -- %s -- %s\n", $matches[1], $matches[2], $matches[3], $matches[4] );
467  if ( $ourtest == '*' || (($ourtest == $this->type) !== $inverted) && $therest != '' ) {
468  if ( preg_match( '#^/(!?)([^/]+)$#', $therest, $matches ) ) {
469  $normmatch = ($matches[1] =='');
470  $proptest = $matches[2];
471 
472  $thisproperties = $this->GetProperties();
473  if(isset($thisproperties) && count($thisproperties) > 0){
474  foreach( $thisproperties AS $k => $v ) {
475  if ( $proptest == '*' || (($v->Name() == $proptest) === $normmatch ) ) {
476  $properties[] = $v;
477  }
478  }
479  }
480 
481  }
482  else {
486  foreach( $this->GetComponents() AS $k => $v ) {
487  $properties = array_merge( $properties, $v->GetPropertiesByPath($therest) );
488  }
489  }
490  }
491 
492  if ( ! $anchored ) {
496  foreach( $this->GetComponents() AS $k => $v ) {
497  $properties = array_merge( $properties, $v->GetPropertiesByPath($path) );
498  }
499  }
500  dbg_error_log('vComponent', "GetPropertiesByPath: Found %d within '%s' for path '%s'\n", count($properties), $this->type, $path );
501  return $properties;
502  }
503 
509  function ClearProperties( $type = null ) {
510  $this->explode();
511  if($this->isValid()){
512  $this->invalidate();
513  }
514 
515  if ( $type != null ) {
516  $testtypes = (gettype($type) == 'string' ? array( $type => true ) : $type );
517  // First remove all the existing ones of that type
518  foreach( $this->properties AS $k => $v ) {
519  if ( isset($testtypes[$v->Name()]) && $testtypes[$v->Name()] ) {
520  unset($this->properties[$k]);
521 
522  }
523  }
524  $this->properties = array_values($this->properties);
525  }
526  else {
527 
528  $this->properties = array();
529  }
530  }
531 
535  function SetProperties( $new_properties, $type = null ) {
536  $this->explode();
537  $this->ClearProperties($type);
538  foreach( $new_properties AS $k => $v ) {
539  $this->properties[] = $v;
540  }
541  }
542 
550  function AddProperty( $new_property, $value = null, $parameters = null ) {
551  $this->explode();
552  if ( isset($value) && gettype($new_property) == 'string' ) {
553  $new_prop = new vProperty('', $this->master);
554  $new_prop->Name($new_property);
555  $new_prop->Value($value);
556  if ( $parameters != null ) {
557  $new_prop->Parameters($parameters);
558  }
559 // dbg_error_log('vComponent'," Adding new property '%s'", $new_prop->Render() );
560  $this->properties[] = $new_prop;
561  }
562  else if ( $new_property instanceof vProperty ) {
563  $this->properties[] = $new_property;
564  $new_property->setMaster($this->master);
565  }
566 
567  if($this->isValid()){
568  $this->invalidate();
569  }
570  }
571 
581  function GetComponents( $type = null, $normal_match = true ) {
582  $this->explode();
583  $components = isset($this->components) ? $this->components : array();
584 
585  if ( $type != null ) {
586  //$components = $this->components;
587  $testtypes = (gettype($type) == 'string' ? array( $type => true ) : $type );
588  foreach( $components AS $k => $v ) {
589 // printf( "Type: %s, %s, %s\n", $v->GetType(),
590 // ($normal_match && isset($testtypes[$v->GetType()]) && $testtypes[$v->GetType()] ? 'true':'false'),
591 // ( !$normal_match && (!isset($testtypes[$v->GetType()]) || !$testtypes[$v->GetType()]) ? 'true':'false')
592 // );
593  if ( !($normal_match && isset($testtypes[$v->GetType()]) && $testtypes[$v->GetType()] )
594  && !( !$normal_match && (!isset($testtypes[$v->GetType()]) || !$testtypes[$v->GetType()])) ) {
595  unset($components[$k]);
596  }
597  }
598  $components = array_values($components);
599  }
600 // print_r($components);
601  return $components;
602  }
603 
604 
609  function ClearComponents( $type = null ) {
610  if($this->isValid()){
611  $this->explode();
612  }
613 
614 
615  if ( $type != null && !empty($this->components)) {
616  $testtypes = (gettype($type) == 'string' ? array( $type => true ) : $type );
617  // First remove all the existing ones of that type
618  foreach( $this->components AS $k => $v ) {
619  $this->components[$k]->ClearComponents($testtypes);
620  if ( isset($testtypes[$v->GetType()]) && $testtypes[$v->GetType()] ) {
621  unset($this->components[$k]);
622  if ( $this->isValid()) {
623  $this->invalidate();
624  }
625  }
626 
627  }
628  }
629  else {
630  $this->components = array();
631  if ( $this->isValid()) {
632  $this->invalidate();
633  }
634  }
635 
636  return $this->isValid();
637  }
638 
645  function SetComponents( $new_component, $type = null ) {
646  $this->explode();
647  if ( $this->isValid()) {
648  $this->invalidate();
649  }
650  if ( empty($type) ) {
651  $this->components = $new_component;
652  return;
653  }
654 
655  $this->ClearComponents($type);
656  foreach( $new_component AS $k => $v ) {
657  $this->components[] = $v;
658  }
659  }
660 
666  public function AddComponent( $new_component ) {
667  $this->explode();
668  if ( is_array($new_component) && count($new_component) == 0 ) return;
669 
670  if ( $this->isValid()) {
671  $this->invalidate();
672  }
673 
674  try {
675  if ( is_array($new_component) ) {
676  foreach( $new_component AS $k => $v ) {
677  $this->components[] = $v;
678  if ( !method_exists($v,'setMaster') ) fatal('Component to be added must be a vComponent');
679  $v->setMaster($this->master);
680  }
681  }
682  else {
683  if ( !method_exists($new_component,'setMaster') ) fatal('Component to be added must be a vComponent');
684  $new_component->setMaster($this->master);
685  $this->components[] = $new_component;
686  }
687  }
688  catch( Exception $e ) {
689  fatal();
690  }
691  }
692 
693 
699  function MaskComponents( $keep, $recursive = true ) {
700  $this->explode();
701  if(!isset($this->components)){
702  return ;
703  }
704 
705  foreach( $this->components AS $k => $v ) {
706  if ( !isset($keep[$v->GetType()]) ) {
707  unset($this->components[$k]);
708  if ( $this->isValid()) {
709  $this->invalidate();
710  }
711  }
712  else if ( $recursive ) {
713  $v->MaskComponents($keep);
714  }
715  }
716  }
717 
723  function MaskProperties( $keep, $component_list=null ) {
724  $this->explode();
725  if ( !isset($component_list) || isset($component_list[$this->type]) ) {
726  foreach( $this->properties AS $k => $v ) {
727  if ( !isset($keep[$v->Name()]) || !$keep[$v->Name()] ) {
728  unset($this->properties[$k]);
729  if ( $this->isValid()) {
730  $this->invalidate();
731  }
732  }
733  }
734  }
735  if(isset($this->components)){
736  foreach( $this->components AS $k => $v ) {
737  $v->MaskProperties($keep, $component_list);
738  }
739  }
740 
741  }
742 
751  function WrapComponent( $content ) {
752  $strs = preg_split( "/\r?\n/", $content );
753  $wrapped = "";
754  foreach ($strs as $str) {
755 // print "Before: >>$str<<, len(".strlen($str).")\n";
756  $wrapped_bit = (strlen($str) < 76 ? $str : preg_replace( '/(.{72})/u', '$1'."\r\n ", $str )) .self::VEOL;
757 // print "After: >>$wrapped_bit<<\n";
758  $wrapped .= $wrapped_bit;
759  }
760  return $wrapped;
761  }
762 
768  function UnwrapComponent( &$content ) {
769  return preg_replace('/\r?\n[ \t]/', '', $content );
770  }
771 
772 
779  protected function RenderWithoutWrap($restricted_properties = null, $force_rendering = false){
780  $unrolledComponents = isset($this->components);
781  $rendered = vComponent::KEYBEGIN . $this->type . self::VEOL;
782 
783 
784  if($this->isValid()){
785  $rendered .= $this->RenderWithoutWrapFromIterator($unrolledComponents);
786  } else {
787  $rendered .= $this->RenderWithoutWrapFromObjects();
788  }
789 
790  if($unrolledComponents){
791  //$count = 0;
792  foreach($this->components as $component){
793  //$component->explode();
794  //$count++;
795  $component_render = $component->RenderWithoutWrap( null, $force_rendering );
796  if(strlen($component_render) > 0){
797  $rendered .= $component_render . self::VEOL;
798  }
799 
800  //$component->close();
801 
802  }
803  }
804 
805  return $rendered . vComponent::KEYEND . $this->type;
806  }
807 
812  protected function RenderWithoutWrapFromObjects(){
813  $rendered = '';
814  if(isset($this->properties)){
815  foreach( $this->properties AS $k => $v ) {
816  if ( method_exists($v, 'Render') ) {
817  $forebug = $v->Render() . self::VEOL;
818  $rendered .= $forebug;
819  }
820  }
821  }
822 
823  return $rendered;
824  }
825 
831  protected function RenderWithoutWrapFromIterator($unrolledComponents){
832  $this->rewind();
833  $rendered = '';
834  $lentype = 0;
835 
836  if(isset($this->type)){
837  $lentype = strlen($this->type);
838  }
839 
840  $iterator = $this->iterator;
841  $inInnerObject = 0;
842  do {
843  $line = $iterator->current() . self::VEOL;
844  $seek = $iterator->key();
845 
846  $posStart = strpos($line, vComponent::KEYBEGIN);
847  if($posStart !== false && $posStart == 0){
848  $type = substr($line, vComponent::KEYBEGINLENGTH);
849  if(!isset($this->type)){
850  //$this->seekBegin = $seek;
851  $this->type = $type;
852  $lentype = strlen($this->type);
853  } else if(strncmp($type, $this->type, $lentype) != 0){
854  // dont render line which is owned
855  // by inner commponent -> inner component *BEGIN*
856  if($unrolledComponents){
857  $inInnerObject++;
858  } else {
859  $rendered .= $line ;
860  }
861  }
862  } else {
863 
864  $posEnd = strpos($line, vComponent::KEYEND);
865  if($posEnd !== false && $posEnd == 0){
866  $thisEnd = substr($line, vComponent::KEYENDLENGTH);
867  if(strncmp($thisEnd, $this->type, $lentype) == 0){
868  // Current object end
869  $this->seekEnd = $seek;
870  //$iterator->next();
871  break;
872  }else if($unrolledComponents){
873  // dont render line which is owned
874  // by inner commponent -> inner component *END*
875  $inInnerObject--;
876  } else {
877  $rendered .= $line;
878  }
879 
880  } else if($inInnerObject === 0 || !$unrolledComponents){
881  $rendered .= $line;
882  }
883  }
884  $iterator->next();
885  } while($iterator->valid() && ( !isset($this->seekEnd) || $this->seekEnd > $seek));
886 
887 
888  return $rendered;
889 
890  }
891 
892 
899  function Render($restricted_properties = null, $force_rendering = false){
900  return $this->WrapComponent($this->RenderWithoutWrap($restricted_properties, $force_rendering));
901  //return $this->InternalRender($restricted_properties, $force_rendering);
902  }
903 
904  function isValid(){
905  if($this->valid){
906  if(isset($this->components)){
907  foreach($this->components as $comp){
908  if(!$comp->isValid()){
909  return false;
910  }
911  }
912  }
913 
914  return true;
915  }
916  return false;
917  }
918 
928  function TestFilter( $filters ) {
929  foreach( $filters AS $k => $v ) {
930  $tag = $v->GetNSTag();
931 // dbg_error_log( 'vCalendar', ":TestFilter: '%s' ", $tag );
932  switch( $tag ) {
933  case 'urn:ietf:params:xml:ns:caldav:is-defined':
934  case 'urn:ietf:params:xml:ns:carddav:is-defined':
935  if ( count($this->properties) == 0 && count($this->components) == 0 ) return false;
936  break;
937 
938  case 'urn:ietf:params:xml:ns:caldav:is-not-defined':
939  case 'urn:ietf:params:xml:ns:carddav:is-not-defined':
940  if ( count($this->properties) > 0 || count($this->components) > 0 ) return false;
941  break;
942 
943  case 'urn:ietf:params:xml:ns:caldav:comp-filter':
944  case 'urn:ietf:params:xml:ns:carddav:comp-filter':
945  $subcomponents = $this->GetComponents($v->GetAttribute('name'));
946  $subfilter = $v->GetContent();
947 // dbg_error_log( 'vCalendar', ":TestFilter: Found '%d' (of %d) subs of type '%s'",
948 // count($subcomponents), count($this->components), $v->GetAttribute('name') );
949  $subtag = $subfilter[0]->GetNSTag();
950  if ( $subtag == 'urn:ietf:params:xml:ns:caldav:is-not-defined'
951  || $subtag == 'urn:ietf:params:xml:ns:carddav:is-not-defined' ) {
952  if ( count($properties) > 0 ) {
953 // dbg_error_log( 'vComponent', ":TestFilter: Wanted none => false" );
954  return false;
955  }
956  }
957  else if ( count($subcomponents) == 0 ) {
958  if ( $subtag == 'urn:ietf:params:xml:ns:caldav:is-defined'
959  || $subtag == 'urn:ietf:params:xml:ns:carddav:is-defined' ) {
960 // dbg_error_log( 'vComponent', ":TestFilter: Wanted some => false" );
961  return false;
962  }
963  else {
964 // dbg_error_log( 'vCalendar', ":TestFilter: Wanted something from missing sub-components => false" );
965  $negate = $subfilter[0]->GetAttribute("negate-condition");
966  if ( empty($negate) || strtolower($negate) != 'yes' ) return false;
967  }
968  }
969  else {
970  foreach( $subcomponents AS $kk => $subcomponent ) {
971  if ( ! $subcomponent->TestFilter($subfilter) ) return false;
972  }
973  }
974  break;
975 
976  case 'urn:ietf:params:xml:ns:carddav:prop-filter':
977  case 'urn:ietf:params:xml:ns:caldav:prop-filter':
978  $subfilter = $v->GetContent();
979  $properties = $this->GetProperties($v->GetAttribute("name"));
980  dbg_error_log( 'vCalendar', ":TestFilter: Found '%d' props of type '%s'", count($properties), $v->GetAttribute('name') );
981  if ( empty($subfilter) ) {
982  // empty means: test if a property of the type specified by the "name" attribute exists (rfc6352, 10.5.1)
983  $subtag = str_replace('prop-filter', 'is-defined', $tag);
984  } else {
985  $subtag = $subfilter[0]->GetNSTag();
986  }
987  if ( $subtag == 'urn:ietf:params:xml:ns:caldav:is-not-defined'
988  || $subtag == 'urn:ietf:params:xml:ns:carddav:is-not-defined' ) {
989  if ( count($properties) > 0 ) {
990 // dbg_error_log( 'vCalendar', ":TestFilter: Wanted none => false" );
991  return false;
992  }
993  }
994  else if ( count($properties) == 0 ) {
995  if ( $subtag == 'urn:ietf:params:xml:ns:caldav:is-defined'
996  || $subtag == 'urn:ietf:params:xml:ns:carddav:is-defined' ) {
997 // dbg_error_log( 'vCalendar', ":TestFilter: Wanted some => false" );
998  return false;
999  }
1000  else {
1001 // dbg_error_log( 'vCalendar', ":TestFilter: Wanted '%s' from missing sub-properties => false", $subtag );
1002  return false;
1003  }
1004  }
1005  else {
1006  // if we have multiple subfilters: do we need all to match or is a single match sufficient?
1007  $matchAll = $v->GetAttribute("test");
1008  if (isset($matchAll) && $matchAll == "allof") {
1009  $matchAll = true;
1010  } else {
1011  $matchAll = false;
1012  }
1013 
1014  // at this point we know we have at least one of the properties to filter
1015  $matchCount = 0;
1016 
1017  // We need to allow for when a property is repeated, our match
1018  // might not be the first property.
1019  foreach( $properties AS $kk => $property ) {
1020  if ( empty($subfilter) || $property->TestFilter($subfilter, $matchAll) ) {
1021  $matchCount++;
1022  }
1023  }
1024 
1025  // in case of a param-filter/is-not-defined, there must be no single property with that parameter
1026  // otherwise (text-match), a single match is sufficient
1027  $matchesNeeded = 1;
1028  if ( $subtag == 'urn:ietf:params:xml:ns:caldav:param-filter'
1029  || $subtag == 'urn:ietf:params:xml:ns:carddav:param-filter' ) {
1030  $paramSubFilter = $subfilter[0]->GetContent();
1031  if (!empty($paramSubFilter)) {
1032  $paramSubFilterTag = $paramSubFilter[0]->getNSTag();
1033 
1034  if ( $paramSubFilterTag == 'urn:ietf:params:xml:ns:caldav:is-not-defined'
1035  || $paramSubFilterTag == 'urn:ietf:params:xml:ns:carddav:is-not-defined' ) {
1036  // none of the properties must have the parameter
1037  $matchesNeeded = count($properties);
1038  }
1039  }
1040  }
1041 
1042  if ($matchCount < $matchesNeeded) {
1043  return false;
1044  }
1045  }
1046  break;
1047  }
1048  }
1049  return true;
1050  }
1051 }
1052 
1053 
AddComponent( $new_component)
Definition: vComponent.php:666
getComponentAt($position)
Definition: vComponent.php:296
GetProperty( $type)
Definition: vComponent.php:382
AddProperty( $new_property, $value=null, $parameters=null)
Definition: vComponent.php:550
Render($restricted_properties=null, $force_rendering=false)
Definition: vComponent.php:899
RenderWithoutWrapFromObjects()
Definition: vComponent.php:812
RenderWithoutWrap($restricted_properties=null, $force_rendering=false)
Definition: vComponent.php:779
SetComponents( $new_component, $type=null)
Definition: vComponent.php:645
GetPValue( $type)
Definition: vComponent.php:399
WrapComponent( $content)
Definition: vComponent.php:751
ClearComponents( $type=null)
Definition: vComponent.php:609
UnwrapComponent(&$content)
Definition: vComponent.php:768
MaskComponents( $keep, $recursive=true)
Definition: vComponent.php:699
CollectParameterValues( $parameter_name)
Definition: vComponent.php:356
GetPropertiesByPath( $path)
Definition: vComponent.php:457
ClearProperties( $type=null)
Definition: vComponent.php:509
MaskProperties( $keep, $component_list=null)
Definition: vComponent.php:723
GetComponents( $type=null, $normal_match=true)
Definition: vComponent.php:581
GetProperties( $type=null)
Definition: vComponent.php:411
SetType( $type)
Definition: vComponent.php:343
TestFilter( $filters)
Definition: vComponent.php:928
RenderWithoutWrapFromIterator($unrolledComponents)
Definition: vComponent.php:831
SetProperties( $new_properties, $type=null)
Definition: vComponent.php:535