Func_CalendarBackend_Caldav::selectPeriods()   F
last analyzed

Complexity

Conditions 32
Paths 377

Size

Total Lines 162

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 285.4961

Importance

Changes 0
Metric Value
cc 32
nc 377
nop 1
dl 0
loc 162
rs 0.8966
c 0
b 0
f 0
ccs 32
cts 86
cp 0.3721
crap 285.4961

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
//-------------------------------------------------------------------------
3
// OVIDENTIA http://www.ovidentia.org
4
// Ovidentia is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 2, or (at your option)
7
// any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
// See the GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17
// USA.
18
//-------------------------------------------------------------------------
19
/**
20
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
21
 * @copyright Copyright (c) 2010 by CANTICO ({@link http://www.cantico.fr})
22
 */
23
24
25
require_once dirname(__FILE__) . '/functions.php';
26
require_once dirname(__FILE__) . '/caldav/caldav-client.php';
27
require_once dirname(__FILE__) . '/sessionfile.class.php';
28
29
bab_functionality::includefile('CalendarBackend');
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class bab_functionality as the method includefile() does only exist in the following sub-classes of bab_functionality: Func_Archive, Func_Archive_Zip, Func_Archive_Zip_ZipArchive, Func_Archive_Zip_Zlib, Func_CalendarBackend, Func_CalendarBackend_Caldav, Func_CalendarBackend_Ovi, Func_Icons, Func_Icons_Default, Func_Ovml, Func_Ovml_Container, Func_Ovml_Container_Addon, Func_Ovml_Container_Article, Func_Ovml_Container_ArticleCategories, Func_Ovml_Container_ArticleCategory, Func_Ovml_Container_ArticleCategoryNext, Func_Ovml_Container_ArticleCategoryPrevious, Func_Ovml_Container_ArticleFiles, Func_Ovml_Container_ArticleNext, Func_Ovml_Container_ArticlePrevious, Func_Ovml_Container_ArticleTopic, Func_Ovml_Container_ArticleTopicNext, Func_Ovml_Container_ArticleTopicPrevious, Func_Ovml_Container_ArticleTopics, Func_Ovml_Container_Articles, Func_Ovml_Container_ArticlesHomePages, Func_Ovml_Container_CalendarCategories, Func_Ovml_Container_CalendarEventDomains, Func_Ovml_Container_CalendarEvents, Func_Ovml_Container_CalendarGroupEvents, Func_Ovml_Container_CalendarResourceEvents, Func_Ovml_Container_CalendarUserEvents, Func_Ovml_Container_Calendars, Func_Ovml_Container_DbDirectories, Func_Ovml_Container_DbDirectory, Func_Ovml_Container_DbDirectoryAcl, Func_Ovml_Container_DbDirectoryEntry, Func_Ovml_Container_DbDirectoryEntryFields, Func_Ovml_Container_DbDirectoryFields, Func_Ovml_Container_DbDirectoryMemberFields, Func_Ovml_Container_DbDirectoryMembers, Func_Ovml_Container_Delegation, Func_Ovml_Container_DelegationAdministrators, Func_Ovml_Container_DelegationItems, Func_Ovml_Container_DelegationManaged, Func_Ovml_Container_Delegations, Func_Ovml_Container_DelegationsCategories, Func_Ovml_Container_DelegationsCategory, Func_Ovml_Container_DelegationsManaged, Func_Ovml_Container_Faq, Func_Ovml_Container_FaqNext, Func_Ovml_Container_FaqPrevious, Func_Ovml_Container_FaqQuestion, Func_Ovml_Container_FaqQuestionNext, Func_Ovml_Container_FaqQuestionPrevious, Func_Ovml_Container_FaqQuestions, Func_Ovml_Container_FaqSubCategories, Func_Ovml_Container_FaqSubCategory, Func_Ovml_Container_Faqs, Func_Ovml_Container_File, Func_Ovml_Container_FileFields, Func_Ovml_Container_FileNext, Func_Ovml_Container_FilePrevious, Func_Ovml_Container_Files, Func_Ovml_Container_Folder, Func_Ovml_Container_FolderNext, Func_Ovml_Container_FolderPrevious, Func_Ovml_Container_Folders, Func_Ovml_Container_Forum, Func_Ovml_Container_ForumNext, Func_Ovml_Container_ForumPrevious, Func_Ovml_Container_Forums, Func_Ovml_Container_IfEqual, Func_Ovml_Container_IfGreaterThan, Func_Ovml_Container_IfGreaterThanOrEqual, Func_Ovml_Container_IfIsSet, Func_Ovml_Container_IfLessThan, Func_Ovml_Container_IfLessThanOrEqual, Func_Ovml_Container_IfNotEqual, Func_Ovml_Container_IfNotIsSet, Func_Ovml_Container_IfUserMemberOfGroups, Func_Ovml_Container_Multipages, Func_Ovml_Container_ObjectsInfo, Func_Ovml_Container_OrgPathToEntity, Func_Ovml_Container_OrgUserEntities, Func_Ovml_Container_OvmlArray, Func_Ovml_Container_OvmlArrayFields, Func_Ovml_Container_OvmlSoap, Func_Ovml_Container_ParentsArticleCategory, Func_Ovml_Container_Post, Func_Ovml_Container_PostFiles, Func_Ovml_Container_RecentArticles, Func_Ovml_Container_RecentComments, Func_Ovml_Container_RecentFaqQuestions, Func_Ovml_Container_RecentFiles, Func_Ovml_Container_RecentPosts, Func_Ovml_Container_RecentThreads, Func_Ovml_Container_SitemapEntries, Func_Ovml_Container_SitemapEntry, Func_Ovml_Container_SitemapPath, Func_Ovml_Container_Soap, Func_Ovml_Container_SubFolders, Func_Ovml_Container_Tags, Func_Ovml_Container_Thread, Func_Ovml_Container_TmProjects, Func_Ovml_Container_TmSpaces, Func_Ovml_Container_TmTaskFields, Func_Ovml_Container_TmTasks, Func_Ovml_Container_WaitingArticles, Func_Ovml_Container_WaitingComments, Func_Ovml_Container_WaitingFiles, Func_Ovml_Container_WaitingPosts, Func_Ovml_Function, Func_Ovml_Function_AOAddition, Func_Ovml_Function_AODivision, Func_Ovml_Function_AOModulus, Func_Ovml_Function_AOMultiplication, Func_Ovml_Function_AOSubtraction, Func_Ovml_Function_AddStyleSheet, Func_Ovml_Function_Addon, Func_Ovml_Function_Ajax, Func_Ovml_Function_ArticleTree, Func_Ovml_Function_FileTree, Func_Ovml_Function_Get, Func_Ovml_Function_GetCookie, Func_Ovml_Function_GetPageTitle, Func_Ovml_Function_GetPath, Func_Ovml_Function_GetSessionVar, Func_Ovml_Function_GetVar, Func_Ovml_Function_Header, Func_Ovml_Function_IfNotIsSet, Func_Ovml_Function_Include, Func_Ovml_Function_NextArticle, Func_Ovml_Function_Post, Func_Ovml_Function_PreviousArticle, Func_Ovml_Function_PreviousOrNextArticle, Func_Ovml_Function_PutArray, Func_Ovml_Function_PutSoapArray, Func_Ovml_Function_PutVar, Func_Ovml_Function_Recurse, Func_Ovml_Function_Request, Func_Ovml_Function_SetCookie, Func_Ovml_Function_SetSessionVar, Func_Ovml_Function_SitemapCustomNodeId, Func_Ovml_Function_SitemapMenu, Func_Ovml_Function_SitemapPosition, Func_Ovml_Function_SitemapUrl, Func_Ovml_Function_Translate, Func_Ovml_Function_UrlContent, Func_Ovml_Function_WebStat, Func_PortalAuthentication, Func_PortalAuthentication_AuthOvidentia, Func_SearchUi, Func_SitemapDynamicNode, Func_SitemapDynamicNode_Topic, Func_UserEditor, Func_WorkingHours, Func_WorkingHours_Ovidentia, Ovml_Container_Sitemap, bab_ArithmeticOperator, bab_Ovml_Container_Operator, bab_rgp. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
30
31
32
class Func_CalendarBackend_Caldav extends Func_CalendarBackend
33
{
34
35
36
	/**
37
	 * @var CalDAVClient
38
	 */
39
	protected $caldavClient;
40
41
42
	/**
43
	 * @var string
44
	 */
45
	private $serverUrl = null;
46
47
48
49
50
	/**
51
	 * @return string
52
	 * @static
53
	 */
54
	public function getDescription()
55
	{
56
		return caldav_translate('CalDAV server');
57
	}
58
59
60
	/**
61
	 * The backend can be used as a storage backend for the existing calendars (personal only for now)
62
	 * @return bool
63
	 */
64
	public function StorageBackend()
65
	{
66 1
		return $this->getStorageBackend();
67
	}
68 1
69
70
	/**
71
	 * Register myself as a functionality.
72
	 * @static
73
	 */
74
	public function register()
75
	{
76
		require_once $GLOBALS['babInstallPath'].'utilit/functionalityincl.php';
77
		$functionalities = new bab_functionalities();
78
		$functionalities->registerClass(__CLASS__, __FILE__);
79
	}
80
81
82
83
84
	public function includeEventCalendar()
85
	{
86 7
		require_once dirname(__FILE__).'/eventcalendar.class.php';
87
	}
88 7
89 7
90
91
92
	/**
93
	 *
94
	 * @param	int	$userId		owner of calendar
95
	 *
96
	 * @return caldav_PersonalCalendar
97
	 */
98
	public function PersonalCalendar($userId)
99
	{
100 7
		$this->includeEventCalendar();
101
		$calendar = new caldav_PersonalCalendar($this);
102 7
		$calendar->setIdUser($userId);
103 7
		return $calendar;
104 7
	}
105 7
106
	
107
	
108
	public function ResourceCalendar($id, Array $configuration)
109
	{
110
		$this->includeEventCalendar();
111
		$calendar = new caldav_ResourceCalendar($this);
112
		$calendar->setUid($id);
113
		$calendar->setConfiguration($configuration);
114
		return $calendar;
115
	}
116
	
117
118
119
120
	public function includeCalendarPeriod()
121
	{
122 7
		require_once dirname(__FILE__).'/calendarperiod.class.php';
123
	}
124 7
125 7
126
127
128
	/**
129
	 * Create new calendar period
130
	 *
131
	 * @param int $begin	Timestamp
132
	 * @param int $end		Timestamp
133
	 *
134
	 * @return caldav_CalendarPeriod
135
	 */
136
	public function CalendarPeriod($begin = null, $end = null)
137
	{
138 5
		$this->includeCalendarPeriod();
139
		return new caldav_CalendarPeriod();
140 5
	}
141 5
142
143
144
	public function includeCalendarAlarm()
145
	{
146
		require_once dirname(__FILE__).'/calendarperiod.class.php';
147
	}
148
149
	/**
150
	 * Create new calendar alarm
151
	 * VALARM object item, store rules for reminder on event
152
	 * @see bab_CalendarPeriod::setAlarm()
153
	 *
154
	 * @return caldav_CalendarAlarm
155
	 */
156
	public function CalendarAlarm()
157
	{
158
		$this->includeCalendarAlarm();
159
		return new caldav_CalendarAlarm();
160
	}
161
162
163
164
	public function getProdId()
165
	{
166 3
		return 'PRODID:-//Cantico//NONSGML Ovidentia CalDAV Client//EN';
167
	}
168 3
169
170
	/**
171
	 * Returns the timezone name. E.g. 'Europe/Paris'.
172
	 *
173
	 * @return string
174
	 */
175
	static public function getTimezoneName()
176
	{
177 3
		$timezone = date_default_timezone_get();
178
	    if (strtolower($timezone) === 'system/localtime') {
179 3
	    	$timezone = 'Europe/Paris';
180 3
	    }
181
182
	    return $timezone;
183
	}
184 3
185
186
	/**
187
	 * Returns the timezone's icalendar definition.
188
	 *  BEGIN:VTIMEZONE
189
	 *  ...
190
	 *  END:VTIMEZONE
191
	 *
192
	 * @return string
193
	 */
194
	public function getTimeZone()
195
	{
196 3
	    static $vtimezone = null;
197
	    if (isset($vtimezone)) {
198 3
	        return $vtimezone;
199 3
	    }
200 2
201
	    $timezone = self::getTimezoneName();
202
203 1
	    if ($addon = bab_getAddonInfosInstance('LibCaldav')) {
204
	        $timezoneFilename = $addon->getTemplatePath() . 'zoneinfo/' . $timezone . '.ics';
205 1
	    } else {
206
	        $timezoneFilename = dirname(__FILE__).'/../skins/ovidentia/templates/zoneinfo/' . $timezone . '.ics';
207
	    }
208 1
209
	    $vcalendar = @file_get_contents($timezoneFilename);
210
	    if ($vcalendar !== false) {
211 1
212 1
	        $m = null;
213
	        preg_match('/(BEGIN:VTIMEZONE.*END:VTIMEZONE)/Us', $vcalendar, $m);
214 1
215 1
	        $vtimezone = $m[0];
216
	        $vtimezone = str_replace("\n", "\r\n", $vtimezone);
217 1
	        $vtimezone .= "\r\n";
218 1
	        return $vtimezone;
219 1
	    }
220 1
221
 		$vtimezone = 'BEGIN:VTIMEZONE' . "\r\n"
222
                    . 'TZID:Europe/Paris' . "\r\n"
223
                    . 'X-LIC-LOCATION:Europe/Paris' . "\r\n"
224
                    . 'BEGIN:DAYLIGHT' . "\r\n"
225
                    . 'TZOFFSETFROM:+0100' . "\r\n"
226
                    . 'TZOFFSETTO:+0200' . "\r\n"
227
                    . 'TZNAME:CEST' . "\r\n"
228
                    . 'DTSTART:19700329T020000' . "\r\n"
229
                    . 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3' . "\r\n"
230
                    . 'END:DAYLIGHT' . "\r\n"
231
                    . 'BEGIN:STANDARD' . "\r\n"
232
                    . 'TZOFFSETFROM:+0200' . "\r\n"
233
                    . 'TZOFFSETTO:+0100' . "\r\n"
234
                    . 'TZNAME:CET' . "\r\n"
235
                    . 'DTSTART:19701025T030000' . "\r\n"
236
                    . 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10' . "\r\n"
237
                    . 'END:STANDARD' . "\r\n"
238
                    . 'END:VTIMEZONE' . "\r\n";
239
 		return $vtimezone;
240
	}
241
242
243
244
245
246
247
248
	/**
249
	 * Sets the base url to access the CalDAV server.
250
	 *
251
	 * @param string $url  The URL for the calendar server
252
	 *
253
	 * @return Func_CalendarBackend_Caldav
254
	 */
255
	public function setServerUrl($url)
256
	{
257
		$this->serverUrl = $url;
258
259
		return $this;
260
	}
261
	
262
	
263
	/**
264
	 * 
265
	 * @param int $userId
266
	 * @return int | null
267
	 */
268
	public function getUserServerId($userId)
269
	{
270 8
		$registry = bab_getRegistryInstance();
271
		$registry->changeDirectory('/LibCaldav/Users/' . $userId);
272 8
		return $registry->getValue('server');
273 8
	}
274 8
275
	public function getUniqueId($userId)
276
	{
277
		$registry = bab_getRegistryInstance();
278
		$registry->changeDirectory('/LibCaldav/Users/' . $userId);
279
		return $registry->getValue('uniqueId');
280
	}
281
282
	
283 8
	/**
284
	 * Get server configuration
285 8
	 * @param int $id_server
286
	 * @return array
287 8
	 */
288 8
	public function getServer($id_server)
289
	{
290 8
		global $babDB;
291
		
292
		$res = $babDB->db_query('SELECT * FROM libcaldav_servers WHERE id='.$babDB->quote($id_server));
293
		while($arr = $babDB->db_fetch_assoc($res))
294
		{
295
			return $arr;
296
		}
297
		
298
		return null;
299
	}
300
301
	public function getServerNeedId($userid)
302
	{
303 8
		global $babDB;
304
		$id_server = $this->getUserServerId($userid);
305 8
		$res = $babDB->db_query('SELECT * FROM libcaldav_servers WHERE id='.$babDB->quote($id_server));
306 8
		while($arr = $babDB->db_fetch_assoc($res))
307 8
		{
308 8
			if($arr["use_unique_id"]=="true")
309
			{
310
				return true;
311
			}
312 8
			else
313
			{
314 8
				return false;
315
			}
316
		}
317
		
318
		return null;
319
	}
320
321
322
323
	/**
324
	 * returns the base url to access the CalDAV server.
325
	 * @param	int	$userId
326
	 * @return string
327
	 */
328
	public function getServerUrl($userId)
329
	{
330
		if (!isset($this->serverUrl)) {
331
			$id_server = $this->getUserServerId($userId);
332
			if (!isset($id_server))
333
			{
334
				return null;
335
			}
336
			
337
			$server = $this->getServer($id_server);
338
			
339
			return $server['server_url'];
340
		}
341
		return $this->serverUrl;
342
	}
343
344
345
346
347
	/**
348 1
	 * Returns the href identifier of a caldav user corresponding to an
349
	 * ovidentia user.
350 1
	 *
351 1
	 * @param int	$userId		An ovidentia user id.
352
	 */
353 1
	public function getUserHref($userId)
354
	{
355
		if ($this->configByUser()) {
356
		
357
			return $this->getUserIdentifier($userId);
358
		}
359
		
360
		return bab_getUserNickname($userId);
361 1
	}
362
363
364
365 1
366 1
	/**
367
	 * check a personnal calendar with user configuration
368 1
	 *
369
	 * @param int	$userId
370
	 *
371
	 * @return bool
372 1
	 */
373
	public function checkCalendar($userId)
374
	{
375
		$path = $this->getPersonnalCalendarUrl($userId);
376
		list($nickname, $password) = $this->getPersonalCalendarCredentials($userId);
377
		
378
		$this->caldavClient = new CalDAVClient($path, $nickname, $password, 'calendar');
379
		
380
381
		$xml = '<?xml version="1.0" encoding="utf-8" ?>
382 7
		<D:propfind xmlns:D="DAV:">
383
		<D:prop>
384 7
		<D:current-user-privilege-set/>
385 7
		</D:prop>
386
		</D:propfind>';
387
388
389
		try {
390
			$this->caldavClient->SetDepth(0);
391
			$response = $this->caldavClient->DoXMLRequest('PROPFIND', $xml, '');
392
393
		} catch (Exception $e) {
394
			return false;
395
		}
396
397
		return !empty($response);
398
	}
399
400
	/**
401
	 *
402
	 * @param caldav_EventCalendar $calendar
403
	 * @param $relativePath
404
	 *
405
	 * @return Func_CalendarBackend_Caldav
406
	 */
407
	public function init(caldav_EventCalendar $calendar)
408
	{	
409
		$this->caldavClient = $calendar->getCaldavClient();
410
		return $this;
411
	}
412
413
414
415
	/**
416
	 * The list of calendars recorded with the sharing access form
417
	 * to use theses calendars, the user must have a personal calendar or $babBody->babsite['iPersonalCalendarAccess'] == 'Y'
418
	 *
419
	 * @param int		$access_user		in most case, the current user
420
	 * @param string	$calendartype		optional filter by calendar type
421
	 * @return array	<int>				array of id_user
422
	 */
423
	public function getAccessiblePersonalCalendars($access_user = null, $calendartype = null)
424
	{
425
		/*@var $backend Func_CalendarBackend_Ovi */
426
		$backend = bab_functionality::get('CalendarBackend/Ovi');
427
		if (!isset($backend)) {
428
			return array();
429
		}
430
431
		return $backend->getAccessiblePersonalCalendars($access_user, $calendartype);
432
	}
433
	
434
	
435
	
436
	/**
437
	 * @return array
438
	 */
439
	public function getAccessibleResourceCalendars()
440
	{
441
		
442
		$arr = bab_getUserIdObjects('libcaldav_resource_groups');
443
		
444
		if (empty($arr))
445
		{
446
			return array();
447
		}
448
		
449
		global $babDB;
450
		
451
		$res = $babDB->db_query('SELECT * FROM libcaldav_resources WHERE id IN('.$babDB->quote($arr).')');
452
		$return = array();
453
		while ($arr = $babDB->db_fetch_assoc($res))
454
		{
455
			$return[$arr['id']] = array(
456
				'name' => $arr['name'],
457
				'url' => $arr['url'],
458
				'nickname' => $arr['nickname'],
459
				'password' => $arr['password']	
460
			);
461
		}
462
		
463
		return $return;
464
	}
465
466
467
468
	public function iCalObjectToVcalendarInvitation(bab_ICalendarObject $icalObject, bab_PersonalCalendar $calendar)
0 ignored issues
show
Unused Code introduced by
The parameter $calendar 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...
469
	{
470
		$this->includeCalendarPeriod();
471
		$vcalendar = 'BEGIN:VCALENDAR' . "\n"
472 3
		. $this->getProdId() . "\n"
473
		. 'VERSION:2.0' . "\n"
474 3
		. 'METHOD:REQUEST' . "\n"
475 3
		. $this->getTimeZone();
476 3
477
		$vcalendar .= caldav_CalendarPeriod::toIcal($icalObject) . "\n";
0 ignored issues
show
Compatibility introduced by
$icalObject of type object<bab_ICalendarObject> is not a sub-type of object<bab_CalendarPeriod>. It seems like you assume a child class of the class bab_ICalendarObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
478 3
479 3
		$vcalendar .= 'END:VCALENDAR';
480
481
		return $vcalendar;
482
	}
483 3
484
485
486
487
	/**
488
	 * Creates or updates a calendar event.
489
	 *
490
	 * @param 	caldav_CalendarPeriod 	$period
491
	 * @param	string					$method		iCalendar Transport-Independent Interoperability Protocol (iTIP) (RFC 5546)
492 3
	 * 												PUBLISH | REQUEST | REPLY | ADD | CANCEL | REFRESH | COUNTER | DECLINECOUNTER
493 3
	 *
494
	 *
495
	 * @return bool		true if the period was correctly saved.
496
	 */
497
	public function savePeriod(bab_CalendarPeriod $period, $method = null)
498
	{
499
		$this->includeCalendarPeriod();
500
		$periodCollection = $period->getCollection();
501
		$calendar = $periodCollection->getCalendar();
502
503
		if (!($calendar instanceof caldav_EventCalendar))
504
		{
505 3
			throw new ErrorException(sprintf('failed to save the event %s, wrong calendar type %s', $period->getProperty('UID'), $calendar->getUrlIdentifier()));
506
		}
507 3
508
		$this->init($calendar);
509
510
511
		// Kerio specific :
512
		// when events selected from KERIO caldav server,
513
		// the ORGANIZER of an event is removed from the list of attendees
514
		// to fix this problem, we add X-CTO-ORGANIZER-PARTSTAT to store the PARTSTAT of the ORGANIZER
515
		// only if the organizer is in the list of attendees
516
517
		if ($organizer = $period->getOrganizer())
518
		{
519
			foreach($period->getAttendees() as $attendee)
520
			{
521
				if ($attendee['email'] === $organizer['email'] && $organizer['name'] === $attendee['CN'])
522 3
				{
523 3
					$period->setProperty('X-CTO-ORGANIZER-PARTSTAT', $attendee['PARTSTAT']);
524
					break;
525 3
				}
526
			}
527
		}
528
529
530
		$uid = $period->getProperty('UID');
531
532 3
		if (empty($uid)) {
533 3
			// create the event with generated ID
534
			$uid = uniqid();
535 3
			$period->setProperty('UID', $uid);
536 3
			$period->setProperty('SEQUENCE', 1);
537
			$period->setProperty('DTSTAMP', BAB_DateTime::now()->getICal(true));
538 3
			$period->setProperty('CREATED', BAB_DateTime::now()->getICal(true));
539
			$newEvent = true;
540 1
			$originalPeriods = array(clone $period);
541
542
		} else {
543
		    
544 1
		    
545 3
		    // optional delete on cancel
546
		    
547
		    $registry = bab_getRegistryInstance();
548 3
		    $registry->changeDirectory('/LibCaldav/');
549 3
		    
550
		    if ('CANCEL' === $method && $registry->getValue('deleteOnCancel')) {
551 1
		        return $this->deletePeriod($period);
552 1
		    }
553
		    
554
555
			// try to update SEQUENCE
556 2
557 2
			$sequence = 1 + (int) $period->getProperty('SEQUENCE');
558
			$period->setProperty('SEQUENCE', $sequence);
559
560
			$icalEvents = $this->caldavClient->GetEntryByUid($uid);
561 3
			$originalPeriods = null;
562
563 3
			foreach ($icalEvents as $icalEvent) {
564 3
			    
565
			    if (!isset($icalEvent['data'])) {
566
			        continue;
567
			    }
568
			    
569
				$originalPeriods = $this->expandPeriods($icalEvent['data'], $periodCollection, false);
570
			}
571
572
573
			if (isset($originalPeriods))
574
			{
575
				// Modification of an existing event.
576
				$newEvent = false;
577
			}
578
			else
579
			{
580
				// create the event with given ID
581
				$originalPeriods = array(clone $period);
582 3
				$newEvent = true;
583
			}
584
585 3
			/* @var $replacedPeriod bab_ICalendarObject */
586
			$replacedPeriod = null;
0 ignored issues
show
Unused Code introduced by
$replacedPeriod is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
587
588 3
			$recurrenceId = $period->getProperty('RECURRENCE-ID');
589 3
			if ($recurrenceId !== '') {
590 3
591
				// Here we know we change only one recurrence period in the event.
592
				if (is_array($recurrenceId)) {
593
					$recurrenceId = array_pop($recurrenceId);
594 3
				}
595
				if (isset($originalPeriods[$recurrenceId])) {
596 3
					// The recurrence id already exist, we replace the period.
597 3
					$replacedPeriod = $originalPeriods[$recurrenceId];
598 3
				} else {
599
					// The recurrence id does not already exist, we create a new period recurrence.
600
					$replacedPeriod = null;
601 3
					$originalPeriods[$recurrenceId] = $period;
602 3
				}
603 3
604 3
			} else {
605
606 3
				// Here we know we change all the periods in the event.
607 1
				$replacedPeriod = reset($originalPeriods);
608 3
			}
609
610 3
			if (isset($replacedPeriod) && $replacedPeriod) {
611 2
612 2
				try {
613
					$replacedPeriod->removeAttendees();
614 2
					$replacedPeriod->removeRelations();
615 2
				} catch(Exception $e){
616
					// relation could not be removed if there is an ongoing approbation
617
				}
618
619
				foreach ($period->getProperties() as $icalProperty) {
620
621
					$colonPos = mb_strpos($icalProperty, ':');
622
					$propName = substr($icalProperty, 0, $colonPos);
623
					$propValue = substr($icalProperty, $colonPos + 1);
624
					
625
626
					if (!empty($propValue)) {
627
						$replacedPeriod->setProperty($propName, $propValue);
628
					}
629
				}
630
631
				foreach ($period->getRelations() as $relation) {
632
					$replacedPeriod->addRelation($relation['reltype'], $relation['calendar']);
633
				}
634
635
				foreach ($period->getAllAttendees() as $attendee) {
636
					if (isset($attendee['calendar']))
637
					{
638
						// the calendar of attendee is accessible
639 3
						$replacedPeriod->addAttendee($attendee['calendar'], $attendee['ROLE'], $attendee['PARTSTAT'], $attendee['RSVP']);
640
					} else {
641 3
						// the calendar is not accessible
642
						// try to get the non accessible calendar :
643
						
644 3
						if ($id_user = bab_getUserIdByEmailAndName($attendee['email'], $attendee['CN']))
645
						{
646
							// use the icalendars object of attendee to bypass the access rights tests
647
							$att_cals = bab_getICalendars($id_user);
648 3
							
649
							if( $id_calendar = $att_cals->getPersonalCalendarUid($id_user))
650
							{
651
								$reftype = $att_cals->getUserReferenceType($id_user);
652
								$usercal = $att_cals->getEventCalendar("$reftype/$id_calendar");
653
								
654 3
								if (isset($usercal))
655 3
								{
656 3
									$replacedPeriod->addAttendee($usercal, $attendee['ROLE'], $attendee['PARTSTAT'], $attendee['RSVP']);
0 ignored issues
show
Documentation introduced by
$usercal is of type object<bab_EventCalendar>, but the function expects a object<bab_PersonalCalendar>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
657
								}
658
							}
659 3
						}
660 3
						
661 1
						
662 1
						
663
					}
664
				}
665 3
666 3
				if ($alarm = $period->getAlarm()) {
667 3
					$replacedPeriod->setAlarm($alarm);
668
				}
669 3
			}
670
		}
671
		
672 3
		
673 2
		if (empty($originalPeriods)) {
674 2
		    throw new ErrorException('No periods to save, put request canceled');
675
		}
676
		
677
678
		$xml = 'BEGIN:VCALENDAR' . "\n"
679 3
		. $this->getProdId() . "\n"
680 3
		. 'VERSION:2.0' . "\n"
681
		. $this->getTimeZone();
682
683
684
		if (null !== $method)
685
		{
686
			$xml .= "METHOD:$method\n";
687 3
		}
688
689
690
		foreach ($originalPeriods as $p) {
691
			$xml .= caldav_CalendarPeriod::toIcal($p) . "\n";
692
		}
693
694
		$xml .= 'END:VCALENDAR';
695
696
697
		if ($newEvent) {
698
			$this->caldavClient->setMatch(false);
699
		} else {
700
			// Check ETAG with If-Match (setMatch method)
701
		}
702
		
703
		try {
704
			$this->caldavClient->DoPUTRequest($uid . '.ics', $xml);
705
		} catch (Exception $e) {
706
		    
707
		    bab_debug($e->getFile().' -> '.$e->getLine().'<br /><br />'.$e->getTraceAsString());
708
		    
709
		    // only ErrorException are captured as error messages in ovidentia
710
            throw new ErrorException($e->getMessage());
711
		}
712
713
		// caldav_SessionFile($uid . '.ics', $xml);
714
715
		return true;
716
	}
717
718
719
	/**
720
	 * Process coma separated values from multiples properties or one property
721
	 * 
722
	 * T6775 : probablement plusieurs EXDATE dans le meme evenement
723
	 * 
724
	 * @param	string | array	$properties
725
	 * @return array
726
	 */
727
	private function explodeRules($properties)
728
	{
729
		if (is_array($properties))
730 5
		{
731
			$values = array();
732 5
			foreach($properties as $property)
733 5
			{
734 5
				$values = array_merge($values, explode(',', $property));
735
			}
736 5
			
737
			return $values;
738
		}
739 5
		
740 4
		return explode(',', $properties);
741 4
	}
742 4
743 4
744 4
	/**
745 5
	 * Expands an icalendar-formatted data string $icalEventData to an array of <bab_CalendarPeriod>.
746 4
	 * The data string must correspond to a single caldav event (only one UID) that can however be
747 4
	 * made of several recurrences (hence several VEVENT).
748 4
	 *
749 4
	 * @param string						$icalEventData		The icalendar-formatted event data.
750 4
	 * @param bab_CalendarEventCollection	$collection			If specified, periods will be associated to this collection.
751 5
	 * @param bool							$expandRecurrence	True to have VEVENTs with RRULES expanded.
752
	 * 															If set to false, only one bab_CalendarPariod is created for a
753 5
	 * 															VEVENT with an RRULE, VEVENTs with a RECURRENCE-ID are still
754
	 * 															returned as additional bab_CalendarPeriods.
755
	 *
756 5
	 * @return bab_CalendarPeriod[]
757
	 */
758
	protected function expandPeriods($icalEventData, bab_CalendarEventCollection $collection = null, $expandRecurrence = true, $expandStart = null, $expandEnd = null)
759 5
	{
760
		$periods = array();
761 5
		$eventsData = array();
762
		preg_match_all('/BEGIN:VEVENT(.*)END:VEVENT/Us', $icalEventData, $eventsData);
763
764
		if ($expandRecurrence) {
765
			// If recurrent events should be expanded and no expand range has been specified, we
766
			// limit to +/- 5 years.
767 View Code Duplication
			if (!isset($expandStart)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
768 5
				require_once $GLOBALS['babInstallPath'] . 'utilit/dateTime.php';
769
				$expandStart = BAB_DateTime::now();
770
				$expandStart->add(-5, BAB_DATETIME_YEAR);
771
				$expandStart = $expandStart->getICal();
772
			}
773 View Code Duplication
			if (!isset($expandEnd)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
774
				require_once $GLOBALS['babInstallPath'] . 'utilit/dateTime.php';
775
				$expandEnd = BAB_DateTime::now();
776
				$expandEnd->add(5, BAB_DATETIME_YEAR);
777
				$expandEnd = $expandEnd->getICal();
778
			}
779
		}
780
781
		foreach ($eventsData[1] as $eventData) {
782
			
783
784
			$period = $this->CalendarPeriod();
785
786
			try {
787
				$period->fromIcal($eventData);
788
			}
789
			catch(Exception $e)
790
			{
791
				// bab_debug($e->getMessage(), DBG_ERROR, 'caldav');
792
				continue;
793
			}
794
795
			if ($expandRecurrence
796
				&& ($period->getProperty('RRULE') !== '' || $period->getProperty('RDATE') !== '')) {
797
798
				// If the period has a recurrence rule, we create as much periods as necessary.
799
800
				require_once dirname(__FILE__) . '/caldav/RRule.php';
801
802
				$recurrenceDates = array();
803
804
				// First we use the RDATE and RRULE parameters to determine the list
805
				// of dates.
806
807
				$icalStart = new LibCaldav_iCalDate($period->getProperty('DTSTART'));
808
				$icalEnd = new LibCaldav_iCalDate($period->getProperty('DTEND'));
809
				$icalDuration = $icalStart->DateDifference($icalEnd);
810
811 View Code Duplication
				if ($period->getProperty('RDATE') !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
812
					$rdates = $this->explodeRules($period->getProperty('RDATE'));
813
					foreach ($rdates as $rdate) {
814
						if ($rdate >= $expandStart && $rdate < $expandEnd) {
815
							$recurrenceDates[$rdate] = $rdate;
816
						}
817
					}
818
				}
819
820 View Code Duplication
				if ($period->getProperty('RRULE') !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
821
					$rrule = new RRule($icalStart, $period->getProperty('RRULE'));
822
823
					// We add an element to $recurrenceDates for each date defined by the recurrence rule.
824
					while (($dtStart = $rrule->GetNext()) && ($dtStart->_text < $expandEnd)) {
825
						if ($dtStart->_text >= $expandStart) {
826
							$recurrenceDates[$dtStart->_text] = $dtStart->_text;
827
						}
828
					}
829
				}
830
831
				// Now we use EXDATE and EXRULE parameters to determine a list
832
				// of date excluded from the recurrence rule.
833
834 View Code Duplication
				if ($period->getProperty('EXDATE') !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
835
					$exdates = $this->explodeRules($period->getProperty('EXDATE'));
836
					foreach ($exdates as $exdate) {
837
						if ($exdate >= $expandStart && $exdate < $expandEnd) {
838
							unset($recurrenceDates[$exdate]);
839
						}
840
					}
841
				}
842
843 View Code Duplication
				if ($period->getProperty('EXRULE') !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
844
					$exrule = new RRule($icalStart, $period->getProperty('EXRULE'));
845
846
					// We remove an element from $recurrenceDates for each date defined by the recurrence rule.
847
					while (($dtStart = $exrule->GetNext()) && ($dtStart->_text < $expandEnd)) {
848
						if ($dtStart->_text >= $expandStart) {
849
							unset($recurrenceDates[$dtStart->_text]);
850
						}
851
					}
852
				}
853 5
854 5
				// Finally we create a period for each date remaining in $recurrenceDates.
855 5
856 5
				foreach ($recurrenceDates as $startDate) {
857 5
					$dtStart = new LibCaldav_iCalDate($startDate);
858 5
					$dtEnd = new LibCaldav_iCalDate($dtStart);
859 5
					$dtEnd->addDuration($icalDuration);
860 5
					
861 5
					// en utilisant un clone de $period c'est probablement plus rapide
862 5
					// mais il semble que le lien avec la collection soit casse, cela declanche un probleme dans bab_CalAttendeeBackend::getRealAttendee()
863
					// $date_period = clone $period;
864
					$date_period = $this->CalendarPeriod();
865
					$date_period->fromIcal($eventData);
866
					
867
					$date_period->setDates(BAB_DateTime::fromICal($dtStart->_text), BAB_DateTime::fromICal($dtEnd->_text));
0 ignored issues
show
Bug introduced by
It seems like \BAB_DateTime::fromICal($dtStart->_text) can be null; however, setDates() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
Bug introduced by
It seems like \BAB_DateTime::fromICal($dtEnd->_text) can be null; however, setDates() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
868 5 View Code Duplication
					if (isset($collection)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
869
						$collection->addPeriod($date_period);
870 5
						$relations = $date_period->getRelations('PARENT');
871
						if (count($relations) === 0) {
872
							$date_period->addRelation('PARENT', $collection->getCalendar());
873 5
						}
874
					}
875 5
					$periods[$date_period->getProperty('DTSTART')] = $date_period;
876
				}
877
878
879
			} else {
880
881 View Code Duplication
				if (isset($collection)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
882
					$collection->addPeriod($period);
883
					$relations = $period->getRelations('PARENT');
884
					if (count($relations) === 0) {
885
						$period->addRelation('PARENT', $collection->getCalendar());
886
					}
887
				}
888 4
				if (!$expandRecurrence || ($period->getProperty('DTSTART') < $expandEnd && $period->getProperty('DTEND') > $expandStart) ) {
889
					$recurrenceId = $period->getProperty('RECURRENCE-ID');
890 4
					if ($recurrenceId !== '') {
891
						if (is_array($recurrenceId)) {
892 4
							$recurrenceId = array_pop($recurrenceId);
893 4
						}
894
						$periods[$recurrenceId] = $period;
895
					} else {
896
						$periods[$period->getProperty('DTSTART')] = $period;
897 4
					}
898
				}
899
900 4
			}
901 4
		}
902
903
		return $periods;
904
	}
905
906 4
907
	/**
908
	 * Returns the period corresponding to the specified identifier (and optionally a particular occurence at the specified start date).
909 4
	 *
910
	 * @param	bab_PeriodCollection	$periodCollection		where to search for event
911 4
	 * @param 	string 					$identifier				The UID property of event
912
	 * @param 	string 					$start					The icalendar-formatted start date (useful when editing a particular iteration of a recurrent event).
913
	 *
914
	 * @return caldav_CalendarPeriod	Or null if no match
915
	 */
916 4
	public function getPeriod(bab_PeriodCollection $periodCollection, $identifier, $start = null)
917 4
	{
918
		$calendar = $periodCollection->getCalendar();
919
920
		if (!$calendar)
921
		{
922 4
			throw new Exception(sprintf('try to search for event in collection %s but the collection is not in a calendar', get_class($periodCollection)));
923 4
		}
924
925 1
		$this->init($calendar);
0 ignored issues
show
Compatibility introduced by
$calendar of type object<bab_EventCalendar> is not a sub-type of object<caldav_EventCalendar>. It seems like you assume a child class of the class bab_EventCalendar to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
926
927 1
		try {
928 1
			$events = $this->caldavClient->GetEntryByUid($identifier);
929
		} catch (Exception $e) {
930
			bab_debug($e->getMessage());
931
			$events = array();
932
		}
933 1
934
		$periods = array();
935
936
		//		var_dump($events);
937
		foreach ($events as $icalEvent) {
938
		    
939
		    if (!isset($icalEvent['data'])) {
940
		        continue;
941
		    }
942
943
//			echo $icalEvent['data'] . "\n\n\n";
944
			$periods = $this->expandPeriods($icalEvent['data'], $periodCollection, true);
0 ignored issues
show
Documentation introduced by
$periodCollection is of type object<bab_PeriodCollection>, but the function expects a null|object<bab_CalendarEventCollection>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
945
			if (isset($start) && isset($periods[$start])) {
946
				return $periods[$start];
947
			}
948
949
950
			if ($identifier.'.ics' === $icalEvent['href']) {
951
				return array_pop($periods);
952
			}
953
		}
954
955
		if (count($periods) > 0)
956
		{
957
			return array_pop($periods);
958
		}
959
960
961
		return null;
962
	}
963
964
965
	/**
966
	 * Returns the period corresponding to the specified identifier (and optionally a particular occurence at the specified start date).
967
	 *
968
	 * @param bab_PeriodCollection	$periodCollection		where to search for event
969
	 * @param string 				$identifier				The UID property of event
970
	 * @param bool					$expandRecurrence		True to have VEVENTs with RRULES expanded.
971
	 * 														If set to false, only one bab_CalendarPariod is created for a
972
	 * 														VEVENT with an RRULE, VEVENTs with a RECURRENCE-ID are still
973
	 * 														returned as additional bab_CalendarPeriods.
974
	 * @param BAB_DateTime			$expandStart			Lower limit for date expansion, null for no lower limit.
975
	 * @param BAB_DateTime			$expandEnd				Upper limit for date expansion, null for no upper limit.
976 1
	 *
977
	 * @return array<caldav_CalendarPeriod>	Or null if no match
978 1
	 */
979 1
	public function getAllPeriods(bab_PeriodCollection $periodCollection, $identifier, $expandRecurrence = true, BAB_DateTime $expandStart = null, BAB_DateTime $expandEnd = null)
980 1
	{
981 1
		$calendar = $periodCollection->getCalendar();
982 1
983 1
		$this->init($calendar);
0 ignored issues
show
Compatibility introduced by
$calendar of type object<bab_EventCalendar> is not a sub-type of object<caldav_EventCalendar>. It seems like you assume a child class of the class bab_EventCalendar to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
984
		$events = $this->caldavClient->GetEntryByUid($identifier);
985
986
		if (isset($expandStart)) {
987
			$expandStart = $expandStart->getICal();
988
		}
989
		if (isset($expandEnd)) {
990
			$expandEnd = $expandEnd->getICal();
991
		}
992
		$periods = array();
0 ignored issues
show
Unused Code introduced by
$periods is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
993 1
994
		foreach ($events as $icalEvent) {
995 1
996 1
			$periods = $this->expandPeriods($icalEvent['data'], $periodCollection, $expandRecurrence, $expandStart, $expandEnd);
0 ignored issues
show
Documentation introduced by
$periodCollection is of type object<bab_PeriodCollection>, but the function expects a null|object<bab_CalendarEventCollection>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
997
			return $periods;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $periods; (bab_CalendarPeriod[]) is incompatible with the return type of the parent method Func_CalendarBackend::getAllPeriods of type Iterator.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
998 1
		}
999
		return null;
1000 1
	}
1001 1
1002 1
1003 1
1004
	private static function flattenCriteria(bab_PeriodCriteria $criteria, &$criteriaArray)
1005 1
	{
1006
		$criteriaArray[] = $criteria;
1007 1
		$subCriteria = $criteria->getCriterions();
1008 1
		foreach($subCriteria as $subCriterion) {
1009 1
			self::flattenCriteria($subCriterion, $criteriaArray);
1010 1
		}
1011 1
	}
1012 1
1013 1
1014 1
1015 1
1016 1
	/**
1017 1
	 * @param bab_PeriodCriteria $criteria
1018 1
	 *
1019 1
	 * @return iterator <caldav_CalendarPeriod>
1020
	 */
1021 1
	public function selectPeriods(bab_PeriodCriteria $criteria = null)
1022
	{
1023
		$criteriaArray = array();
1024
		self::flattenCriteria($criteria, $criteriaArray);
0 ignored issues
show
Bug introduced by
It seems like $criteria defined by parameter $criteria on line 1021 can be null; however, Func_CalendarBackend_Caldav::flattenCriteria() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
1025
1026
		$filteredProperties = array();
1027
1028
		$begin = null;
1029
		$end = null;
1030
		$uid_values = array();
1031
		$uid_criterion = null;
1032
1033
		foreach ($criteriaArray as $criterion) {
1034
			//			echo get_class($criterion) . "\n";
1035
			if ($criterion instanceof bab_PeriodCriteriaCalendar) {
1036
				$selectedCalendars = array();
1037
				foreach ($criterion->getCalendar() as $calendarId => $calendar) {
1038
					if (($calendar instanceof caldav_PersonalCalendar) || ($calendar instanceof caldav_ResourceCalendar)) {
1039
						$selectedCalendars[$calendarId] = $calendar;
1040
					}
1041
				}
1042
			} else if ($criterion instanceof bab_PeriodCritieraBeginDateLessThanOrEqual) {
1043
				$end = $criterion->getDate();
1044
				$end = isset($end) ? $end->getICal(true) : null;
1045 1
			} else if ($criterion instanceof bab_PeriodCritieraEndDateGreaterThanOrEqual) {
1046
				$begin = $criterion->getDate();
1047
				$begin = isset($begin) ? $begin->getICal(true) : null;
1048 1
1049 1
			} else if ($criterion instanceof bab_PeriodCritieraUid) {
1050
1051
				$uid_criterion = clone $criterion;
1052
				$uid_values = $criterion->getUidValues();
1053
1054
				foreach($uid_values as $uid)
1055
				{
1056 1
					$filteredProperties[] = array(
1057
						'name' => 'UID',
1058 1
						'value' => $uid,
1059
						'contain' => false
1060
					);
1061 1
				}
1062
1063 1
			} else if ($criterion instanceof bab_PeriodCritieraProperty) {
1064 1
1065
				foreach ($criterion->getValue() as $value) {
1066
					$filteredProperties[] = array(
1067
						'name' => $criterion->getProperty(),
1068
						'value' => $value,
1069
						'contain' => $criterion->getContain()
1070
					);
1071
				}
1072
			}
1073
		}
1074 1
1075 1
1076
		if (empty($selectedCalendars))
1077
		{
1078 1
			require_once $GLOBALS['babInstallPath'].'utilit/devtools.php';
1079
			bab_debug('Warning : query in LibCaldav without compatible calendars', DBG_WARNING, 'Caldav');
1080
			return array();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type of the parent method Func_CalendarBackend::selectPeriods of type Iterator.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1081
		}
1082
1083
1084
		$periods = array();
1085
1086
		foreach ($selectedCalendars as $selectedCalendar) {
1087
1088
			try {
1089
				$this->init($selectedCalendar);
1090
				
1091
				if (null === $begin && null === $end && $uid_values)
0 ignored issues
show
Bug Best Practice introduced by
The expression $uid_values of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1092
				{
1093
					// getUidValuesByCalendar use the parent_calendar column in the inbox
1094
					$uid_list = $uid_criterion->getUidValuesByCalendar($selectedCalendar);
1095
					if (!$uid_list)
1096
					{
1097
						continue;
1098 1
					}
1099
					
1100
					$events = $this->caldavClient->GetEntriesByUid($uid_list);
1101 1
				} else {
1102
					$this->caldavClient->SetDepth(1);
1103 1
					$events = $this->caldavClient->GetEvents($begin, $end);
1104 1
				}
1105
				
1106
			} catch (caldav_HttpException $e) // 403, 404
0 ignored issues
show
Bug introduced by
The class caldav_HttpException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1107
			{
1108
				global $babBody;
1109 1
				$babBody->addError($e->getMessage()."test");
1110 1
				return array();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type of the parent method Func_CalendarBackend::selectPeriods of type Iterator.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1111 1
				
1112 1
			}
1113 1
			 catch (caldav_AccessException $e) // 401
0 ignored issues
show
Bug introduced by
The class caldav_AccessException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
1114
			{
1115
				global $babBody;
1116 1
				$babBody->addError($e->getMessage()."test2");
1117
				return array();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type of the parent method Func_CalendarBackend::selectPeriods of type Iterator.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1118 1
				
1119
			} catch (Exception $e) {
1120
				bab_debug($e->getMessage());
1121 1
				continue; 	// exemple: the inbox of a ovidentia user contain a reference to a caldav event in a broken
1122
							// user configuration, the continue allow to process other caldav calendars in the same inbox
1123
			}
1124
1125
1126
			$defaultCollection = $this->CalendarEventCollection($selectedCalendar);
1127
			//		$defaultCollection->setCalendar($calendar[0]);
1128
1129
			foreach ($events as $event) {
1130
1131
				if (!isset($event['data']))
1132
				{
1133
					continue;
1134
				}
1135
1136
1137
				$ps = $this->expandPeriods($event['data'], $defaultCollection, true, $begin, $end);
1138
				foreach ($ps as $p) {
1139
					$periods[] = $p;
1140
					$this->caldavClient->setHrefForUid($p->getProperty('UID'), $event['hrefpath']);
1141
				}
1142
1143
				
1144
			}
1145
1146
		}
1147
1148
1149
		if (!empty($filteredProperties)) {
1150
1151
			$filteredPeriods = array();
1152
			foreach ($periods as $period) {
1153 1
				foreach ($filteredProperties as $property) {
1154
					if (false === $property['contain'] && (((string) $property['value']) === (string) $period->getProperty($property['name'])))
1155
					{
1156
						$filteredPeriods[] = $period;
1157
						break;
1158
1159
					} else if (stripos($period->getProperty($property['name']), $property['value']) !== false) {
1160
						$filteredPeriods[] = $period;
1161
						break;
1162
					}
1163
				}
1164
			}
1165 1
1166
1167
			$periods = $filteredPeriods;
1168 1
		}
1169 1
1170
1171 1
		/*
1172 1
		foreach ($periods as $period) {
1173 1
			bab_debug($period->getProperties(), 2, 'caldav');
1174 1
		}
1175
1176
1177
		require_once $GLOBALS['babInstallPath'].'utilit/devtools.php';
1178
		bab_debug_print_backtrace();
1179
		*/
1180
1181
		return $periods;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $periods; (array) is incompatible with the return type of the parent method Func_CalendarBackend::selectPeriods of type Iterator.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1182
	}
1183
1184
1185
1186
1187
	/**
1188 1
	 * Deletes the period corresponding to the specified identifier.
1189
	 *
1190
	 * @param	bab_CalendarPeriod	$period		The period to delete
1191
	 *
1192
	 */
1193
	public function deletePeriod(bab_CalendarPeriod $period)
1194
	{
1195
1196
		$periodCollection = $period->getCollection();
1197
		$calendar = $periodCollection->getCalendar();
1198
1199
		if ($calendar instanceof caldav_PersonalCalendar)
1200
		{
1201
			$this->deletePeriodForUser($calendar, $period);
1202 1
		}
1203
		else
1204 1
		{
1205 1
			// the main calendar is not caldav
1206 1
			// try to get a caldav calendar from the attendees or throw an error
1207
			foreach($period->getAttendees() as $attendee)
1208 1
			{
1209
				if ($attendee['calendar'] instanceof caldav_PersonalCalendar)
1210 1
				{
1211
					
1212
					$this->deletePeriodForUser($attendee['calendar'], $period);
1213
				}
1214 1
			}
1215 1
		}
1216
	}
1217
1218
1219 1
1220
1221
1222
1223
1224
	/**
1225
	 *
1226
	 * @param caldav_PersonalCalendar $calendar
1227
	 * @param bab_CalendarPeriod $period
1228
	 * @return unknown_type
1229
	 */
1230
	private function deletePeriodForUser(caldav_PersonalCalendar $calendar, bab_CalendarPeriod $period)
1231
	{
1232
		$uid = $period->getProperty('UID');
1233
		$periodCollection = $period->getCollection();
1234
		$this->init($calendar);
1235
1236
		$recurrenceId = $period->getProperty('RECURRENCE-ID');
1237
1238
		if ($recurrenceId === '') {
1239
1240
			// No RECURRENCE-ID specified so we delete the whole event.
1241
			try {
1242
				$this->caldavClient->DoDELETERequest($uid . '.ics');
1243
			} catch (Exception $e) {
1244
				bab_debug($e->getMessage());
1245
			}
1246
1247
			return true;
1248
1249
		}
1250
1251
1252
1253
1254
		require_once $GLOBALS['babInstallPath'] . 'utilit/dateTime.php';
1255
1256
		// Here we know we delete recurrence period(s) in the event.
1257
1258
		if (is_array($recurrenceId)) {
1259
			list($params , $recurrenceId) = each($recurrenceId);
1260
			$params = explode(';',$params);
1261
			array_shift($params);
1262
			$range = null;
1263
1264
			foreach($params as $param)
1265
			{
1266
				$arr = explode('=', $param);
1267
				if (2 === count($arr))
1268
				{
1269
					list($name, $value) = $arr;
1270
					$name = trim($name);
1271
					$value = trim($value);
1272
1273
					switch($name)
1274
					{
1275
						case 'RANGE':
1276
							$range = $value;
1277
							break;
1278
					}
1279
				}
1280
			}
1281
		}
1282
1283
		$originalPeriods = array();
1284
		$icalEvents = $this->caldavClient->GetEntryByUid($uid);
1285
1286
		foreach ($icalEvents as $icalEvent) {
1287
			$originalPeriods = $this->expandPeriods($icalEvent['data'], $periodCollection, false);
1288
		}
1289
1290
		if ((!isset($originalPeriods[0])) || ($originalPeriods[0]->getProperty('RRULE') === '')) {
1291
			$this->init($calendar);
1292
1293
			// no recurence rule, delete full event
1294
1295
			try {
1296
				$this->caldavClient->DoDELETERequest($uid . '.ics');
1297
			} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1298
1299
			}
1300
			return true;
1301
		}
1302
1303
1304
		foreach($originalPeriods as $dtstart => $period)
1305
		{
1306
			if (0 !== $dtstart && ($dtstart === $recurrenceId || ($dtstart < $recurrenceId && 'THISANDPRIOR' === $range) || ($dtstart > $recurrenceId && 'THISANDFUTURE' === $range)) )
0 ignored issues
show
Bug introduced by
The variable $range does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1307
			{
1308
				// A period with this recurrence id already exist in the list of modified periods, we remove the period.
1309
				unset($originalPeriods[$dtstart]);
1310
			}
1311
		}
1312
1313
1314
		// search the list of periods to add as exception
1315
1316
		$rrulePeriods = $this->expandPeriods($icalEvent['data'], $periodCollection, true);
0 ignored issues
show
Bug introduced by
The variable $icalEvent seems to be defined by a foreach iteration on line 1286. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
1317
		$deleteRuleExceptions = array();
1318
		foreach($rrulePeriods as $dtstart => $period)
1319
		{
1320
			if ($dtstart === $recurrenceId || ($dtstart < $recurrenceId && 'THISANDPRIOR' === $range) )
1321
			{
1322
				$deleteRuleExceptions[$dtstart] = $dtstart;
1323
			}
1324
		}
1325
1326
1327
		if (isset($originalPeriods[0]))
1328
		{
1329
			$originalPeriod = $originalPeriods[0];
1330
1331
1332
			if ($deleteRuleExceptions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $deleteRuleExceptions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1333
				// add exceptions dates
1334
1335
				if (($exdate = $originalPeriod->getProperty('EXDATE')) === '') {
1336
					$exdate = implode(',', $deleteRuleExceptions);
1337
				} else {
1338
					$exdate = explode(',', $exdate);
1339
					$exdate = array_merge($exdate, array_values($deleteRuleExceptions));
1340
					$exdate = implode(',', $exdate);
1341
				}
1342
				$originalPeriod->setProperty('EXDATE', $exdate);
1343
			}
1344
1345
1346
			if ('THISANDFUTURE' === $range) {
1347
				// update the RRULE with an UNTIL value (UTC is mandatory)
1348
1349
				if ($rrule = $originalPeriod->getProperty('RRULE'))
1350
				{
1351
					$until = BAB_DateTime::fromICal($recurrenceId);
1352
					$until = $until->getICal(true);
1353
					$rrule = preg_replace('/UNTIL=\s*[0-9TZ]+/', '', $rrule);
1354
					$rrule = trim($rrule, ' ;');
1355
					$rrule .= ';UNTIL='.$until;
1356
1357
					bab_debug($rrule);
1358
					$originalPeriod->setProperty('RRULE', $rrule);
1359
				}
1360
			}
1361
1362
			$originalPeriod->setProperty('LAST-MODIFIED', BAB_DateTime::now()->getIcal(true));
1363
			$originalPeriod->setProperty('DTSTAMP', BAB_DateTime::now()->getIcal(true));
1364
		}
1365
1366
1367
		if (count($originalPeriods) == 0) {
1368
			return;
1369
		}
1370
1371
		$xml = 'BEGIN:VCALENDAR' . "\n"
1372
		. $this->getProdId() . "\n"
1373
		. 'VERSION:2.0' . "\n"
1374
		. $this->getTimeZone();
1375
1376
		foreach ($originalPeriods as $p) {
1377
			$xml .= caldav_CalendarPeriod::toIcal($p) . "\n";
1378
		}
1379
1380
		$xml .= 'END:VCALENDAR';
1381
1382
		$this->init($calendar);
1383
1384
1385
		// TODO : Check ETAG with If-Match (setMatch method)
1386
1387
		try {
1388
			$this->caldavClient->DoPUTRequest($uid . '.ics', $xml);
1389
		} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1390
		}
