1: <?php
2: /**
3: * Handles recurrence data.
4: *
5: * PHP version 5
6: *
7: * @category Kolab
8: * @package Kolab_Format
9: * @author Gunnar Wrobel <wrobel@pardus.de>
10: * @license http://www.horde.org/licenses/lgpl21 LGPL
11: * @link http://www.horde.org/libraries/Horde_Kolab_Format
12: */
13:
14: /**
15: * Handles recurrence data.
16: *
17: * Copyright 2011-2012 Horde LLC (http://www.horde.org/)
18: *
19: * See the enclosed file COPYING for license information (LGPL). If you did not
20: * receive this file, see
21: * http://www.horde.org/licenses/lgpl21.
22: *
23: * @since Horde_Kolab_Format 1.1.0
24: *
25: * @category Kolab
26: * @package Kolab_Format
27: * @author Gunnar Wrobel <wrobel@pardus.de>
28: * @license http://www.horde.org/licenses/lgpl21 LGPL
29: * @link http://www.horde.org/libraries/Horde_Kolab_Format
30: */
31: class Horde_Kolab_Format_Xml_Type_Composite_Recurrence
32: extends Horde_Kolab_Format_Xml_Type_Composite
33: {
34: protected $elements = array(
35: 'interval' => 'Horde_Kolab_Format_Xml_Type_RecurrenceInterval',
36: 'day' => 'Horde_Kolab_Format_Xml_Type_Multiple_String',
37: 'daynumber' => 'Horde_Kolab_Format_Xml_Type_Integer',
38: 'month' => 'Horde_Kolab_Format_Xml_Type_String_MaybeMissing',
39: 'range' => 'Horde_Kolab_Format_Xml_Type_RecurrenceRange',
40: 'exclusion' => 'Horde_Kolab_Format_Xml_Type_Multiple_Date',
41: 'complete' => 'Horde_Kolab_Format_Xml_Type_Multiple_Date',
42: );
43:
44: /**
45: * Load the node value from the Kolab object.
46: *
47: * @param string $name The name of the the
48: * attribute to be fetched.
49: * @param array &$attributes The data array that
50: * holds all attribute
51: * values.
52: * @param DOMNode $parent_node The parent node of the
53: * node to be loaded.
54: * @param Horde_Kolab_Format_Xml_Helper $helper A XML helper instance.
55: * @param array $params Additiona parameters for
56: * this parse operation.
57: *
58: * @return DOMNode|boolean The named DOMNode or false if no node value was
59: * found.
60: */
61: public function load(
62: $name,
63: &$attributes,
64: $parent_node,
65: Horde_Kolab_Format_Xml_Helper $helper,
66: $params = array()
67: )
68: {
69: $result = parent::load($name, $attributes, $parent_node, $helper, $params);
70:
71: if ($node = $helper->findNodeRelativeTo('./' . $name, $parent_node)) {
72: // Get the cycle type (must be present)
73: $attributes['recurrence']['cycle'] = $node->getAttribute('cycle');
74: // Get the sub type (may be present)
75: $attributes['recurrence']['type'] = $node->getAttribute('type');
76: }
77: if (empty($attributes['recurrence'])) {
78: return $result;
79: }
80:
81: $recurrence = $attributes['recurrence'];
82:
83: if ($recurrence['interval'] < 0) {
84: throw new Horde_Kolab_Format_Exception_ParseError(
85: sprintf(
86: 'Recurrence: interval cannot be below zero [Value: %s]!',
87: $recurrence['interval']
88: )
89: );
90: }
91:
92: if (empty($recurrence['cycle'])) {
93: throw new Horde_Kolab_Format_Exception_ParseError('Recurrence: "cycle" attribute missing!');
94: }
95:
96: if ($recurrence['cycle'] == 'weekly') {
97: // Check for <day>
98: if (!isset($recurrence['day']) || count($recurrence['day']) == 0) {
99: throw new Horde_Kolab_Format_Exception_ParseError(
100: 'Recurrence: day tag missing for weekly recurrence!'
101: );
102: }
103: }
104:
105: // The code below is only for monthly or yearly recurrences
106: if ($recurrence['cycle'] == 'monthly'
107: || $recurrence['cycle'] == 'yearly') {
108: if (!isset($recurrence['type'])) {
109: throw new Horde_Kolab_Format_Exception_ParseError(
110: 'Recurrence: type attribute missing!'
111: );
112: }
113:
114: if (!isset($recurrence['daynumber'])) {
115: throw new Horde_Kolab_Format_Exception_ParseError(
116: 'Recurrence: daynumber tag missing!'
117: );
118: }
119: $daynumber = $recurrence['daynumber'];
120: if ($daynumber < 0) {
121: throw new Horde_Kolab_Format_Exception_ParseError(
122: sprintf(
123: 'Recurrence: daynumber cannot be below zero ["%s"]!',
124: $daynumber
125: )
126: );
127: }
128:
129: if ($recurrence['type'] == 'daynumber') {
130: if ($recurrence['cycle'] == 'yearly' && $daynumber > 366) {
131: throw new Horde_Kolab_Format_Exception_ParseError(
132: sprintf(
133: 'Recurrence: daynumber cannot be larger than 366 for yearly recurrences ["%s"]!',
134: $daynumber
135: )
136: );
137: } else if ($recurrence['cycle'] == 'monthly' && $daynumber > 31) {
138: throw new Horde_Kolab_Format_Exception_ParseError(
139: sprintf(
140: 'Recurrence: daynumber cannot be larger than 31 for monthly recurrences ["%s"]!',
141: $daynumber
142: )
143: );
144: }
145: } else if ($recurrence['type'] == 'weekday') {
146: // daynumber is the week of the month
147: if ($daynumber > 5) {
148: throw new Horde_Kolab_Format_Exception_ParseError(
149: sprintf(
150: 'Recurrence: daynumber cannot be larger than 5 for type weekday ["%s"]!',
151: $daynumber
152: )
153: );
154: }
155:
156: // Check for <day>
157: if (!isset($recurrence['day']) || count($recurrence['day']) == 0) {
158: throw new Horde_Kolab_Format_Exception_ParseError(
159: 'Recurrence: day tag missing for type weekday!'
160: );
161: }
162: }
163:
164: if (($recurrence['type'] == 'monthday' || $recurrence['type'] == 'yearday')
165: && $recurrence['cycle'] == 'monthly') {
166: throw new Horde_Kolab_Format_Exception_ParseError(
167: 'Recurrence: type monthday/yearday is only allowed for yearly recurrences'
168: );
169: }
170:
171: if ($recurrence['cycle'] == 'yearly') {
172: if ($recurrence['type'] == 'monthday') {
173: // daynumber and month
174: if (!isset($recurrence['month'])) {
175: throw new Horde_Kolab_Format_Exception_ParseError(
176: 'Recurrence: month tag missing for type monthday'
177: );
178: }
179: if ($daynumber > 31) {
180: throw new Horde_Kolab_Format_Exception_ParseError(
181: sprintf(
182: 'Recurrence: daynumber cannot be larger than 31 for type monthday ["%s"]!',
183: $daynumber
184: )
185: );
186: }
187: } else if ($recurrence['type'] == 'yearday') {
188: if ($daynumber > 366) {
189: throw new Horde_Kolab_Format_Exception_ParseError(
190: sprintf(
191: 'Recurrence: daynumber cannot be larger than 366 for type yearday ["%s"]!',
192: $daynumber
193: )
194: );
195: }
196: }
197: }
198:
199: }
200:
201: return $result;
202: }
203:
204: /**
205: * Update the specified attribute.
206: *
207: * @param string $name The name of the attribute
208: * to be updated.
209: * @param mixed $value The value to store.
210: * @param DOMNode $parent_node The parent node of the
211: * node that should be
212: * updated.
213: * @param Horde_Kolab_Format_Xml_Helper $helper A XML helper instance.
214: * @param array $params The parameters for this
215: * write operation.
216: * @param DOMNode|NULL $old_node The previous value (or
217: * null if there is none).
218: *
219: * @return DOMNode|boolean The new/updated child node or false if this
220: * failed.
221: *
222: * @throws Horde_Kolab_Format_Exception If converting the data to XML failed.
223: */
224: public function saveNodeValue(
225: $name,
226: $value,
227: $parent_node,
228: Horde_Kolab_Format_Xml_Helper $helper,
229: $params = array(),
230: $old_node = false
231: )
232: {
233: $node = parent::saveNodeValue($name, $value, $parent_node, $helper, $params, $old_node);
234: // Add attributes
235: $node->setAttribute('cycle', $value['cycle']);
236: if (isset($value['type'])) {
237: $node->setAttribute('type', $value['type']);
238: }
239: return $node;
240: }
241: }
242: