Merge branch '2015.11-develop' into 2016.11
[tine20] / tine20 / Tinebase / WebDav / Collection / AbstractContainerTree.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Tinebase
6  * @subpackage  WebDAV
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @author      Lars Kneschke <l.kneschke@metaways.de>
9  * @copyright   Copyright (c) 2014-2014 Metaways Infosystems GmbH (http://www.metaways.de)
10  */
11
12 /**
13  * class to handle top level folders for an application
14  *
15  * @package     Tinebase
16  * @subpackage  WebDAV
17  */
18 abstract class Tinebase_WebDav_Collection_AbstractContainerTree extends \Sabre\DAV\Collection implements \Sabre\DAV\IProperties, \Sabre\DAVACL\IACL, \Sabre\DAV\IExtendedCollection
19 {
20     /**
21      * the current application object
22      * 
23      * @var Tinebase_Model_Application
24      */
25     protected $_application;
26     
27     /**
28      * application name
29      *
30      * @var string
31      */
32     protected $_applicationName;
33     
34     /**
35      * app has personal folders
36      *
37      * @var string
38      */
39     protected $_hasPersonalFolders = true;
40     
41     /**
42      * app has records folder
43      *
44      * @var string
45      */
46     protected $_hasRecordFolder = true;
47     
48     /**
49      * the current path
50      * 
51      * @var string
52      */
53     protected $_path;
54     
55     /**
56      * @var array
57      */
58     protected $_pathParts;
59     
60     /**
61      * 
62      * @var boolean
63      */
64     protected $_useIdAsName;
65     
66     protected static $_classCache = array (
67         '_getUser' => array()
68     );
69     
70     /**
71      * contructor
72      * 
73      * @param string $path         the current path
74      * @param bool   $useIdAsName  use name or id as node name
75      */
76     public function __construct($path, $useIdAsName = false)
77     {
78         $this->_path        = $path;
79         $this->_useIdAsName = $useIdAsName;
80     }
81
82     /**
83      * use login as folder name
84      *
85      * @return boolean
86      */
87     protected function _useLoginAsFolderName()
88     {
89         return Tinebase_Config::getInstance()->get(Tinebase_Config::USE_LOGINNAME_AS_FOLDERNAME);
90     }
91     
92     /**
93      * (non-PHPdoc)
94      * @see \Sabre\DAV\Collection::createDirectory()
95      */
96     public function createDirectory($name) 
97     {
98         return $this->_createContainer(array(
99             'name' => $name
100         ));
101     }
102     
103     /**
104      * (non-PHPdoc)
105      * @see \Sabre\DAV\IExtendedCollection::createExtendedCollection()
106      */
107     public function createExtendedCollection($name, array $resourceType, array $properties)
108     {
109         return $this->_createContainer(array(
110             'name'  => isset($properties['{DAV:}displayname']) ? $properties['{DAV:}displayname'] : $name,
111             'uuid'  => $name,
112             'color' => isset($properties['{http://apple.com/ns/ical/}calendar-color']) ? substr($properties['{http://apple.com/ns/ical/}calendar-color'], 0, 7) : null
113         ));
114     }
115     
116     /**
117      * (non-PHPdoc)
118      * @see Sabre\DAV\Collection::getChild()
119      */
120     public function getChild($name)
121     {
122         switch (count($this->_getPathParts())) {
123             # path == /<applicationPrefix> (for example calendars)
124             # return folders for currentuser, other users and 'shared' folder
125             # $name can be
126             # * contact_id of user
127             # * 'shared'
128             case 1:
129                 if ($name === Tinebase_Model_Container::TYPE_SHARED ||
130                     ($this->_hasRecordFolder && $name === Tinebase_FileSystem::FOLDER_TYPE_RECORDS)) {
131                     $path = $this->_path . '/' . $name;
132                     
133                 } elseif ($this->_hasPersonalFolders) {
134                     if ($name === '__currentuser__') {
135                         $path = $this->_path . '/__currentuser__';
136                         
137                     } else {
138                         try {
139                             // check if it exists only
140                             $this->_getUser($name);
141                             
142                         } catch (Tinebase_Exception_NotFound $tenf) {
143                             $message = "Directory $this->_path/$name not found";
144                             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(
145                                 __METHOD__ . '::' . __LINE__ . ' ' . $message);
146                             throw new \Sabre\DAV\Exception\NotFound($message);
147                         }
148                         
149                         $path = $this->_path . '/' . $name;
150                     }
151                     
152                 } else {
153                     throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
154                 }
155                 
156                 $className = $this->_getApplicationName() . '_Frontend_WebDAV';
157                 
158                 return new $className($path, $this->_useIdAsName);
159                 
160                 break;
161                 
162             # path == /<applicationPrefix>/<contactid>|'shared'
163             # list container
164             case 2:
165                 if (Tinebase_Helper::array_value(1, $this->_getPathParts()) == Tinebase_Model_Container::TYPE_SHARED) {
166                     try { 
167                         if ($name instanceof Tinebase_Model_Container) {
168                             $container = $name;
169                         } elseif ($this->_useIdAsName) {
170                             // first try to fetch by uuid ...
171                             try {
172                                 $container = Tinebase_Container::getInstance()->getByProperty((string) $name, 'uuid');
173                             } catch (Tinebase_Exception_NotFound $tenf) {
174                                 // ... if that fails by id
175                                 $container = Tinebase_Container::getInstance()->getContainerById($name);
176                             }
177                         } else {
178                             $container = Tinebase_Container::getInstance()->getContainerByName(
179                                 $this->_getApplicationName(),
180                                 (string) $name,
181                                 Tinebase_Model_Container::TYPE_SHARED
182                             );
183                         }
184                         
185                     } catch (Tinebase_Exception_NotFound $tenf) {
186                         throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
187                         
188                     } catch (Tinebase_Exception_InvalidArgument $teia) {
189                         // invalid container id provided
190                         throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
191                     }
192                 } elseif ($this->_hasRecordFolder && Tinebase_Helper::array_value(1, $this->_getPathParts()) == Tinebase_FileSystem::FOLDER_TYPE_RECORDS) {
193                     
194                     return new Tinebase_Frontend_WebDAV_RecordCollection($this->_path . '/' . $name);
195                     
196                 } elseif ($this->_hasPersonalFolders) {
197                     if (Tinebase_Helper::array_value(1, $this->_getPathParts()) === '__currentuser__') {
198                         $accountId = Tinebase_Core::getUser()->accountId;
199                         
200                     } else {
201                         try {
202                             $accountId = $this->_getUser(Tinebase_Helper::array_value(1, $this->_getPathParts()))->accountId;
203                             
204                         } catch (Tinebase_Exception_NotFound $tenf) {
205                             throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
206                         }
207                     }
208                     
209                     try {
210                         if ($name instanceof Tinebase_Model_Container) {
211                             $container = $name;
212                         } elseif ($this->_useIdAsName) {
213                             // first try to fetch by uuid ...
214                             try {
215                                 $container = Tinebase_Container::getInstance()->getByProperty((string) $name, 'uuid');
216                             } catch (Tinebase_Exception_NotFound $tenf) {
217                                 // ... if that fails by id
218                                 $container = Tinebase_Container::getInstance()->getContainerById($name);
219                             }
220                             
221                         } else { 
222                             $container = Tinebase_Container::getInstance()->getContainerByName(
223                                 $this->_getApplicationName(),
224                                 (string) $name,
225                                 Tinebase_Model_Container::TYPE_PERSONAL, 
226                                 $accountId
227                             );
228                         }
229                         
230                     } catch (Tinebase_Exception_NotFound $tenf) {
231                         throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
232                         
233                     } catch (Tinebase_Exception_InvalidArgument $teia) {
234                         // invalid container id provided
235                         throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
236                     }
237                     
238                 } else {
239                     throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
240                 }
241                 
242                 if (!Tinebase_Core::getUser()->hasGrant($container, Tinebase_Model_Grants::GRANT_READ) ||
243                     !Tinebase_Core::getUser()->hasGrant($container, Tinebase_Model_Grants::GRANT_SYNC)) {
244                     throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
245                 }
246                 
247                 $objectClass = Tinebase_Application::getInstance()->getApplicationById($container->application_id)->name . '_Frontend_WebDAV_Container';
248                 
249                 if (! class_exists($objectClass)) {
250                     throw new \Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
251                 }
252                  
253                 return new $objectClass($container, $this->_useIdAsName);
254                 
255                 break;
256                 
257             default:
258                 throw new Sabre\DAV\Exception\NotFound("Directory $this->_path/$name not found");
259             
260                 break;
261         }
262     }
263     
264     /**
265      * Returns an array with all the child nodes
266      * 
267      * the records subtree is not returned as child here. It's only available via getChild().
268      *
269      * @return \Sabre\DAV\INode[]
270      */
271     public function getChildren()
272     {
273         $children = array();
274         
275         switch (count($this->_getPathParts())) {
276             # path == /<applicationPrefix> (for example calendars)
277             # return folders for currentuser, other users and 'shared' folder
278             case 1:
279                 $children[] = $this->getChild(Tinebase_Model_Container::TYPE_SHARED);
280                 
281                 if ($this->_hasPersonalFolders) {
282                     $children[] = $this->getChild(
283                         $this->_useIdAsName ?
284                             Tinebase_Core::getUser()->contact_id :
285                             ($this->_useLoginAsFolderName() ?
286                                 Tinebase_Core::getUser()->accountLoginName :
287                                 Tinebase_Core::getUser()->accountDisplayName)
288                     );
289                     
290                     $otherUsers = Tinebase_Container::getInstance()->getOtherUsers(Tinebase_Core::getUser(), $this->_getApplicationName(), array(
291                         Tinebase_Model_Grants::GRANT_READ,
292                         Tinebase_Model_Grants::GRANT_SYNC
293                     ));
294                     
295                     foreach ($otherUsers as $user) {
296                         if ($user->contact_id && $user->visibility === Tinebase_Model_User::VISIBILITY_DISPLAYED) {
297                             try {
298                                 $folderId = $this->_useIdAsName ?
299                                     $user->contact_id :
300                                     ($this->_useLoginAsFolderName() ? $user->accountLoginName : $user->accountDisplayName);
301
302                                 $children[] = $this->getChild($folderId);
303                             } catch (\Sabre\DAV\Exception\NotFound $sdavenf) {
304                                 // ignore contacts not found
305                             }
306                         }
307                     }
308                 }
309         
310                 break;
311             
312             # path == /<applicationPrefix>/<contactid>|'shared'
313             # list container
314             case 2:
315                 if (Tinebase_Helper::array_value(1, $this->_getPathParts()) == Tinebase_Model_Container::TYPE_SHARED) {
316                     $containers = Tinebase_Container::getInstance()->getSharedContainer(
317                         Tinebase_Core::getUser(),
318                         $this->_getApplicationName(),
319                         array(
320                             Tinebase_Model_Grants::GRANT_READ,
321                             Tinebase_Model_Grants::GRANT_SYNC
322                         )
323                     );
324                     
325                 } elseif ($this->_hasPersonalFolders) {
326                     if (Tinebase_Helper::array_value(1, $this->_getPathParts()) === '__currentuser__') {
327                         $accountId = Tinebase_Core::getUser()->accountId;
328                         
329                     } else {
330                         try {
331                             $accountId = $this->_getUser(Tinebase_Helper::array_value(1, $this->_getPathParts()))->accountId;
332                         } catch (Tinebase_Exception_NotFound $tenf) {
333                             throw new \Sabre\DAV\Exception\NotFound("Path $this->_path not found");
334                         }
335                     }
336                     
337                     try {
338                         if ($this->_getApplicationName() === 'Filemanager' || $this->_clientSupportsDelegations()) {
339                             $containers = Tinebase_Container::getInstance()->getPersonalContainer(
340                                 Tinebase_Core::getUser(),
341                                 $this->_getApplicationName(),
342                                 $accountId,
343                                 array(
344                                     Tinebase_Model_Grants::GRANT_READ, 
345                                     Tinebase_Model_Grants::GRANT_SYNC
346                                 )
347                             ); 
348                         } else {
349                             $containers = Tinebase_Container::getInstance()->getContainerByACL(Tinebase_Core::getUser(), $this->_getApplicationName(),  array(
350                                 Tinebase_Model_Grants::GRANT_READ, 
351                                 Tinebase_Model_Grants::GRANT_SYNC
352                             ));
353                         }
354                     } catch (Tinebase_Exception_AccessDenied $tead) {
355                         throw new Sabre\DAV\Exception\NotFound("Could not find path (" . $tead->getMessage() . ")");
356                     }
357                     
358                 } else {
359                     throw new Sabre\DAV\Exception\NotFound("Path $this->_path not found");
360                 }
361                 
362                 foreach ($containers as $container) {
363                     try {
364                         $children[] = $this->getChild($this->_useIdAsName ? $container->getId() : $container->name);
365                     } catch (\Sabre\DAV\Exception\NotFound $sdavenf) {
366                         // ignore containers not found
367                     }
368                 }
369                 
370                 break;
371                 
372             default:
373                 throw new Sabre\DAV\Exception\NotFound("Path $this->_path not found");
374                 
375                 break;
376         }
377         
378         return $children;
379     }
380     
381     /**
382      * checks if client supports delegations
383      * 
384      * @return boolean
385      * 
386      * @todo don't use $_SERVER to fetch user agent
387      * @todo move user agent parsing to Tinebase
388      */
389     protected function _clientSupportsDelegations()
390     {
391         if (isset($_SERVER['HTTP_USER_AGENT'])) {
392             list($backend, $version) = Calendar_Convert_Event_VCalendar_Factory::parseUserAgent($_SERVER['HTTP_USER_AGENT']);
393             $clientSupportsDelegations = ($backend === Calendar_Convert_Event_VCalendar_Factory::CLIENT_MACOSX);
394         } else {
395             $clientSupportsDelegations = false;
396         }
397         
398         return $clientSupportsDelegations;
399     }
400     
401     /**
402      * return etag
403      * 
404      * @return string
405      */
406     public function getETag()
407     {
408         $etags = array();
409         
410         foreach ($this->getChildren() as $child) {
411             $etags[] = $child->getETag();
412         }
413         
414         return '"' . sha1(implode(null, $etags)) . '"';
415     }
416     
417     /**
418      * Returns a group principal
419      *
420      * This must be a url to a principal, or null if there's no owner
421      *
422      * @return string|null
423      */
424     public function getGroup()
425     {
426         return null;
427     }
428     
429     /**
430      * (non-PHPdoc)
431      * @see \Sabre\DAV\Node::getLastModified()
432      */
433     public function getLastModified()
434     {
435         $lastModified = 1;
436         
437         foreach ($this->getChildren() as $child) {
438             $lastModified = $child->getLastModified() > $lastModified ? $child->getLastModified() : $lastModified;
439         }
440         
441         return $lastModified;
442     }
443     
444     /**
445      * Returns a list of ACE's for this node.
446      *
447      * Each ACE has the following properties:
448      *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
449      *     currently the only supported privileges
450      *   * 'principal', a url to the principal who owns the node
451      *   * 'protected' (optional), indicating that this ACE is not allowed to
452      *      be updated.
453      *      
454      * @todo implement real logic
455      * @return array
456      */
457     public function getACL() 
458     {
459         $principal = 'principals/users/' . Tinebase_Core::getUser()->contact_id;
460         
461         return array(
462             array(
463                 'privilege' => '{DAV:}read',
464                 'principal' => $principal,
465                 'protected' => true,
466             ),
467             array(
468                 'privilege' => '{DAV:}write',
469                 'principal' => $principal,
470                 'protected' => true,
471             )
472         );
473     }
474     
475     /**
476      * Returns the name of the node
477      *
478      * @return string
479      */
480     public function getName()
481     {
482         if (count($this->_getPathParts()) === 2 && 
483             Tinebase_Helper::array_value(1, $this->_getPathParts()) !== Tinebase_Model_Container::TYPE_SHARED &&
484             !$this->_useIdAsName
485         ) {
486             try {
487                 $user = $this->_getUser(Tinebase_Helper::array_value(1, $this->_getPathParts()));
488                 
489                 $name = $this->_useLoginAsFolderName() ? $user->accountLoginName : $user->accountDisplayName;
490                 
491             } catch (Tinebase_Exception_NotFound $tenf) {
492                 list(,$name) = Sabre\DAV\URLUtil::splitPath($this->_path);
493             }
494             
495         } else {
496             list(,$name) = Sabre\DAV\URLUtil::splitPath($this->_path);
497         }
498         
499         return $name;
500     }
501     
502     /**
503      * Returns the owner principal
504      *
505      * This must be a url to a principal, or null if there's no owner
506      * 
507      * @return string|null
508      */
509     public function getOwner()
510     {
511         if (count($this->_getPathParts()) === 2 && $this->getName() !== Tinebase_Model_Container::TYPE_SHARED) {
512             try {
513                 $user = $this->_getUser(Tinebase_Helper::array_value(1, $this->_getPathParts()));
514             } catch (Tinebase_Exception_NotFound $tenf) {
515                 return null;
516             }
517             
518             return 'principals/users/' . $user->contact_id;
519         }
520         
521         return null;
522     }
523     
524     /**
525      * Returns the list of properties
526      *
527      * @param array $requestedProperties
528      * @return array
529      */
530     public function getProperties($requestedProperties) 
531     {
532         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
533             __METHOD__ . '::' . __LINE__ . ' path: ' . $this->_path . ' ' . print_r($requestedProperties, true));
534         
535         $response = array();
536     
537         foreach ($requestedProperties as $property) {
538             switch ($property) {
539                 case '{DAV:}displayname':
540                     if (count($this->_getPathParts()) === 2 && $this->getName() !== Tinebase_Model_Container::TYPE_SHARED) {
541                         try {
542                             $user = $this->_getUser(Tinebase_Helper::array_value(1, $this->_getPathParts()));
543                             $contact = Addressbook_Controller_Contact::getInstance()->get($user->contact_id);
544                         } catch (Tinebase_Exception_NotFound $tenf) {
545                             continue 2;
546                         }
547                         
548                         $response[$property] = $contact->n_fileas;
549                     }
550                     
551                     break;
552                     
553                 case '{DAV:}owner':
554                     if ($this->getOwner()) {
555                         $response[$property] = new \Sabre\DAVACL\Property\Principal(
556                             \Sabre\DAVACL\Property\Principal::HREF, $this->getOwner()
557                         );
558                     }
559                     
560                     break;
561                     
562                 case '{DAV:}getetag':
563                     $response[$property] = $this->getETag();
564                     
565                     break;
566             }
567         }
568         
569         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(
570             __METHOD__ . '::' . __LINE__ . ' path: ' . $this->_path . ' ' . print_r($response, true));
571         
572         return $response;
573     }
574     
575     /**
576      * Updates the ACL
577      *
578      * This method will receive a list of new ACE's.
579      *
580      * @param array $acl
581      * @return void
582      */
583     public function setACL(array $acl)
584     {
585         throw new Sabre\DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
586     }
587     
588     /**
589      * Updates properties on this node,
590      *
591      * The properties array uses the propertyName in clark-notation as key,
592      * and the array value for the property value. In the case a property
593      * should be deleted, the property value will be null.
594      *
595      * This method must be atomic. If one property cannot be changed, the
596      * entire operation must fail.
597      *
598      * If the operation was successful, true can be returned.
599      * If the operation failed, false can be returned.
600      *
601      * Deletion of a non-existant property is always succesful.
602      *
603      * Lastly, it is optional to return detailed information about any
604      * failures. In this case an array should be returned with the following
605      * structure:
606      *
607      * array(
608      *   403 => array(
609      *      '{DAV:}displayname' => null,
610      *   ),
611      *   424 => array(
612      *      '{DAV:}owner' => null,
613      *   )
614      * )
615      *
616      * In this example it was forbidden to update {DAV:}displayname. 
617      * (403 Forbidden), which in turn also caused {DAV:}owner to fail
618      * (424 Failed Dependency) because the request needs to be atomic.
619      *
620      * @param array $mutations 
621      * @return bool|array 
622      */
623     public function updateProperties($mutations) 
624     {
625         $result = array(
626             200 => array(),
627             403 => array()
628         );
629
630         foreach ($mutations as $key => $value) {
631             switch ($key) {
632                 // once iCal tried to set default-alarm config with a negative feedback
633                 // it doesn't send default-alarms to the server any longer. So we fake
634                 // success here as workaround to let the client send its default alarms
635                 case '{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}default-alarm-vevent-datetime':
636                 case '{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}default-alarm-vevent-date':
637                 case '{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}default-alarm-vtodo-datetime':
638                 case '{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}default-alarm-vtodo-date':
639                     // fake success
640                     $result['200'][$key] = null;
641                     break;
642
643                 default:
644                     $result['403'][$key] = null;
645             }
646         }
647
648         return $result;
649     }
650     
651     /**
652      * 
653      */
654     public function getSupportedPrivilegeSet()
655     {
656         return null;
657     }
658     
659     /**
660      * return application object
661      * 
662      * @return Tinebase_Model_Application
663      */
664     protected function _getApplication()
665     {
666         if (!$this->_application) {
667             $this->_application = Tinebase_Application::getInstance()->getApplicationByName($this->_getApplicationName());
668         }
669         
670         return $this->_application;
671     }
672     
673     /**
674      * creates a new container
675      * 
676      * @todo allow to create personal folders only when in currents users own path
677      * 
678      * @param  array  $properties  properties for new container
679      * @throws \Sabre\DAV\Exception\Forbidden
680      * @return Tinebase_Model_Container
681      */
682     protected function _createContainer(array $properties) 
683     {
684         if (count($this->_getPathParts()) !== 2) {
685             throw new \Sabre\DAV\Exception\Forbidden('Permission denied to create directory ' . $properties['name']);
686         }
687         
688         $containerType = Tinebase_Helper::array_value(1, $this->_getPathParts()) == Tinebase_Model_Container::TYPE_SHARED ?
689             Tinebase_Model_Container::TYPE_SHARED :
690             Tinebase_Model_Container::TYPE_PERSONAL;
691         
692         $newContainer = new Tinebase_Model_Container(array_merge($properties, array(
693             'type'              => $containerType,
694             'backend'           => 'Sql',
695             'application_id'    => $this->_getApplication()->getId(),
696             'model'             => Tinebase_Core::getApplicationInstance($this->_applicationName)->getDefaultModel()
697         )));
698
699         try {
700             $container = Tinebase_Container::getInstance()->addContainer($newContainer);
701         } catch (Tinebase_Exception_AccessDenied $tead) {
702             throw new \Sabre\DAV\Exception\Forbidden('Permission denied to create directory ' . $properties['name']);
703         }
704         
705         return $container;
706     }
707     
708     /**
709      * return application name
710      * 
711      * @return string
712      */
713     protected function _getApplicationName()
714     {
715         if (!$this->_applicationName) {
716             $this->_applicationName = Tinebase_Helper::array_value(0, explode('_', get_class($this)));
717         }
718         
719         return $this->_applicationName;
720     }
721     
722     /**
723      * get path parts
724      * 
725      * @return array
726      */
727     protected function _getPathParts()
728     {
729         if (!$this->_pathParts) {
730             $this->_pathParts = $this->_parsePath($this->_path);
731         }
732         
733         return $this->_pathParts;
734     }
735     
736     /**
737      * split path into parts
738      * 
739      * @param  string  $_path
740      * @return array
741      */
742     protected function _parsePath($_path)
743     {
744         $pathParts = explode('/', trim($this->_path, '/'));
745         
746         return $pathParts;
747     }
748
749     protected function _getUser($_id)
750     {
751         $classCacheId = ($this->_useIdAsName ? 'contact_id' : ($this->_useLoginAsFolderName() ? 'accountLoginName' : 'accountDisplayName')) . $_id;
752
753         if (isset(self::$_classCache[__FUNCTION__][$classCacheId])) {
754             return self::$_classCache[__FUNCTION__][$classCacheId];
755         }
756
757         if ($this->_useIdAsName) {
758             $contact = Addressbook_Controller_Contact::getInstance()->get($_id);
759             $user = Tinebase_User::getInstance()->getUserByPropertyFromSqlBackend('accountId', $contact->account_id, 'Tinebase_Model_FullUser');
760         } else {
761             if ($this->_useLoginAsFolderName()) {
762                 $user = Tinebase_User::getInstance()->getUserByPropertyFromSqlBackend('accountLoginName', $_id, 'Tinebase_Model_FullUser');
763             } else {
764                 $user = Tinebase_User::getInstance()->getUserByPropertyFromSqlBackend('accountDisplayName', $_id, 'Tinebase_Model_FullUser');
765             }
766         }
767
768         self::$_classCache[__FUNCTION__][$classCacheId] = $user;
769
770         return $user;
771     }
772 }