1391
1392
		return true;
1393
	}
1394
1395
1396
1397
	/**
1398
	 * Update an attendee PARTSTAT value of a calendar event
1399
	 * a user can modifiy his participation status without modifing the full event, before triggering this method, the access right will be checked with the
1400
	 * canUpdateAttendeePARTSTAT method of the calendar
1401
	 *
1402
	 * @see bab_EventCalendar::canUpdateAttendeePARTSTAT()
1403
	 *
1404
	 * @param bab_CalendarPeriod 	$period		the event
1405
	 * @param bab_PersonalCalendar 	$calendar	the personal calendar used as an attendee
1406
	 * @param string 				$partstat	ACCEPTED | DECLINED
1407
	 * @param string				$comment	comment given when changing PARTSTAT (optional)
1408
	 * @return bool
1409
	 */
1410
	public function updateAttendeePartstat(bab_CalendarPeriod $period, bab_PersonalCalendar $calendar, $partstat, $comment = '')
1411
	{
1412
		$period->addAttendee($calendar, 'REQ-PARTICIPANT', $partstat);
1413
1414
		$return = $this->savePeriod($period, 'REPLY');
1415
		$period->commitEvent();
1416
1417
		return $return;
1418
	}
1419
1420
1421
1422
1423
	/**
1424
	 * @param	int	$accessType		BAB_CAL_ACCESS_VIEW | BAB_CAL_ACCESS_UPDATE | BAB_CAL_ACCESS_FULL | BAB_CAL_ACCESS_SHARED_UPDATE
1425
	 *
1426
	 * return string		The dav xml privilege corresponding to the ovidentia access type.
1427
	 */
