1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\VObject\Parser; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse 6*a1a3b679SAndreas Boehler Sabre\VObject\Component\VCalendar, 7*a1a3b679SAndreas Boehler Sabre\VObject\Component\VCard, 8*a1a3b679SAndreas Boehler Sabre\VObject\ParseException, 9*a1a3b679SAndreas Boehler Sabre\VObject\EofException; 10*a1a3b679SAndreas Boehler 11*a1a3b679SAndreas Boehler/** 12*a1a3b679SAndreas Boehler * Json Parser. 13*a1a3b679SAndreas Boehler * 14*a1a3b679SAndreas Boehler * This parser parses both the jCal and jCard formats. 15*a1a3b679SAndreas Boehler * 16*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/). 17*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 18*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 19*a1a3b679SAndreas Boehler */ 20*a1a3b679SAndreas Boehlerclass Json extends Parser { 21*a1a3b679SAndreas Boehler 22*a1a3b679SAndreas Boehler /** 23*a1a3b679SAndreas Boehler * The input data 24*a1a3b679SAndreas Boehler * 25*a1a3b679SAndreas Boehler * @var array 26*a1a3b679SAndreas Boehler */ 27*a1a3b679SAndreas Boehler protected $input; 28*a1a3b679SAndreas Boehler 29*a1a3b679SAndreas Boehler /** 30*a1a3b679SAndreas Boehler * Root component 31*a1a3b679SAndreas Boehler * 32*a1a3b679SAndreas Boehler * @var Document 33*a1a3b679SAndreas Boehler */ 34*a1a3b679SAndreas Boehler protected $root; 35*a1a3b679SAndreas Boehler 36*a1a3b679SAndreas Boehler /** 37*a1a3b679SAndreas Boehler * This method starts the parsing process. 38*a1a3b679SAndreas Boehler * 39*a1a3b679SAndreas Boehler * If the input was not supplied during construction, it's possible to pass 40*a1a3b679SAndreas Boehler * it here instead. 41*a1a3b679SAndreas Boehler * 42*a1a3b679SAndreas Boehler * If either input or options are not supplied, the defaults will be used. 43*a1a3b679SAndreas Boehler * 44*a1a3b679SAndreas Boehler * @param resource|string|array|null $input 45*a1a3b679SAndreas Boehler * @param int|null $options 46*a1a3b679SAndreas Boehler * @return array 47*a1a3b679SAndreas Boehler */ 48*a1a3b679SAndreas Boehler public function parse($input = null, $options = null) { 49*a1a3b679SAndreas Boehler 50*a1a3b679SAndreas Boehler if (!is_null($input)) { 51*a1a3b679SAndreas Boehler $this->setInput($input); 52*a1a3b679SAndreas Boehler } 53*a1a3b679SAndreas Boehler if (is_null($this->input)) { 54*a1a3b679SAndreas Boehler throw new EofException('End of input stream, or no input supplied'); 55*a1a3b679SAndreas Boehler } 56*a1a3b679SAndreas Boehler 57*a1a3b679SAndreas Boehler if (!is_null($options)) { 58*a1a3b679SAndreas Boehler $this->options = $options; 59*a1a3b679SAndreas Boehler } 60*a1a3b679SAndreas Boehler 61*a1a3b679SAndreas Boehler switch($this->input[0]) { 62*a1a3b679SAndreas Boehler case 'vcalendar' : 63*a1a3b679SAndreas Boehler $this->root = new VCalendar(array(), false); 64*a1a3b679SAndreas Boehler break; 65*a1a3b679SAndreas Boehler case 'vcard' : 66*a1a3b679SAndreas Boehler $this->root = new VCard(array(), false); 67*a1a3b679SAndreas Boehler break; 68*a1a3b679SAndreas Boehler default : 69*a1a3b679SAndreas Boehler throw new ParseException('The root component must either be a vcalendar, or a vcard'); 70*a1a3b679SAndreas Boehler 71*a1a3b679SAndreas Boehler } 72*a1a3b679SAndreas Boehler foreach($this->input[1] as $prop) { 73*a1a3b679SAndreas Boehler $this->root->add($this->parseProperty($prop)); 74*a1a3b679SAndreas Boehler } 75*a1a3b679SAndreas Boehler if (isset($this->input[2])) foreach($this->input[2] as $comp) { 76*a1a3b679SAndreas Boehler $this->root->add($this->parseComponent($comp)); 77*a1a3b679SAndreas Boehler } 78*a1a3b679SAndreas Boehler 79*a1a3b679SAndreas Boehler // Resetting the input so we can throw an feof exception the next time. 80*a1a3b679SAndreas Boehler $this->input = null; 81*a1a3b679SAndreas Boehler 82*a1a3b679SAndreas Boehler return $this->root; 83*a1a3b679SAndreas Boehler 84*a1a3b679SAndreas Boehler } 85*a1a3b679SAndreas Boehler 86*a1a3b679SAndreas Boehler /** 87*a1a3b679SAndreas Boehler * Parses a component 88*a1a3b679SAndreas Boehler * 89*a1a3b679SAndreas Boehler * @param array $jComp 90*a1a3b679SAndreas Boehler * @return \Sabre\VObject\Component 91*a1a3b679SAndreas Boehler */ 92*a1a3b679SAndreas Boehler public function parseComponent(array $jComp) { 93*a1a3b679SAndreas Boehler 94*a1a3b679SAndreas Boehler // We can remove $self from PHP 5.4 onward. 95*a1a3b679SAndreas Boehler $self = $this; 96*a1a3b679SAndreas Boehler 97*a1a3b679SAndreas Boehler $properties = array_map( 98*a1a3b679SAndreas Boehler function($jProp) use ($self) { 99*a1a3b679SAndreas Boehler return $self->parseProperty($jProp); 100*a1a3b679SAndreas Boehler }, 101*a1a3b679SAndreas Boehler $jComp[1] 102*a1a3b679SAndreas Boehler ); 103*a1a3b679SAndreas Boehler 104*a1a3b679SAndreas Boehler if (isset($jComp[2])) { 105*a1a3b679SAndreas Boehler 106*a1a3b679SAndreas Boehler $components = array_map( 107*a1a3b679SAndreas Boehler function($jComp) use ($self) { 108*a1a3b679SAndreas Boehler return $self->parseComponent($jComp); 109*a1a3b679SAndreas Boehler }, 110*a1a3b679SAndreas Boehler $jComp[2] 111*a1a3b679SAndreas Boehler ); 112*a1a3b679SAndreas Boehler 113*a1a3b679SAndreas Boehler } else $components = array(); 114*a1a3b679SAndreas Boehler 115*a1a3b679SAndreas Boehler return $this->root->createComponent( 116*a1a3b679SAndreas Boehler $jComp[0], 117*a1a3b679SAndreas Boehler array_merge($properties, $components), 118*a1a3b679SAndreas Boehler $defaults = false 119*a1a3b679SAndreas Boehler ); 120*a1a3b679SAndreas Boehler 121*a1a3b679SAndreas Boehler } 122*a1a3b679SAndreas Boehler 123*a1a3b679SAndreas Boehler /** 124*a1a3b679SAndreas Boehler * Parses properties. 125*a1a3b679SAndreas Boehler * 126*a1a3b679SAndreas Boehler * @param array $jProp 127*a1a3b679SAndreas Boehler * @return \Sabre\VObject\Property 128*a1a3b679SAndreas Boehler */ 129*a1a3b679SAndreas Boehler public function parseProperty(array $jProp) { 130*a1a3b679SAndreas Boehler 131*a1a3b679SAndreas Boehler list( 132*a1a3b679SAndreas Boehler $propertyName, 133*a1a3b679SAndreas Boehler $parameters, 134*a1a3b679SAndreas Boehler $valueType 135*a1a3b679SAndreas Boehler ) = $jProp; 136*a1a3b679SAndreas Boehler 137*a1a3b679SAndreas Boehler $propertyName = strtoupper($propertyName); 138*a1a3b679SAndreas Boehler 139*a1a3b679SAndreas Boehler // This is the default class we would be using if we didn't know the 140*a1a3b679SAndreas Boehler // value type. We're using this value later in this function. 141*a1a3b679SAndreas Boehler $defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName); 142*a1a3b679SAndreas Boehler 143*a1a3b679SAndreas Boehler $parameters = (array)$parameters; 144*a1a3b679SAndreas Boehler 145*a1a3b679SAndreas Boehler $value = array_slice($jProp, 3); 146*a1a3b679SAndreas Boehler 147*a1a3b679SAndreas Boehler $valueType = strtoupper($valueType); 148*a1a3b679SAndreas Boehler 149*a1a3b679SAndreas Boehler if (isset($parameters['group'])) { 150*a1a3b679SAndreas Boehler $propertyName = $parameters['group'] . '.' . $propertyName; 151*a1a3b679SAndreas Boehler unset($parameters['group']); 152*a1a3b679SAndreas Boehler } 153*a1a3b679SAndreas Boehler 154*a1a3b679SAndreas Boehler $prop = $this->root->createProperty($propertyName, null, $parameters, $valueType); 155*a1a3b679SAndreas Boehler $prop->setJsonValue($value); 156*a1a3b679SAndreas Boehler 157*a1a3b679SAndreas Boehler // We have to do something awkward here. FlatText as well as Text 158*a1a3b679SAndreas Boehler // represents TEXT values. We have to normalize these here. In the 159*a1a3b679SAndreas Boehler // future we can get rid of FlatText once we're allowed to break BC 160*a1a3b679SAndreas Boehler // again. 161*a1a3b679SAndreas Boehler if ($defaultPropertyClass === 'Sabre\VObject\Property\FlatText') { 162*a1a3b679SAndreas Boehler $defaultPropertyClass = 'Sabre\VObject\Property\Text'; 163*a1a3b679SAndreas Boehler } 164*a1a3b679SAndreas Boehler 165*a1a3b679SAndreas Boehler // If the value type we received (e.g.: TEXT) was not the default value 166*a1a3b679SAndreas Boehler // type for the given property (e.g.: BDAY), we need to add a VALUE= 167*a1a3b679SAndreas Boehler // parameter. 168*a1a3b679SAndreas Boehler if ($defaultPropertyClass !== get_class($prop)) { 169*a1a3b679SAndreas Boehler $prop["VALUE"] = $valueType; 170*a1a3b679SAndreas Boehler } 171*a1a3b679SAndreas Boehler 172*a1a3b679SAndreas Boehler return $prop; 173*a1a3b679SAndreas Boehler 174*a1a3b679SAndreas Boehler } 175*a1a3b679SAndreas Boehler 176*a1a3b679SAndreas Boehler /** 177*a1a3b679SAndreas Boehler * Sets the input data 178*a1a3b679SAndreas Boehler * 179*a1a3b679SAndreas Boehler * @param resource|string|array $input 180*a1a3b679SAndreas Boehler * @return void 181*a1a3b679SAndreas Boehler */ 182*a1a3b679SAndreas Boehler public function setInput($input) { 183*a1a3b679SAndreas Boehler 184*a1a3b679SAndreas Boehler if (is_resource($input)) { 185*a1a3b679SAndreas Boehler $input = stream_get_contents($input); 186*a1a3b679SAndreas Boehler } 187*a1a3b679SAndreas Boehler if (is_string($input)) { 188*a1a3b679SAndreas Boehler $input = json_decode($input); 189*a1a3b679SAndreas Boehler } 190*a1a3b679SAndreas Boehler $this->input = $input; 191*a1a3b679SAndreas Boehler 192*a1a3b679SAndreas Boehler } 193*a1a3b679SAndreas Boehler 194*a1a3b679SAndreas Boehler} 195