1428
	public function getDavPrivilege($accessType)
1429
	{
1430
		switch ($accessType) {
1431
1432
			// TODO : NEED to update right here.
1433
			case BAB_CAL_ACCESS_VIEW:
1434
				return '<D:privilege><D:read/></D:privilege>';
1435
1436
			case BAB_CAL_ACCESS_UPDATE:
1437
				return '<D:privilege><D:read/></D:privilege><D:privilege><D:write/></D:privilege>';
1438
1439
			case BAB_CAL_ACCESS_FULL:
1440
				return '<D:privilege><D:read/></D:privilege><D:privilege><D:write/></D:privilege>';
1441
1442
			case BAB_CAL_ACCESS_SHARED_UPDATE:
1443
				return '<D:privilege><D:read/></D:privilege><D:privilege><D:write/></D:privilege>';
1444
		}
1445
		return '';
1446
	}
1447
1448
1449
1450
1451
	/**
1452
	 * @param $object
1453
	 * @param array			$privileges
0 ignored issues
show
Bug introduced by
There is no parameter named $privileges. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1454
	 * @param array<int>	$users			Ovidentia user ids
1455
	 * @param string		$changeType		'grant' or 'deny'
1456
	 */
1457
	protected function changeAccess($object, $accessTypes, $users, $changeType)
1458
	{
1459
		if (!is_array($users)) {
1460
			$users = array($users);
1461
		}
1462
		$xmlPrincipals = '<D:principal>';
1463
		foreach ($users as $user) {
1464
			$xmlPrincipals .= '<D:href>' . $this->getUserHref($user) . '</D:href>';
1465
		}
1466
		$xmlPrincipals .= '</D:principal>';
1467
1468
		if (!is_array($accessTypes)) {
1469
			$accessTypes = array($accessTypes);
1470
		}
1471
		$xmlPrivileges = '<D:' . $changeType . '>';
1472
		foreach ($accessTypes as $accessType) {
1473
			$xmlPrivileges .= $this->getDavPrivilege($accessType);
1474
		}
1475
		$xmlPrivileges .= '</D:' . $changeType . '>';
1476
1477
		$xml =
1478
			'<?xml version="1.0" encoding="utf-8" ?>
1479
   			<D:acl xmlns:D="DAV:">
1480
			 <D:ace>' .
1481
		$xmlPrincipals .
1482
		$xmlPrivileges .
1483
	  	   '</D:ace>
1484
	 	  </D:acl>';
1485
1486
		if (!is_string($object)) {
1487
			$objectUrl = $object->getUrl();
1488
		} else {
1489
			$objectUrl = $object;
1490
		}
1491
1492
		$userId = $GLOBALS['BAB_SESS_USERID'];
1493
		$caldavClient = new CalDAVClient($this->getServerUrl(), $this->getUserIdentifier($userId),$this->getUserPassword($userId), null);
0 ignored issues
show
Bug introduced by
The call to getServerUrl() misses a required argument $userId.

This check looks for function calls that miss required arguments.

Loading history...
1494
		try {
1495
			return $caldavClient->DoXMLRequest('ACL', $xml, $objectUrl);
1496
		} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1497
		}
1498
	}
1499
1500
1501
1502
1503
	/**
1504
	 */
1505
	public function grantAccess($object, $accessTypes, $users)
1506
	{
1507
		$this->changeAccess($object, $accessTypes, $users, 'grant');
1508
	}
1509
1510
1511
1512
1513
	/**
1514
	 */
1515
	public function revokeAccess($object, $accessTypes, $users)
1516
	{
1517
		$this->changeAccess($object, $accessTypes, $users, 'deny');
1518
	}
1519
1520
1521
1522
	/**
1523
	 * Returns all access privileges granted to the specified user on the specified object.
1524
	 *
1525
	 * @return array
1526
	 */
1527
	public function getAccesses($object, $userId)
0 ignored issues
show
Unused Code introduced by
The parameter $object 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...
Unused Code introduced by
The parameter $userId 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...
1528
	{
1529
		return;
1530
		
1531
		
1532
		$xml = '<?xml version="1.0" encoding="utf-8" ?>
0 ignored issues
show
Unused Code introduced by
$xml = '<?xml version="1...op> </D:propfind>'; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1533
				<D:propfind xmlns:D="DAV:">
1534
				<D:prop>
1535
				<D:current-user-privilege-set/>
1536
				</D:prop>
1537
				</D:propfind>';
1538
		if (!is_string($object)) {
1539
			$objectUrl = $object->getUrl();
1540
		} else {
1541
			$objectUrl = $object;
1542
		}
1543
		try {
1544
			$this->caldavClient->SetDepth(0);
1545
			$this->caldavClient->DoXMLRequest('PROPFIND', $xml, $objectUrl);
1546
		} catch(Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1547
1548
		}
1549
1550
1551
		$dom = new DOMDocument();
1552
		$dom->loadXML($this->caldavClient->xmlResponse);
1553
1554
1555
		//		HTTP/1.1 207 Multi-Status
1556
		//		Date: Thu, 09 Sep 2010 09:58:33 GMT
1557
		//		Server: Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny8 with Suhosin-Patch
1558
		//		X-Powered-By: PHP/5.2.6-1+lenny8
1559
		//		DAV: 1, 2, access-control, calendar-access, calendar-schedule, extended-mkcol, calendar-proxy, bind, calendar-auto-schedule
1560
		//		ETag: "b4449ea2bf72f5e850ec928688e197b7"
1561
		//		X-DAViCal-Version: DAViCal/0.9.9; DB/1.2.8
1562
		//		Content-Length: 1541
1563
		//		Vary: Accept-Encoding
1564
		//		Connection: close
1565
		//		Content-Type: text/xml; charset="utf-8"
1566
		//
1567
		//		<?xml version="1.0" encoding="utf-8" ? >
1568
		//		<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
1569
		//		 <response>
1570
		//		  <href>/davical/caldav.php/laucho/home/</href>
1571
		//		  <propstat>
1572
		//		   <prop>
1573
		//		    <current-user-privilege-set>
1574
		//		     <privilege>
1575
		//		      <all/>
1576
		//		     </privilege>
1577
		//		     <privilege>
1578
		//		      <read/>
1579
		//		     </privilege>
1580
		//		     <privilege>
1581
		//		      <unlock/>
1582
		//		     </privilege>
1583
		//		     <privilege>
1584
		//		      <read-acl/>
1585
		//		     </privilege>
1586
		//		     <privilege>
1587
		//		      <read-current-user-privilege-set/>
1588
		//		     </privilege>
1589
		//		     <privilege>
1590
		//		      <write-acl/>
1591
		//		     </privilege>
1592
		//		     <privilege>
1593
		//		      <C:read-free-busy/>
1594
		//		     </privilege>
1595
		//		     <privilege>
1596
		//		      <write/>
1597
		//		     </privilege>
1598
		//		     <privilege>
1599
		//		      <write-properties/>
1600
		//		     </privilege>
1601
		//		     <privilege>
1602
		//		      <write-content/>
1603
		//		     </privilege>
1604
		//		     <privilege>
1605
		//		      <bind/>
1606
		//		     </privilege>
1607
		//		     <privilege>
1608
		//		      <unbind/>
1609
		//		     </privilege>
1610
		//		     <privilege>
1611
		//		      <C:schedule-deliver/>
1612
		//		     </privilege>
1613
		//		     <privilege>
1614
		//		      <C:schedule-deliver-invite/>
1615
		//		     </privilege>
1616
		//		     <privilege>
1617
		//		      <C:schedule-deliver-reply/>
1618
		//		     </privilege>
1619
		//		     <privilege>
1620
		//		      <C:schedule-query-freebusy/>
1621
		//		     </privilege>
1622
		//		     <privilege>
1623
		//		      <C:schedule-send/>
1624
		//		     </privilege>
1625
		//		     <privilege>
1626
		//		      <C:schedule-send-invite/>
1627
		//		     </privilege>
1628
		//		     <privilege>
1629
		//		      <C:schedule-send-reply/>
1630
		//		     </privilege>
1631
		//		     <privilege>
1632
		//		      <C:schedule-send-freebusy/>
1633
		//		     </privilege>
1634
		//		    </current-user-privilege-set>
1635
		//		   </prop>
1636
		//		   <status>HTTP/1.1 200 OK</status>
1637
		//		  </propstat>
1638
		//		 </response>
1639
		//		</multistatus>
1640
1641
		$xpath = new DOMXPath($dom);
1642
1643
		$xpath->registerNamespace('D', 'DAV:');
1644
1645
		$entries = $xpath->query('//D:multistatus/D:response/D:propstat/D:prop/D:current-user-privilege-set/D:privilege/*');
1646
1647
1648
		$accesses = array();
1649
		//BAB_CAL_ACCESS_VIEW | BAB_CAL_ACCESS_UPDATE | BAB_CAL_ACCESS_FULL | BAB_CAL_ACCESS_SHARED_UPDATE
1650
		foreach ($entries as $entry) {
1651
1652
    		switch ($entry->tagName) {
1653
    			case 'all':
1654
    				$accesses[BAB_CAL_ACCESS_FULL] = BAB_CAL_ACCESS_FULL;
1655
    				break;
1656
    			case 'write':
1657
    				$accesses[BAB_CAL_ACCESS_UPDATE] = BAB_CAL_ACCESS_UPDATE;
1658
    				break;
1659
    			case 'read':
1660 1
    				$accesses[BAB_CAL_ACCESS_VIEW] = BAB_CAL_ACCESS_VIEW;
1661
    				break;
1662 1
    		}
1663 1
		}
1664 1
1665 1
		return $accesses;
1666
	}
1667
1668
	/**
1669
	 * The default caldav server url if no other is explicitely specified.
1670
	 * @deprecated
1671
	 * @return string
1672
	 */
1673
	public function getDefaultServerUrl()
1674
	{
1675
		return '';
1676
	}
1677
1678
1679
1680 8
1681
	/**
1682 8
	 *
1683 8
	 * @param int	$userId
1684 8
	 * @param int	$serverId
1685 8
	 *
1686
	 * @return Func_CalendarBackend_Caldav
1687
	 */
1688
	public function setServerId($userId, $serverId)
1689
	{
1690
		$registry = bab_getRegistryInstance();
1691
		$registry->changeDirectory('/LibCaldav/Users/' . $userId);
1692
		$registry->setKeyValue('server', $serverId);
1693
	}
1694
	
1695
	
1696
	
1697
	
1698
1699
1700
1701
1702
	/**
1703
	 * The default url for any user's personal calendar
1704
	 * %u will be replaced by ovidentia nickname
1705
	 *
1706
	 * @return string
1707
	 */
1708
	public function getDefaultUserCalendarUrl()
1709
	{
1710
		$registry = bab_getRegistryInstance();
1711
		$registry->changeDirectory('/LibCaldav');
1712
		$path = $registry->getValue('defaultUserCalendarUrl', '');
1713
		return $path;
1714
	}
1715
1716
1717
1718
1719
	/**
1720
	 *
1721
	 *
1722
	 * @param string	$path
1723
	 *
1724
	 * @return Func_CalendarBackend_Caldav
1725
	 */
1726
	public function setDefaultUserCalendarUrl($path)
1727
	{
1728
		$registry = bab_getRegistryInstance();
1729
		$registry->changeDirectory('/LibCaldav');
1730
		$registry->setKeyValue('defaultUserCalendarUrl', $path);
1731
	}
1732
1733
1734
1735
1736
	/**
1737
	 * The caldav admin identifier
1738
	 *
1739
	 * @return string
1740
	 */
1741
	public function getAdminIdentifier()
1742
	{
1743
		$registry = bab_getRegistryInstance();
1744
		$registry->changeDirectory('/LibCaldav');
1745
		$identifier = $registry->getValue('adminIdentifier', '');
1746
		return $identifier;
1747
	}
1748
1749
1750
1751
1752
	/**
1753
	 *
1754
	 *
1755
	 * @param string	$identifier
1756
	 *
1757
	 * @return Func_CalendarBackend_Caldav
1758
	 */
1759
	public function setAdminIdentifier($identifier)
1760
	{
1761
		$registry = bab_getRegistryInstance();
1762
		$registry->changeDirectory('/LibCaldav');
1763
		$registry->setKeyValue('adminIdentifier', $identifier);
1764
	}
1765
1766
1767
1768
1769
	/**
1770
	 * The caldav admin password
1771
	 *
1772
	 * @return string
1773
	 */
1774
	public function getAdminPassword()
1775
	{
1776
		$registry = bab_getRegistryInstance();
1777
		$registry->changeDirectory('/LibCaldav');
1778
		$password = $registry->getValue('adminPassword', '');
1779
		return $password;
1780
	}
1781
1782
1783
1784
1785
	/**
1786
	 *
1787
	 *
1788
	 * @param string	$password
1789 1
	 *
1790
	 * @return Func_CalendarBackend_Caldav
1791 1
	 */
1792 1
	public function setAdminPassword($password)
1793 1
	{
1794
		$registry = bab_getRegistryInstance();
1795
		$registry->changeDirectory('/LibCaldav');
1796
		$registry->setKeyValue('adminPassword', $password);
1797
	}
1798
	
1799
	
1800
	
1801 8
	/**
1802
	 * Set if backend is used as a storage backend (allow user switching)
1803 8
	 *
1804
	 * @param bool		$status
1805
	 *
1806
	 * @return Func_CalendarBackend_Caldav
1807
	 */
1808
	public function setStorageBackend($status)
1809
	{
1810
		$registry = bab_getRegistryInstance();
1811 8
		$registry->changeDirectory('/LibCaldav');
1812
		$registry->setKeyValue('StorageBackend', (bool) $status);
1813 8
	}
1814 8
1815 8
	
1816 8
	
1817 8
	public function getStorageBackend()
1818
	{
1819
		$registry = bab_getRegistryInstance();
1820
		$registry->changeDirectory('/LibCaldav');
1821
		return $registry->getValue('StorageBackend', true);
1822 8
	}
1823
	
1824
	
1825
	
1826
	public function setVerifyPeer($status)
1827 8
	{
1828
	    $registry = bab_getRegistryInstance();
1829 8
	    $registry->changeDirectory('/LibCaldav');
1830 8
	    $registry->setKeyValue('verify_peer', (bool) $status);
1831 8
	}
1832
	
1833 8
	
1834
	
1835 8
	public function getVerifyPeer()
1836 8
	{
1837
	    $registry = bab_getRegistryInstance();
1838
	    $registry->changeDirectory('/LibCaldav');
1839
	    return $registry->getValue('verify_peer', true);
1840 8
	}
1841
	
1842
	/**
1843
	 * test if personnal calendar use a per user configuration
1844 8
	 * @return bool
1845
	 */
1846
	public function configByUser()
1847
	{
1848
		return ('' === $this->getDefaultUserCalendarUrl());
1849
	}
1850
	
1851
	
1852
	/**
1853
	 * Get username and password to use for personnal calendar
1854
	 * @return array
1855
	 */
1856
	public function getPersonalCalendarCredentials($userId)
1857
	{
1858
		if ($this->configByUser())
1859
		{
1860
			$nickname = $this->getUserIdentifier($userId);
1861
			$password = $this->getUserPassword($userId);
1862
		} else {
1863 8
			$nickname = $this->getAdminIdentifier();
1864
			$password = $this->getAdminPassword();
1865 8
		}
1866 8
		
1867 8
		return array($nickname, $password);
1868 8
	}
1869
	
1870
	
1871 8
	
1872
	public function getPersonnalCalendarUrl($userId)
1873
	{
1874
		if ($this->configByUser())
1875
		{
1876
1877
				$relativePath = $this->getUserCalendarPath($userId);
1878
				
1879
				$url = $this->getServerUrl($userId) . $relativePath;
1880
				if (empty($url))
1881
				{
1882
					throw new Exception(sprintf('Empty calendar url for user %s', bab_getUserName($userId)));
1883
				}
1884
				
1885
				if (substr($url, -1, 1) !== '/') {
1886
					$url .= '/';
1887 1
				}
1888
				return $url;
1889 1
			
1890 1
		} else {
1891 1
			
1892 1
			$calendarPathTemplate = $this->getDefaultUserCalendarUrl();
1893
			return $this->processCalendarPathTemplate($calendarPathTemplate, bab_getUserNickname($userId), $userId);
1894
		}
1895
	}
1896
1897
1898
1899
	/**
1900
	 * Returns the stored caldav identifier for ovidentia user $userId.
1901
	 *
1902
	 * @param int $userId The ovidentia user id.
1903
	 *
1904 8
	 * @return string
1905
	 */
1906 8
	public function getUserIdentifier($userId)
1907 8
	{
1908 8
		$registry = bab_getRegistryInstance();
1909 8
		$registry->changeDirectory('/LibCaldav/Users/' . $userId);
1910
		$identifier = $registry->getValue('identifier');
1911
		if (!isset($identifier)) {
1912
			return bab_getUserNickname($userId);
1913
		}
1914
		return $identifier;
1915
	}
1916
1917
1918
1919
1920
	/**
1921
	 * Sets the caldav identifier for ovidentia user $userId.
1922
	 *
1923
	 * @param string	$identifier
1924
	 *
1925 1
	 * @param int    $userId     The ovidentia user id.
1926
	 * @param string $identifier The caldav user identifier.
1927 1
	 *
1928 1
	 * @return Func_CalendarBackend_Caldav
1929 1
	 */
1930 1
	public function setUserIdentifier($userId, $identifier)
1931
	{
1932
		$registry = bab_getRegistryInstance();
1933
		$registry->changeDirectory('/LibCaldav/Users/' . $userId);
1934
		$registry->setKeyValue('identifier', $identifier);
1935
	}
1936
1937
1938
1939
1940
	/**
1941
	 * Returns the stored caldav password for ovidentia user $userId.
1942 8
	 *
1943
	 * @param int $userId The ovidentia user id.
1944 8
	 *
1945 8
	 * @return string
1946 8
	 */
1947
	public function getUserPassword($userId)
1948 8
	{
1949
		$registry = bab_getRegistryInstance();
1950 8
		$registry->changeDirectory('/LibCaldav/Users/' . $userId);
1951 8
		$password = $registry->getValue('password', '');
1952 8
		return $password;
1953
	}
1954
1955 8
1956 8
1957 8
1958 8
	/**
1959 8
	 * Sets the caldav password for ovidentia user $userId.
1960
	 *
1961
	 * @param string	$password
1962
	 *
1963
	 * @param int    $userId     The ovidentia user id.
1964
	 * @param string $identifier The caldav user identifier.
0 ignored issues
show
Bug introduced by
There is no parameter named $identifier. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1965
	 *
1966
	 * @return Func_CalendarBackend_Caldav
1967
	 */
1968
	public function setUserPassword($userId, $password)
1969
	{
1970 8
		$registry = bab_getRegistryInstance();
1971
		$registry->changeDirectory('/LibCaldav/Users/' . $userId);
1972 8
		$registry->setKeyValue('password', $password);
1973 8
	}
1974
1975
	public function setUniqueId($UserId,$uniqueId)
1976 8
	{
1977
	    $registry = bab_getRegistryInstance();
1978
	    $registry->changeDirectory('/LibCaldav/Users/' . $UserId);
1979 8
	    $registry->setKeyValue('uniqueId', $uniqueId);
1980
	    
1981
	}
1982
1983
	/**
1984
	 * Returns the relative caldav path to the specified user's personal calendar.
1985
	 *
1986
	 * @param int $userId The ovidentia user id.
1987
	 *
1988
	 * @return string
1989
	 */
1990
	public function getUserCalendarPath($userId)
1991
	{
1992
		$registry = bab_getRegistryInstance();
1993
		$registry->changeDirectory('/LibCaldav/Users/' . $userId);
1994
		$path = $registry->getValue('calendarPath');
1995
1996
		if (!isset($path)) {
1997
			
1998
			$id_server = $this->getUserServerId($userId);
1999
			if (!isset($id_server))
2000
			{
2001
				return null;
2002
			}
2003
			$server = $this->getServer($id_server);
2004
			$nickname = $this->getUserIdentifier($userId);
2005
			$path = $this->processCalendarPathTemplate($server['user_calendar_path'], $nickname, $userId);
2006
			
2007
			
2008
		}
2009
		return $path;
2010
	}
2011
	
2012
	/**
2013
	 * Process replacements in calendar path
2014
	 * 
2015
	 * @param	string	$calendarPathTemplate	ex : /%u/home
2016
	 * @param	string	$nickname				Nickname as typed by the user
2017
	 * 
2018
	 * @return string
2019
	 */
2020
	public function processCalendarPathTemplate($calendarPathTemplate, $nickname, $userid)
2021
	{
2022
		
2023
		if (false !== $p = mb_strpos($nickname, '@'))
2024
		{
2025
			$n = mb_substr($nickname, 0, $p);
2026
		} else {
2027
			$n = $nickname;
2028
		}
2029
		if($this->getServerNeedId($userid))
2030
		{
2031
			$uniqueId = $this->getUniqueId($userid);
2032
			
2033
		}
2034
		else
2035
		{
2036
			$uniqueId = " ";
2037
		}
2038
		
2039
		return str_replace(array('%u', '%n', '%c'), array($nickname, $n,$uniqueId), $calendarPathTemplate);
2040
	}
2041
2042
2043
2044
2045
	/**
2046
	 * Get url of an option page for the backend, the page will be displayed in a popup window accessible for each user
2047
	 * from the calendar options.
2048
	 *
2049
	 * @return string
2050
	 */
2051
	public function getOptionsUrl()
2052
	{
2053
		$addon = bab_getAddonInfosInstance('LibCaldav');
2054
2055
		if (!$addon || !$this->configByUser())
2056
		{
2057
			return '';
2058
		}
2059
2060
		return $addon->getUrl().'userconfiguration';
2061
	}
2062
}
2063