eZ Publish  [4.0]
ezcontentobjecttreenode.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZContentObjectTreeNode class
00004 //
00005 // Created on: <10-Jul-2002 19:28:22 sp>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*! \file ezcontentobjecttreenode.php
00032 */
00033 
00034 /*!
00035   \class eZContentObjectTreeNode ezcontentobjecttreenode.php
00036   \brief The class eZContentObjectTreeNode does
00037 
00038 \verbatim
00039 
00040 Some algorithms
00041 ----------
00042 1. Adding new Node
00043 Enter  1 - parent_node
00044        2 - contentobject_id,  ( that is like a node value )
00045 
00046 (a) - get path_string, depth for parent node to built path_string  and to count depth for new one
00047 (c) - calculating attributes for new node and inserting it
00048 Returns node_id for added node
00049 
00050 
00051 2. Deleting node ( or subtree )
00052 Enter - node_id
00053 
00054 3. Move subtree in tree
00055 Enter node_id,new_parent_id
00056 
00057 
00058 4. fetching subtree
00059 
00060 \endverbatim
00061 
00062 */
00063 
00064 //include_once( "lib/ezutils/classes/ezini.php" );
00065 //include_once( "lib/ezutils/classes/ezhttptool.php" );
00066 //include_once( "lib/ezutils/classes/ezdebugsetting.php" );
00067 //include_once( "kernel/classes/ezcontentobject.php" );
00068 //include_once( "kernel/classes/ezurlaliasml.php" );
00069 
00070 class eZContentObjectTreeNode extends eZPersistentObject
00071 {
00072     /*!
00073      Constructor
00074     */
00075     function eZContentObjectTreeNode( $row = array() )
00076     {
00077         $this->eZPersistentObject( $row );
00078     }
00079 
00080     static function definition()
00081     {
00082         return array( "fields" => array( "node_id" => array( 'name' => "NodeID",
00083                                                              'datatype' => 'integer',
00084                                                              'default' => 0,
00085                                                              'required' => true ),
00086                                          "parent_node_id" => array( 'name' => "ParentNodeID",
00087                                                                     'datatype' => 'integer',
00088                                                                     'default' => 0,
00089                                                                     'required' => true,
00090                                                                     'foreign_class' => 'eZContentObjectTreeNode',
00091                                                                     'foreign_attribute' => 'node_id',
00092                                                                     'multiplicity' => '1..*' ),
00093                                          "main_node_id" => array( 'name' => "MainNodeID",
00094                                                                   'datatype' => 'integer',
00095                                                                   'default' => 0,
00096                                                                   'required' => true,
00097                                                                   'foreign_class' => 'eZContentObjectTreeNode',
00098                                                                   'foreign_attribute' => 'node_id',
00099                                                                   'multiplicity' => '1..*' ),
00100                                          "contentobject_id" => array( 'name' => "ContentObjectID",
00101                                                                       'datatype' => 'integer',
00102                                                                       'default' => 0,
00103                                                                       'required' => true,
00104                                                                       'foreign_class' => 'eZContentObject',
00105                                                                       'foreign_attribute' => 'id',
00106                                                                       'multiplicity' => '1..*' ),
00107                                          'contentobject_version' => array( 'name' => 'ContentObjectVersion',
00108                                                                            'datatype' => 'integer',
00109                                                                            'default' => 0,
00110                                                                            'required' => true ),
00111                                          'contentobject_is_published' => array( 'name' => 'ContentObjectIsPublished',
00112                                                                                 'datatype' => 'integer',
00113                                                                                 'default' => 0,
00114                                                                                 'required' => true ),
00115                                          "depth" => array( 'name' => "Depth",
00116                                                            'datatype' => 'integer',
00117                                                            'default' => 0,
00118                                                            'required' => true ),
00119                                          'sort_field' => array( 'name' => 'SortField',
00120                                                                 'datatype' => 'integer',
00121                                                                 'default' => 1,
00122                                                                 'required' => true ),
00123                                          'sort_order' => array( 'name' => 'SortOrder',
00124                                                                 'datatype' => 'integer',
00125                                                                 'default' => 1,
00126                                                                 'required' => true ),
00127                                          'priority' => array( 'name' => 'Priority',
00128                                                               'datatype' => 'integer',
00129                                                               'default' => 0,
00130                                                               'required' => true ),
00131                                          'modified_subnode' => array( 'name' => 'ModifiedSubNode',
00132                                                                       'datatype' => 'integer',
00133                                                                       'default' => 0,
00134                                                                       'required' => true ),
00135                                          "path_string" => array( 'name' => "PathString",
00136                                                                  'datatype' => 'string',
00137                                                                  'default' => '',
00138                                                                  'required' => true ),
00139                                          "path_identification_string" => array( 'name' => "PathIdentificationString",
00140                                                                                 'datatype' => 'text',
00141                                                                                 'default' => '',
00142                                                                                 'required' => true ),
00143                                          'remote_id' => array( 'name' => 'RemoteID',
00144                                                                'datatype' => 'string',
00145                                                                'default' => '',
00146                                                                'required' => true ),
00147                                          "is_hidden" => array( 'name' => "IsHidden",
00148                                                                'datatype' => 'integer',
00149                                                                'default' => 0,
00150                                                                'required' => true ),
00151                                          "is_invisible" => array( 'name' => "IsInvisible",
00152                                                                   'datatype' => 'integer',
00153                                                                   'default' => 0,
00154                                                                   'required' => true ) ),
00155                       "keys" => array( "node_id" ),
00156                       "function_attributes" => array( "name" => "getName",
00157                                                       'data_map' => 'dataMap',
00158                                                       'remote_id' => 'remoteID', // Note: This overrides remote_id field
00159                                                       "object" => "object",
00160                                                       "subtree" => "subTree",
00161                                                       "children" => "children",
00162                                                       "children_count" => "childrenCount",
00163                                                       'view_count' => 'viewCount',
00164                                                       'contentobject_version_object' => 'contentObjectVersionObject',
00165                                                       'sort_array' => 'sortArray',
00166                                                       'can_read' => 'canRead',
00167                                                       'can_pdf' =>  'canPdf',
00168                                                       'can_create' => 'canCreate',
00169                                                       'can_edit' => 'canEdit',
00170                                                       'can_hide' => 'canHide',
00171                                                       'can_remove' => 'canRemove',
00172                                                       'can_move' => 'canMoveFrom',
00173                                                       'can_move_from' => 'canMoveFrom',
00174                                                       'can_add_location' => 'canAddLocation',
00175                                                       'can_remove_location' => 'canRemoveLocation',
00176                                                       'can_view_embed' => 'canViewEmbed',
00177                                                       'is_main' => 'isMain',
00178                                                       'creator' => 'creator',
00179                                                       "path_with_names" => "pathWithNames",
00180                                                       "path" => "fetchPath",
00181                                                       'path_array' => 'pathArray',
00182                                                       "parent" => "fetchParent",
00183                                                       'url' => 'url',
00184                                                       'url_alias' => 'urlAlias',
00185                                                       'class_identifier' => 'classIdentifier',
00186                                                       'class_name' => 'className',
00187                                                       'hidden_invisible_string' => 'hiddenInvisibleString',
00188                                                       'hidden_status_string' => 'hiddenStatusString',
00189                                                       'classes_js_array' => 'availableClassesJsArray' ),
00190                       "increment_key" => "node_id",
00191                       "class_name" => "eZContentObjectTreeNode",
00192                       "name" => "ezcontentobject_tree" );
00193     }
00194 
00195     /*!
00196      Creates a new tree node and returns it.
00197      \param $parentNodeID The ID of the parent or \c null if the node is not known yet.
00198      \param $contentObjectID The ID of the object it points to or \c null if it is not known yet.
00199      \param $contentObjectVersion The version of the object or \c 0 if not known yet.
00200      \param $sortField Number describing the field to sort by, or \c 0 if not known yet.
00201      \param $sortOrder Which way to sort, \c true means ascending while \c false is descending.
00202      \note The attribute \c remote_id will get an automatic and unique value.
00203     */
00204     static function create( $parentNodeID = null, $contentObjectID = null, $contentObjectVersion = 0,
00205                       $sortField = 0, $sortOrder = true )
00206     {
00207         $row = array( 'node_id' => null,
00208                       'main_node_id' => null,
00209                       'parent_node_id' => $parentNodeID,
00210                       'contentobject_id' => $contentObjectID,
00211                       'contentobject_version' => $contentObjectVersion,
00212                       'contentobject_is_published' => false,
00213                       'depth' => 1,
00214                       'path_string' => null,
00215                       'path_identification_string' => null,
00216                       'is_hidden' => false,
00217                       'is_invisible' => false,
00218                       'sort_field' => $sortField,
00219                       'sort_order' => $sortOrder,
00220                       'modified_subnode' => 0,
00221                       'remote_id' => md5( (string)mt_rand() . (string)time() ),
00222                       'priority' => 0 );
00223         $node = new eZContentObjectTreeNode( $row );
00224         return $node;
00225     }
00226 
00227     /*!
00228      \return a map with all the content object attributes where the keys are the
00229              attribute identifiers.
00230      \sa eZContentObject::fetchDataMap
00231     */
00232     function dataMap()
00233     {
00234         return $this->object()->fetchDataMap( $this->attribute( 'contentobject_version' ) );
00235     }
00236 
00237     /*!
00238      Get remote id of content node, the remote ID is often used to synchronise imports and exports.
00239      If there is no remote ID a new unique one will be generated.
00240     */
00241     function remoteID()
00242     {
00243         $remoteID = eZPersistentObject::attribute( 'remote_id', true );
00244         if ( !$remoteID )
00245         {
00246             $this->setAttribute( 'remote_id', md5( (string)mt_rand() . (string)time() ) );
00247             $this->sync( array( 'remote_id' ) );
00248             $remoteID = eZPersistentObject::attribute( 'remote_id', true );
00249         }
00250 
00251         return $remoteID;
00252     }
00253 
00254     /*!
00255      \return true if this node is the main node.
00256      */
00257     function isMain()
00258     {
00259         return $this->NodeID == $this->MainNodeID;
00260     }
00261 
00262     /*!
00263      \return the ID of the class attribute with the given ID.
00264      False is returned if no class/attribute by that identifier is found.
00265      If multiple classes have the same identifier, the first found is returned.
00266     */
00267     static function classAttributeIDByIdentifier( $identifier )
00268     {
00269         $db = eZDB::instance();
00270         $dbName = $db->DB;
00271 
00272         //include_once( 'lib/ezutils/classes/ezphpcreator.php' );
00273         $cacheDir = eZSys::cacheDirectory();
00274         $phpCache = new eZPHPCreator( "$cacheDir", "classattributeidentifiers_$dbName.php" );
00275 
00276         eZExpiryHandler::registerShutdownFunction();
00277         $handler = eZExpiryHandler::instance();
00278         $expiryTime = 0;
00279         if ( $handler->hasTimestamp( 'class-identifier-cache' ) )
00280         {
00281             $expiryTime = $handler->timestamp( 'class-identifier-cache' );
00282         }
00283 
00284         if ( $phpCache->canRestore( $expiryTime ) )
00285         {
00286             $var = $phpCache->restore( array( 'identifierHash' => 'identifier_hash' ) );
00287             $identifierHash = $var['identifierHash'];
00288         }
00289         else
00290         {
00291             // Fetch identifier/id pair from db
00292             $query = "SELECT ezcontentclass_attribute.id as attribute_id, ezcontentclass_attribute.identifier as attribute_identifier, ezcontentclass.identifier as class_identifier
00293                       FROM ezcontentclass_attribute, ezcontentclass
00294                       WHERE ezcontentclass.id=ezcontentclass_attribute.contentclass_id";
00295             $identifierArray = $db->arrayQuery( $query );
00296 
00297             $identifierHash = array();
00298             foreach ( $identifierArray as $identifierRow )
00299             {
00300                 $classIdentifier = $identifierRow['class_identifier'];
00301                 $attributeIdentifier = $identifierRow['attribute_identifier'];
00302                 $attributeID = $identifierRow['attribute_id'];
00303                 $combinedIdentifier = $classIdentifier . '/' . $attributeIdentifier;
00304                 $identifierHash[$combinedIdentifier] = (int)$attributeID;
00305             }
00306 
00307             // Store identifier list to cache file
00308             $phpCache->addVariable( 'identifier_hash', $identifierHash );
00309             $phpCache->store();
00310         }
00311         $return = false;
00312         if ( isset( $identifierHash[$identifier] ) )
00313             $return = $identifierHash[$identifier];
00314 
00315         return $return;
00316     }
00317 
00318     /*!
00319      \return the ID of the class with the given ID.
00320      False is returned if no class by that identifier is found.
00321      If multiple classes have the same identifier, the first found is returned.
00322     */
00323     static function classIDByIdentifier( $identifier )
00324     {
00325         $db = eZDB::instance();
00326         $dbName = $db->DB;
00327 
00328         // VS-DBFILE
00329 
00330         //include_once( 'lib/ezutils/classes/ezphpcreator.php' );
00331         $cacheDir = eZSys::cacheDirectory();
00332         $phpCache = new eZPHPCreator( $cacheDir,
00333                                       'classidentifiers_' . $dbName . '.php',
00334                                       '',
00335                                       array( 'clustering' => 'classidentifiers' ) );
00336 
00337         eZExpiryHandler::registerShutdownFunction();
00338         $handler = eZExpiryHandler::instance();
00339         $expiryTime = 0;
00340         if ( $handler->hasTimestamp( 'class-identifier-cache' ) )
00341         {
00342             $expiryTime = $handler->timestamp( 'class-identifier-cache' );
00343         }
00344 
00345         if ( $phpCache->canRestore( $expiryTime ) )
00346         {
00347             $var = $phpCache->restore( array( 'identifierHash' => 'identifier_hash' ) );
00348             $identifierHash = $var['identifierHash'];
00349         }
00350         else
00351         {
00352             // Fetch identifier/id pair from db
00353             $query = "SELECT id, identifier FROM ezcontentclass where version=0";
00354             $identifierArray = $db->arrayQuery( $query );
00355 
00356             $identifierHash = array();
00357             foreach ( $identifierArray as $identifierRow )
00358             {
00359                 $identifierHash[$identifierRow['identifier']] = $identifierRow['id'];
00360             }
00361 
00362             // Store identifier list to cache file
00363             $phpCache->addVariable( 'identifier_hash', $identifierHash );
00364             $phpCache->store();
00365         }
00366         $return = false;
00367         if ( isset( $identifierHash[$identifier] ) )
00368             $return = $identifierHash[$identifier];
00369 
00370         return $return;
00371     }
00372 
00373     /*!
00374      \return \c true if the node can be read by the current user.
00375      \sa checkAccess().
00376      \note The reference for the return value is required to workaround
00377            a bug with PHP references.
00378     */
00379     function canRead( )
00380     {
00381         if ( !isset( $this->Permissions["can_read"] ) )
00382         {
00383             $this->Permissions["can_read"] = $this->checkAccess( 'read' );
00384         }
00385         return ( $this->Permissions["can_read"] == 1 );
00386     }
00387 
00388     /*!
00389      \return \c true if the current user can create a pdf of this content object.
00390      \note The reference for the return value is required to workaround
00391            a bug with PHP references.
00392     */
00393     function canPdf( )
00394     {
00395         if ( !isset( $this->Permissions["can_pdf"] ) )
00396         {
00397             $this->Permissions["can_pdf"] = $this->checkAccess( 'pdf' );
00398         }
00399         return ( $this->Permissions["can_pdf"] == 1 );
00400     }
00401 
00402 
00403     /*!
00404      \return \c true if the node can be viewed as embeded object by the current user.
00405      \sa checkAccess().
00406      \note The reference for the return value is required to workaround
00407            a bug with PHP references.
00408     */
00409     function canViewEmbed( )
00410     {
00411         if ( !isset( $this->Permissions["can_view_embed"] ) )
00412         {
00413             $this->Permissions["can_view_embed"] = $this->checkAccess( 'view_embed' );
00414         }
00415         return ( $this->Permissions["can_view_embed"] == 1 );
00416     }
00417 
00418     /*!
00419      \return \c true if the node can be edited by the current user.
00420      \sa checkAccess().
00421      \note The reference for the return value is required to workaround
00422            a bug with PHP references.
00423     */
00424     function canEdit( )
00425     {
00426         if ( !isset( $this->Permissions["can_edit"] ) )
00427         {
00428             $this->Permissions["can_edit"] = $this->checkAccess( 'edit' );
00429             if ( $this->Permissions["can_edit"] != 1 )
00430             {
00431                  $user = eZUser::currentUser();
00432                  if ( $user->id() == $this->ContentObject->attribute( 'id' ) )
00433                  {
00434                      $access = $user->hasAccessTo( 'user', 'selfedit' );
00435                      if ( $access['accessWord'] == 'yes' )
00436                      {
00437                          $this->Permissions["can_edit"] = 1;
00438                      }
00439                  }
00440             }
00441         }
00442         return ( $this->Permissions["can_edit"] == 1 );
00443     }
00444 
00445     /*!
00446      \return \c true if the node can be hidden by the current user.
00447      \sa checkAccess().
00448      \note The reference for the return value is required to workaround
00449            a bug with PHP references.
00450     */
00451     function canHide( )
00452     {
00453         if ( !isset( $this->Permissions["can_hide"] ) )
00454         {
00455             $this->Permissions["can_hide"] = $this->checkAccess( 'hide' );
00456         }
00457         return ( $this->Permissions["can_hide"] == 1 );
00458     }
00459 
00460     /*!
00461      \return \c true if the current user can create a new node as child of this node.
00462      \sa checkAccess().
00463      \note The reference for the return value is required to workaround
00464            a bug with PHP references.
00465     */
00466     function canCreate( )
00467     {
00468         if ( !isset( $this->Permissions["can_create"] ) )
00469         {
00470             $this->Permissions["can_create"] = $this->checkAccess( 'create' );
00471         }
00472         return ( $this->Permissions["can_create"] == 1 );
00473     }
00474 
00475     /*!
00476      \return \c true if the node can be removed by the current user.
00477      \sa checkAccess().
00478      \note The reference for the return value is required to workaround
00479            a bug with PHP references.
00480     */
00481     function canRemove( )
00482     {
00483         if ( !isset( $this->Permissions["can_remove"] ) )
00484         {
00485             $this->Permissions["can_remove"] = $this->checkAccess( 'remove' );
00486         }
00487         return ( $this->Permissions["can_remove"] == 1 );
00488     }
00489 
00490     /*!
00491      Check if the node can be moved. (actually checks 'edit' and 'remove' permissions)
00492      \return \c true if the node can be moved by the current user.
00493      \sa checkAccess().
00494      \note The reference for the return value is required to workaround
00495            a bug with PHP references.
00496      \deprecated The function canMove() is preferred since its naming is clearer.
00497     */
00498     function canMove()
00499     {
00500         return $this->canMoveFrom();
00501     }
00502 
00503     /*!
00504      Check if the node can be moved. (actually checks 'edit' and 'remove' permissions)
00505      \return \c true if the node can be moved by the current user.
00506      \sa checkAccess().
00507      \note The reference for the return value is required to workaround
00508            a bug with PHP references.
00509     */
00510     function canMoveFrom( )
00511     {
00512         if ( !isset( $this->Permissions['can_move_from'] ) )
00513         {
00514             $this->Permissions['can_move_from'] = $this->checkAccess( 'edit' ) && $this->checkAccess( 'remove' );
00515         }
00516         return ( $this->Permissions['can_move_from'] == 1 );
00517     }
00518 
00519     /*!
00520      \return \c true if a node of class \a $classID can be moved to the current node by the current user.
00521      \sa checkAccess().
00522      \note The reference for the return value is required to workaround
00523            a bug with PHP references.
00524     */
00525     function canMoveTo( $classID = false )
00526     {
00527         if ( !isset( $this->Permissions['can_move_to'] ) )
00528         {
00529             $this->Permissions['can_move_to'] = $this->checkAccess( 'create', $classID );
00530         }
00531         return ( $this->Permissions['can_move_to'] == 1 );
00532     }
00533 
00534     /*!
00535      \return \c true if a node can be swaped by the current user.
00536      \sa checkAccess().
00537      \note The reference for the return value is required to workaround
00538            a bug with PHP references.
00539     */
00540     function canSwap()
00541     {
00542         if ( !isset( $this->Permissions['can_swap'] ) )
00543         {
00544             $this->Permissions['can_swap'] = $this->checkAccess( 'edit' );
00545         }
00546         return ( $this->Permissions['can_swap'] == 1 );
00547     }
00548 
00549     /*!
00550      \return \c true if current user can add object locations to current node.
00551      \sa checkAccess()
00552     */
00553     function canAddLocation()
00554     {
00555         if ( !isset( $this->Permissions['can_add_location'] ) )
00556         {
00557             $this->Permissions['can_add_location'] = $this->checkAccess( 'can_add_location' );
00558         }
00559         return ( $this->Permissions['can_add_location'] == 1 );
00560     }
00561 
00562     /*!
00563      \return \c true if current user can add object locations to current node.
00564     */
00565     function canRemoveLocation()
00566     {
00567         if ( !isset( $this->Permissions['can_remove_location'] ) )
00568         {
00569             $this->Permissions['can_remove_location'] = $this->checkAccess( 'can_remove_location' );
00570         }
00571         return ( $this->Permissions['can_remove_location'] == 1 );
00572     }
00573 
00574     /*!
00575      \static
00576      \returns the sort key for the given classAttributeID.
00577       int|string is returend. False is returned if unsuccessful.
00578     */
00579     static function sortKeyByClassAttributeID( $classAttributeID )
00580     {
00581         //include_once( 'kernel/classes/ezcontentclassattribute.php' );
00582         return eZContentClassAttribute::sortKeyTypeByID( $classAttributeID );
00583     }
00584 
00585     /*!
00586      \static
00587     */
00588     static function dataTypeByClassAttributeID( $classAttributeID )
00589     {
00590         //include_once( 'kernel/classes/ezcontentclassattribute.php' );
00591         return eZContentClassAttribute::dataTypeByID( $classAttributeID );
00592     }
00593 
00594 
00595     /*!
00596      Fetches the number of nodes which exists in the system.
00597     */
00598     static function fetchListCount()
00599     {
00600         $sql = "SELECT count( node_id ) as count FROM ezcontentobject_tree";
00601         $db = eZDB::instance();
00602         $rows = $db->arrayQuery( $sql );
00603         return $rows[0]['count'];
00604     }
00605 
00606     /*!
00607      Fetches a list of nodes and returns it. Offset and limitation can be set if needed.
00608     */
00609     static function fetchList( $asObject = true, $offset = false, $limit = false )
00610     {
00611         $sql = "SELECT * FROM ezcontentobject_tree";
00612         $parameters = array();
00613         if ( $offset !== false )
00614             $parameters['offset'] = $offset;
00615         if ( $limit !== false )
00616             $parameters['limit'] = $limit;
00617         $db = eZDB::instance();
00618         $rows = $db->arrayQuery( $sql, $parameters );
00619         $nodes = array();
00620         if ( $asObject )
00621         {
00622             foreach ( $rows as $row )
00623             {
00624                 $nodes[] = new eZContentObjectTreeNode( $row );
00625             }
00626             return $nodes;
00627         }
00628         else
00629             return $rows;
00630     }
00631 
00632     /*!
00633         \a static
00634     */
00635     static function createSortingSQLStrings( $sortList, $treeTableName = 'ezcontentobject_tree', $allowCustomColumns = false )
00636     {
00637         $sortingInfo = array( 'sortCount'           => 0,
00638                               'sortingFields'       => " path_string ASC",
00639                               'attributeJoinCount'  => 0,
00640                               'attributeFromSQL'    => "",
00641                               'attributeTargetSQL'  => "",
00642                               'attributeWhereSQL'   => "" );
00643 
00644         if ( $sortList and is_array( $sortList ) and count( $sortList ) > 0 )
00645         {
00646             if ( count( $sortList ) > 1 and !is_array( $sortList[0] ) )
00647             {
00648                 $sortList = array( $sortList );
00649             }
00650 
00651             $sortingFields      = '';
00652             $sortCount          = 0;
00653             $attributeJoinCount = 0;
00654             $attributeFromSQL   = "";
00655             $attributeWhereSQL  = "";
00656             $datatypeSortingTargetSQL = "";
00657 
00658             foreach ( $sortList as $sortBy )
00659             {
00660                 if ( is_array( $sortBy ) and count( $sortBy ) > 0 )
00661                 {
00662                     if ( $sortCount > 0 )
00663                     {
00664                         $sortingFields .= ', ';
00665                     }
00666 
00667                     $sortField = $sortBy[0];
00668                     switch ( $sortField )
00669                     {
00670                         case 'path':
00671                         {
00672                             $sortingFields .= 'path_string';
00673                         } break;
00674                         case 'path_string':
00675                         {
00676                             $sortingFields .= 'path_identification_string';
00677                         } break;
00678                         case 'published':
00679                         {
00680                             $sortingFields .= 'ezcontentobject.published';
00681                         } break;
00682                         case 'modified':
00683                         {
00684                             $sortingFields .= 'ezcontentobject.modified';
00685                         } break;
00686                         case 'modified_subnode':
00687                         {
00688                             $sortingFields .= 'modified_subnode';
00689                         } break;
00690                         case 'section':
00691                         {
00692                             $sortingFields .= 'ezcontentobject.section_id';
00693                         } break;
00694                         case 'depth':
00695                         {
00696                             $sortingFields .= 'depth';
00697                         } break;
00698                         case 'class_identifier':
00699                         {
00700                             $sortingFields .= 'ezcontentclass.identifier';
00701                         } break;
00702                         case 'class_name':
00703                         {
00704                             $classNameFilter = eZContentClassName::sqlFilter();
00705                             $sortingFields .= 'contentclass_name';
00706                             $datatypeSortingTargetSQL .= ", $classNameFilter[nameField] AS contentclass_name";
00707                             $attributeFromSQL .= ", $classNameFilter[from]";
00708                             $attributeWhereSQL .= "$classNameFilter[where] AND ";
00709                         } break;
00710                         case 'priority':
00711                         {
00712                             $sortingFields .= $treeTableName . '.priority';
00713                         } break;
00714                         case 'name':
00715                         {
00716                             $sortingFields .= 'ezcontentobject_name.name';
00717                         } break;
00718                         case 'attribute':
00719                         {
00720                             //include_once( 'kernel/classes/ezdatatype.php' );
00721 
00722                             $classAttributeID = $sortBy[2];
00723                             if ( !is_numeric( $classAttributeID ) )
00724                                 $classAttributeID = eZContentObjectTreeNode::classAttributeIDByIdentifier( $classAttributeID );
00725 
00726 
00727                             $contentAttributeTableAlias = "a$attributeJoinCount";
00728                             $datatypeFromSQL = "ezcontentobject_attribute $contentAttributeTableAlias";
00729                             $datatypeWhereSQL = "
00730                                    $contentAttributeTableAlias.contentobject_id = ezcontentobject.id AND
00731                                    $contentAttributeTableAlias.contentclassattribute_id = $classAttributeID AND
00732                                    $contentAttributeTableAlias.version = ezcontentobject_name.content_version AND";
00733                             $datatypeWhereSQL .= eZContentLanguage::sqlFilter( $contentAttributeTableAlias, 'ezcontentobject' );
00734 
00735                             $dataType = eZDataType::create( eZContentObjectTreeNode::dataTypeByClassAttributeID( $classAttributeID ) );
00736                             if( is_object( $dataType ) && $dataType->customSorting() )
00737                             {
00738                                 $params = array();
00739                                 $params['contentobject_attr_id'] = "$contentAttributeTableAlias.id";
00740                                 $params['contentobject_attr_version'] = "$contentAttributeTableAlias.version";
00741                                 $params['table_alias_suffix'] = "$attributeJoinCount";
00742 
00743                                 $sql = $dataType->customSortingSQL( $params );
00744 
00745                                 $datatypeFromSQL .= ", {$sql['from']}";
00746                                 $datatypeWhereSQL .= " AND {$sql['where']}";
00747                                 $datatypeSortingFieldSQL = $sql['sorting_field'];
00748                                 $datatypeSortingTargetSQL .= ', ' . $sql['sorting_field'];
00749                             }
00750                             else
00751                             {
00752                                 // Look up datatype for standard sorting
00753                                 $sortKeyType = eZContentObjectTreeNode::sortKeyByClassAttributeID( $classAttributeID );
00754                                 switch ( $sortKeyType )
00755                                 {
00756                                     case 'string':
00757                                         {
00758                                             $sortKey = 'sort_key_string';
00759                                         } break;
00760 
00761                                     case 'int':
00762                                     default:
00763                                         {
00764                                             $sortKey = 'sort_key_int';
00765                                         } break;
00766                                 }
00767 
00768                                 $datatypeSortingFieldSQL = "a$attributeJoinCount.$sortKey";
00769                                 $datatypeSortingTargetSQL .= ', ' . $datatypeSortingFieldSQL;
00770                             }
00771 
00772                             $sortingFields .= "$datatypeSortingFieldSQL";
00773                             $attributeFromSQL .= ", $datatypeFromSQL";
00774                             $attributeWhereSQL .= "$datatypeWhereSQL AND ";
00775 
00776                             $attributeJoinCount++;
00777                         }break;
00778 
00779                         default:
00780                         {
00781                             if ( $allowCustomColumns )
00782                             {
00783                                 $sortingFields .= $sortField;
00784                             }
00785                             else
00786                             {
00787                                 eZDebug::writeWarning( 'Unknown sort field: ' . $sortField, 'eZContentObjectTreeNode::createSortingSQLStrings' );
00788                                 continue;
00789                             }
00790                         };
00791                     }
00792                     $sortOrder = true; // true is ascending
00793                     if ( isset( $sortBy[1] ) )
00794                         $sortOrder = $sortBy[1];
00795                     $sortingFields .= $sortOrder ? " ASC" : " DESC";
00796                     ++$sortCount;
00797                 }
00798             }
00799 
00800             $sortingInfo['sortCount']           = $sortCount;
00801             $sortingInfo['sortingFields']       = $sortingFields;
00802             $sortingInfo['attributeTargetSQL'] = $datatypeSortingTargetSQL;
00803             $sortingInfo['attributeJoinCount']  = $attributeJoinCount;
00804             $sortingInfo['attributeFromSQL']    = $attributeFromSQL;
00805             $sortingInfo['attributeWhereSQL']   = $attributeWhereSQL;
00806         }
00807 
00808         return $sortingInfo;
00809     }
00810 
00811     /*!
00812         \a static
00813     */
00814     static function createClassFilteringSQLString( $classFilterType, &$classFilterArray )
00815     {
00816         // Check for class filtering
00817         $classCondition = '';
00818 
00819         if ( isset( $classFilterType ) &&
00820              ( $classFilterType == 'include' || $classFilterType == 'exclude' ) &&
00821              count( $classFilterArray ) > 0 )
00822         {
00823             $classCondition = '  ';
00824             $i = 0;
00825             $classCount = count( $classFilterArray );
00826             $classIDArray = array();
00827             foreach ( $classFilterArray as $classID )
00828             {
00829                 $originalClassID = $classID;
00830                 // Check if classes are recerenced by identifier
00831                 if ( is_string( $classID ) && !is_numeric( $classID ) )
00832                 {
00833                     $classID = eZContentObjectTreeNode::classIDByIdentifier( $classID );
00834                 }
00835                 if ( is_numeric( $classID ) )
00836                 {
00837                     $classIDArray[] = $classID;
00838                 }
00839                 else
00840                 {
00841                     eZDebugSetting::writeWarning( 'kernel-content-class', "Invalid class identifier in subTree() classfilterarray, classID : " . $originalClassID );
00842                 }
00843             }
00844 
00845             if ( count( $classIDArray ) > 0  )
00846             {
00847                 $classCondition .= " ezcontentobject.contentclass_id ";
00848                 if ( $classFilterType == 'include' )
00849                     $classCondition .= " IN ";
00850                 else
00851                     $classCondition .= " NOT IN ";
00852 
00853                 $classIDString =  implode( ', ', $classIDArray );
00854                 $classCondition .= ' ( ' . $classIDString . ' ) AND';
00855             }
00856             else
00857             {
00858                 if ( count( $classIDArray ) == 0 and count( $classFilterArray ) > 0 and $classFilterType == 'include' )
00859                 {
00860                     $classCondition = false;
00861                 }
00862             }
00863         }
00864 
00865         return $classCondition;
00866     }
00867 
00868     /*!
00869         \a static
00870     */
00871     static function createExtendedAttributeFilterSQLStrings( &$extendedAttributeFilter )
00872     {
00873         $filter = array( 'tables'   => '',
00874                          'joins'    => '',
00875                          'columns'  => '' );
00876 
00877         if ( $extendedAttributeFilter and count( $extendedAttributeFilter ) > 1 )
00878         {
00879             $extendedAttributeFilterID      = $extendedAttributeFilter['id'];
00880             $extendedAttributeFilterParams  = $extendedAttributeFilter['params'];
00881             $filterINI                      = eZINI::instance( 'extendedattributefilter.ini' );
00882 
00883             $filterClassName    = $filterINI->variable( $extendedAttributeFilterID, 'ClassName' );
00884             $filterMethodName   = $filterINI->variable( $extendedAttributeFilterID, 'MethodName' );
00885             $filterFile         = $filterINI->variable( $extendedAttributeFilterID, 'FileName' );
00886 
00887             if ( $filterINI->hasVariable( $extendedAttributeFilterID, 'ExtensionName' ) )
00888             {
00889                 //include_once( 'lib/ezutils/classes/ezextension.php' );
00890                 $extensionName = $filterINI->variable( $extendedAttributeFilterID, 'ExtensionName' );
00891                 ext_activate( $extensionName, $filterFile );
00892             }
00893             else
00894             {
00895                 include_once( $filterFile );
00896             }
00897 
00898             $classObject        = new $filterClassName();
00899             $parameterArray     = array( $extendedAttributeFilterParams );
00900 
00901             $sqlResult          = call_user_func_array( array( $classObject, $filterMethodName ), $parameterArray );
00902 
00903             $filter['tables']   = $sqlResult['tables'];
00904             $filter['joins']    = $sqlResult['joins'];
00905             $filter['columns']  = $sqlResult['columns'];
00906 
00907         }
00908 
00909         return $filter;
00910     }
00911 
00912     /*!
00913         \a static
00914     */
00915     static function createMainNodeConditionSQLString( $mainNodeOnly )
00916     {
00917         // Main node check
00918         $mainNodeCondition = '';
00919         if ( isset( $mainNodeOnly ) && $mainNodeOnly === true )
00920         {
00921             $mainNodeCondition = 'ezcontentobject_tree.node_id = ezcontentobject_tree.main_node_id AND';
00922         }
00923 
00924         return $mainNodeCondition;
00925     }
00926 
00927     /*!
00928         \a static
00929     */
00930     static function createObjectNameFilterConditionSQLString( $filter )
00931     {
00932         if ( !$filter )
00933             return '';
00934 
00935         $db = eZDB::instance();
00936         if ( $filter == 'others' )
00937         {
00938             //include_once('kernel/common/ezalphabetoperator.php');
00939             $alphabet = eZAlphabetOperator::fetchAlphabet();
00940             $sql = '';
00941             foreach ( $alphabet as $letter )
00942             {
00943                 $sql .= " AND ezcontentobject.name NOT LIKE '". $db->escapeString( $letter ) . "%'\n";
00944             }
00945             return $sql;
00946         }
00947         $objectNameFilterSQL =  " AND ezcontentobject.name LIKE '" . $db->escapeString( $filter ) ."%'";
00948         return $objectNameFilterSQL;
00949     }
00950 
00951 
00952     /*!
00953         \a static
00954     */
00955     static function createAttributeFilterSQLStrings( &$attributeFilter, &$sortingInfo )
00956     {
00957         // Check for attribute filtering
00958 
00959         $filterSQL = array( 'from'    => '',
00960                             'where'   => '' );
00961 
00962         $invalidFilterSQL = false;
00963         $totalAttributesFiltersCount = 0;
00964         $invalidAttributesFiltersCount = 0;
00965 
00966         if ( isset( $attributeFilter ) && $attributeFilter !== false )
00967         {
00968             if ( !is_array( $attributeFilter ) )
00969             {
00970                 eZDebug::writeError( "\$attributeFilter needs to be an array", __METHOD__  );
00971                 return $filterSQL;
00972             }
00973 
00974             $filterArray = $attributeFilter;
00975 
00976             // Check if first value of array is a string.
00977             // To check for and/or filtering
00978             $filterJoinType = 'AND';
00979             if ( is_string( $filterArray[0] ) )
00980             {
00981                 if ( strtolower( $filterArray[0] ) == 'or' )
00982                 {
00983                     $filterJoinType = 'OR';
00984                 }
00985                 else if ( strtolower( $filterArray[0] ) == 'and' )
00986                 {
00987                     $filterJoinType = 'AND';
00988                 }
00989                 unset( $filterArray[0] );
00990             }
00991 
00992             $attibuteFilterJoinSQL = "";
00993             $filterCount = $sortingInfo['sortCount'];
00994             $justFilterCount = 0;
00995 
00996             $db = eZDB::instance();
00997             if ( is_array( $filterArray ) )
00998             {
00999                 // Handle attribute filters and generate SQL
01000                 $totalAttributesFiltersCount = count( $filterArray );
01001 
01002                 foreach ( $filterArray as $filter )
01003                 {
01004                     $isFilterValid = true; // by default assumes that filter is valid
01005 
01006                     $filterAttributeID = $filter[0];
01007                     $filterType = $filter[1];
01008                     $filterValue = is_array( $filter[2] ) ? '' : $db->escapeString( $filter[2] );
01009 
01010                     $useAttributeFilter = false;
01011                     switch ( $filterAttributeID )
01012                     {
01013                         case 'path':
01014                         {
01015                             $filterField = 'path_string';
01016                         } break;
01017                         case 'published':
01018                         {
01019                             $filterField = 'ezcontentobject.published';
01020                         } break;
01021                         case 'modified':
01022                         {
01023                             $filterField = 'ezcontentobject.modified';
01024                         } break;
01025                         case 'modified_subnode':
01026                         {
01027                             $filterField = 'modified_subnode';
01028                         } break;
01029                         case 'section':
01030                         {
01031                             $filterField = 'ezcontentobject.section_id';
01032                         } break;
01033                         case 'depth':
01034                         {
01035                             $filterField = 'depth';
01036                         } break;
01037                         case 'class_identifier':
01038                         {
01039                             $filterField = 'ezcontentclass.identifier';
01040                         } break;
01041                         case 'class_name':
01042                         {
01043                             $classNameFilter = eZContentClassName::sqlFilter();
01044                             $filterField = $classNameFilter['nameField'];
01045                             $filterSQL['from'] .= ", $classNameFilter[from]";
01046                             $filterSQL['where'] .= "$classNameFilter[where] AND ";
01047                         } break;
01048                         case 'priority':
01049                         {
01050                             $filterField = 'ezcontentobject_tree.priority';
01051                         } break;
01052                         case 'name':
01053                         {
01054                             $filterField = 'ezcontentobject_name.name';
01055                         } break;
01056                         case 'owner':
01057                         {
01058                             $filterField = 'ezcontentobject.owner_id';
01059                         } break;
01060                         default:
01061                         {
01062                             $useAttributeFilter = true;
01063                         } break;
01064                     }
01065 
01066                     if ( $useAttributeFilter )
01067                     {
01068                         if ( !is_numeric( $filterAttributeID ) )
01069                             $filterAttributeID = eZContentObjectTreeNode::classAttributeIDByIdentifier( $filterAttributeID );
01070 
01071                         if ( $filterAttributeID === false )
01072                         {
01073                             $isFilterValid = false;
01074                             if( $filterJoinType === 'AND' )
01075                             {
01076                                 // go out
01077                                 $invalidAttributesFiltersCount = $totalAttributesFiltersCount;
01078                                 break;
01079                             }
01080 
01081                             ++$invalidAttributesFiltersCount;
01082                         }
01083                         else
01084                         {
01085                             // Check datatype for filtering
01086                             $filterDataType = eZContentObjectTreeNode::sortKeyByClassAttributeID( $filterAttributeID );
01087                             if ( $filterDataType === false )
01088                             {
01089                                 $isFilterValid = false;
01090                                 if( $filterJoinType === 'AND' )
01091                                 {
01092                                     // go out
01093                                     $invalidAttributesFiltersCount = $totalAttributesFiltersCount;
01094                                     break;
01095                                 }
01096 
01097                                 // check next filter
01098                                 ++$invalidAttributesFiltersCount;
01099                             }
01100                             else
01101                             {
01102                                 $sortKey = false;
01103                                 if ( $filterDataType == 'string' )
01104                                 {
01105                                     $sortKey = 'sort_key_string';
01106                                 }
01107                                 else
01108                                 {
01109                                     $sortKey = 'sort_key_int';
01110                                 }
01111 
01112                                 $filterField = "a$filterCount.$sortKey";
01113 
01114                                 // Use the same joins as we do when sorting,
01115                                 // if more attributes are filtered by we will append them
01116                                 if ( $filterCount >= $sortingInfo['attributeJoinCount'] )
01117                                 {
01118                                     $filterSQL['from']  .= ", ezcontentobject_attribute a$filterCount ";
01119                                     $filterSQL['where'] .= "
01120                                        a$filterCount.contentobject_id = ezcontentobject.id AND
01121                                        a$filterCount.contentclassattribute_id = $filterAttributeID AND
01122                                        a$filterCount.version = ezcontentobject_name.content_version AND ";
01123                                     $filterSQL['where'] .= eZContentLanguage::sqlFilter( "a$filterCount", 'ezcontentobject' ).' AND ';
01124                                 }
01125                                 else
01126                                 {
01127                                     $filterSQL['where'] .= "
01128                                       a$filterCount.contentobject_id = ezcontentobject.id AND
01129                                       a$filterCount.contentclassattribute_id = $filterAttributeID AND
01130                                       a$filterCount.version = ezcontentobject_name.content_version AND ";
01131                                     $filterSQL['where'] .= eZContentLanguage::sqlFilter( "a$filterCount", 'ezcontentobject' ). ' AND ';
01132                                 }
01133                             }
01134                         }
01135                     }
01136 
01137                     if( $isFilterValid )
01138                     {
01139                         $hasFilterOperator = true;
01140                         // Controls quotes around filter value, some filters do this manually
01141                         $noQuotes = false;
01142                         // Controls if $filterValue or $folder[2] is used, $filterValue is already escaped
01143                         $unEscape = false;
01144 
01145                         switch ( $filterType )
01146                         {
01147                             case '=' :
01148                             {
01149                                 $filterOperator = '=';
01150                             }break;
01151 
01152                             case '!=' :
01153                             {
01154                                 $filterOperator = '<>';
01155                             }break;
01156 
01157                             case '>' :
01158                             {
01159                                 $filterOperator = '>';
01160                             }break;
01161 
01162                             case '<' :
01163                             {
01164                                 $filterOperator = '<';
01165                             }break;
01166 
01167                             case '<=' :
01168                             {
01169                                 $filterOperator = '<=';
01170                             }break;
01171 
01172                             case '>=' :
01173                             {
01174                                 $filterOperator = '>=';
01175                             }break;
01176 
01177                             case 'like':
01178                             case 'not_like':
01179                             {
01180                                 $filterOperator = ( $filterType == 'like' ? 'LIKE' : 'NOT LIKE' );
01181                                 // We escape the string ourselves, this MUST be done before wildcard replace
01182                                 $filter[2] = $db->escapeString( $filter[2] );
01183                                 $unEscape = true;
01184                                 // Since * is used as wildcard we need to transform the string to
01185                                 // use % as wildcard. The following rules apply:
01186                                 // - % -> \%
01187                                 // - * -> %
01188                                 // - \* -> *
01189                                 // - \\ -> \
01190 
01191                                 $filter[2] = preg_replace( array( '#%#m',
01192                                                                   '#(?<!\\\\)\\*#m',
01193                                                                   '#(?<!\\\\)\\\\\\*#m',
01194                                                                   '#\\\\\\\\#m' ),
01195                                                            array( '\\%',
01196                                                                   '%',
01197                                                                   '*',
01198                                                                   '\\\\' ),
01199                                                            $filter[2] );
01200                             } break;
01201 
01202                             case 'in':
01203                             case 'not_in' :
01204                             {
01205                                 $filterOperator = ( $filterType == 'in' ? 'IN' : 'NOT IN' );
01206                                 // Turn off quotes for value, we do this ourselves
01207                                 $noQuotes = true;
01208                                 if ( is_array( $filter[2] ) )
01209                                 {
01210                                     reset( $filter[2] );
01211                                     while ( list( $key, $value ) = each( $filter[2] ) )
01212                                     {
01213                                         // Non-numerics must be escaped to avoid SQL injection
01214                                         $filter[2][$key] = is_numeric( $value ) ? $value : "'" . $db->escapeString( $value ) . "'";
01215                                     }
01216                                     $filterValue = '(' .  implode( ",", $filter[2] ) . ')';
01217                                 }
01218                                 else
01219                                 {
01220                                     $hasFilterOperator = false;
01221                                 }
01222                             } break;
01223 
01224                             case 'between':
01225                             case 'not_between' :
01226                             {
01227                                 $filterOperator = ( $filterType == 'between' ? 'BETWEEN' : 'NOT BETWEEN' );
01228                                 // Turn off quotes for value, we do this ourselves
01229                                 $noQuotes = true;
01230                                 if ( is_array( $filter[2] ) )
01231                                 {
01232                                     // Check for non-numerics to avoid SQL injection
01233                                     if ( !is_numeric( $filter[2][0] ) )
01234                                         $filter[2][0] = "'" . $db->escapeString( $filter[2][0] ) . "'";
01235                                     if ( !is_numeric( $filter[2][1] ) )
01236                                         $filter[2][1] = "'" . $db->escapeString( $filter[2][1] ) . "'";
01237 
01238                                     $filterValue = $filter[2][0] . ' AND ' . $filter[2][1];
01239                                 }
01240                             } break;
01241 
01242                             default :
01243                             {
01244                                 $hasFilterOperator = false;
01245                                 eZDebug::writeError( "Unknown attribute filter type: $filterType", "eZContentObjectTreeNode::subTree()" );
01246                             }break;
01247 
01248                         }
01249                         if ( $hasFilterOperator )
01250                         {
01251                             if ( ( $filterCount - $sortingInfo['sortCount'] ) > 0 )
01252                                 $attibuteFilterJoinSQL .= " $filterJoinType ";
01253 
01254                             // If $unEscape is true we get the filter value from the 2nd element instead
01255                             // which must have been escaped by filter type
01256                             $filterValue = $unEscape ? $filter[2] : $filterValue;
01257 
01258                             $attibuteFilterJoinSQL .= "$filterField $filterOperator ";
01259                             $attibuteFilterJoinSQL .= $noQuotes ? "$filterValue " : "'" . $filterValue . "' ";
01260 
01261                             $filterCount++;
01262                             $justFilterCount++;
01263                         }
01264                     }
01265                 } // end of 'foreach ( $filterArray as $filter )'
01266 
01267                 if( $totalAttributesFiltersCount == $invalidAttributesFiltersCount )
01268                 {
01269                     eZDebug::writeNotice( "Attribute filter returned false" );
01270                     $filterSQL = $invalidFilterSQL;
01271                 }
01272                 else
01273                 {
01274                     if ( $justFilterCount > 0 )
01275                         $filterSQL['where'] .= "\n                            ( " . $attibuteFilterJoinSQL . " ) AND ";
01276                 }
01277             } // endif 'if ( is_array( $filterArray ) )'
01278         }
01279 
01280         return $filterSQL;
01281     }
01282 
01283     /*!
01284         \a static
01285     */
01286     static function createNotEqParentSQLString( $nodeID, $depth = false, $depthOperator = 'le' )
01287     {
01288         $notEqParentString  = '';
01289         if( !$depth || $depthOperator == 'le' || $depthOperator == 'lt' )
01290         {
01291             $notEqParentString  = "ezcontentobject_tree.node_id != $nodeID AND";
01292         }
01293 
01294         return $notEqParentString;
01295     }
01296 
01297     /*!
01298         \a static
01299     */
01300     static function createPathConditionSQLString( $nodePath, $nodeDepth, $depth = false, $depthOperator = 'le' )
01301     {
01302         $pathCondition  = '';
01303         $depthCondition = '';
01304 
01305         if ( $depth )
01306         {
01307             $sqlDepthOperator = '<=';
01308             if ( $depthOperator )
01309             {
01310                 if ( $depthOperator == 'lt' )
01311                 {
01312                     $sqlDepthOperator = '<';
01313                 }
01314                 else if ( $depthOperator == 'gt' )
01315                 {
01316                     $sqlDepthOperator = '>';
01317                 }
01318                 else if ( $depthOperator == 'le' )
01319                 {
01320                     $sqlDepthOperator = '<=';
01321                 }
01322                 else if ( $depthOperator == 'ge' )
01323                 {
01324                     $sqlDepthOperator = '>=';
01325                 }
01326                 else if ( $depthOperator == 'eq' )
01327                 {
01328                     $sqlDepthOperator = '=';
01329                 }
01330             }
01331 
01332             $nodeDepth += $depth;
01333             $depthCondition = ' ezcontentobject_tree.depth '. $sqlDepthOperator . ' ' . $nodeDepth . '  and ';
01334         }
01335 
01336         $pathCondition = " ezcontentobject_tree.path_string like '$nodePath%' and $depthCondition ";
01337         return $pathCondition;
01338     }
01339 
01340     /*!
01341         \a static
01342     */
01343     static function createPathConditionAndNotEqParentSQLStrings( &$outPathConditionStr, &$outNotEqParentStr, $nodeID, $depth = false, $depthOperator = 'le' )
01344     {
01345         if ( !$depthOperator )
01346         {
01347             $depthOperator = 'le';
01348         }
01349 
01350         // check if we are only fetching children
01351         // - depth (lower than or) eqaul to 1
01352         // - depth lower than 2 = depth equal to 1
01353         $onlyChildren = ( $depth === 1 && ( $depthOperator === 'le' || $depthOperator === 'eq'  ) ) ||
01354                         ( $depth === 2 && $depthOperator === 'lt' );
01355 
01356         if ( is_array( $nodeID ) && count( $nodeID ) == 1 )
01357         {
01358             $nodeID = $nodeID[0];
01359         }
01360 
01361         if ( is_array( $nodeID ) )
01362         {
01363             $outNotEqParentStr = '';
01364 
01365             // a parent_node_id condition suffits when only fetching children
01366             if ( $onlyChildren )
01367             {
01368                 $db = eZDB::instance();
01369                 $outPathConditionStr = $db->generateSQLINStatement( $nodeID, 'ezcontentobject_tree.parent_node_id', false, true, 'int' ) . ' and';
01370             }
01371             else
01372             {
01373                 $nodeIDList             = $nodeID;
01374                 $sqlPartForOneNodeList  = array();
01375 
01376                 foreach ( $nodeIDList as $nodeID )
01377                 {
01378                     $node           = eZContentObjectTreeNode::fetch( $nodeID, false, false );
01379                     if ( !is_array( $node ) )
01380                         return false;
01381 
01382                     $nodePath       = $node['path_string'];
01383                     $nodeDepth      = $node['depth'];
01384                     $depthCond      = '';
01385                     if ( $depth )
01386                     {
01387                         $sqlDepthOperator = '<=';
01388                         if ( $depthOperator )
01389                         {
01390                             if ( $depthOperator == 'lt' )
01391                             {
01392                                 $sqlDepthOperator = '<';
01393                             }
01394                             else if ( $depthOperator == 'gt' )
01395                             {
01396                                 $sqlDepthOperator = '>';
01397                             }
01398                             else if ( $depthOperator == 'le' )
01399                             {
01400                                 $sqlDepthOperator = '<=';
01401                             }
01402                             else if ( $depthOperator == 'ge' )
01403                             {
01404                                 $sqlDepthOperator = '>=';
01405                             }
01406                             else if ( $depthOperator == 'eq' )
01407                             {
01408                                 $sqlDepthOperator = '=';
01409                             }
01410                         }
01411                         $nodeDepth += $depth;
01412                         $depthCond = ' and ezcontentobject_tree.depth '. $sqlDepthOperator . ' ' . $nodeDepth . ' ';
01413                     }
01414 
01415                     $requireNotEqParentStr      = !$depth || $depthOperator == 'le' || $depthOperator == 'lt';
01416                     $notEqParentStr             = $requireNotEqParentStr ? " and ezcontentobject_tree.node_id != $nodeID " : '';
01417                     $sqlPartForOneNodeList[]    = " ( ezcontentobject_tree.path_string like '$nodePath%'   $depthCond $notEqParentStr ) ";
01418                 }
01419                 $outPathConditionStr = implode( ' or ', $sqlPartForOneNodeList );
01420                 $outPathConditionStr = ' (' . $outPathConditionStr . ') and';
01421             }
01422         }
01423         else
01424         {
01425             if ( $nodeID == 0 )
01426             {
01427                 return false;
01428             }
01429 
01430             // a parent_node_id condition suffits when only fetching children
01431             if ( $onlyChildren )
01432             {
01433                 $outNotEqParentStr = '';
01434                 $outPathConditionStr = 'ezcontentobject_tree.parent_node_id = ' . (int) $nodeID . ' and';
01435             }
01436             else
01437             {
01438                 $node = eZContentObjectTreeNode::fetch( $nodeID, false, false );
01439                 if ( !is_array( $node ) )
01440                     return false;
01441 
01442                 $nodePath   = $node['path_string'];
01443                 $nodeDepth  = $node['depth'];
01444 
01445                 $outNotEqParentStr   = eZContentObjectTreeNode::createNotEqParentSQLString( $nodeID, $depth, $depthOperator );
01446                 $outPathConditionStr = eZContentObjectTreeNode::createPathConditionSQLString( $nodePath, $nodeDepth, $depth, $depthOperator );
01447             }
01448         }
01449 
01450         return true;
01451     }
01452 
01453     /*!
01454         \a static
01455     */
01456     static function createGroupBySQLStrings( &$outGroupBySelectText, &$outGroupByText, $groupBy )
01457     {
01458         if ( $groupBy )
01459         {
01460             if ( isset( $groupBy['field'] ) and isset( $groupBy['type'] ) )
01461             {
01462                 $groupByField       = $groupBy['field'];
01463                 $groupByFieldType   = $groupBy['type'];
01464 
01465                 switch ( $groupByField )
01466                 {
01467                     case 'published':
01468                     {
01469                         $groupBySelect = eZContentObjectTreeNode::subTreeGroupByDateField( "ezcontentobject." . $groupByField, $groupByFieldType );
01470                         $groupBySelect['field'] = "ezcontentobject." . $groupByField;
01471                     } break;
01472                     case 'modified':
01473                     {
01474                         $groupBySelect = eZContentObjectTreeNode::subTreeGroupByDateField( "ezcontentobject." . $groupByField, $groupByFieldType );
01475                         $groupBySelect['field'] = "ezcontentobject." . $groupByField;
01476                     } break;
01477                 }
01478 
01479                 $outGroupBySelectText = ", " . $groupBySelect['select'];
01480                 $outGroupByText = "GROUP BY " . $groupBySelect['group_field'];
01481             }
01482         }
01483     }
01484 
01485     /*!
01486         \a static
01487     */
01488     static function createVersionNameTablesSQLString( $useVersionName )
01489     {
01490         $versionNameTables = '';
01491 
01492         if ( $useVersionName )
01493         {
01494             $versionNameTables = ', ezcontentobject_name ';
01495         }
01496 
01497         return $versionNameTables;
01498     }
01499 
01500     /*!
01501         \a static
01502     */
01503     static function createVersionNameTargetsSQLString( $useVersionName )
01504     {
01505         $versionNameTargets = '';
01506 
01507         if ( $useVersionName )
01508         {
01509             $versionNameTargets = ', ezcontentobject_name.name as name,  ezcontentobject_name.real_translation ';
01510         }
01511 
01512 
01513         return $versionNameTargets;
01514     }
01515 
01516     /*!
01517         \a static
01518     */
01519     static function createVersionNameJoinsSQLString( $useVersionName, $includeAnd = true, $onlyTranslated = false, $lang = false, $treeTableName = 'ezcontentobject_tree' )
01520     {
01521         $versionNameJoins = '';
01522         if ( $useVersionName )
01523         {
01524             if ( $includeAnd )
01525             {
01526                 $versionNameJoins .= ' AND ';
01527             }
01528             $versionNameJoins .= " $treeTableName.contentobject_id = ezcontentobject_name.contentobject_id and
01529                                    $treeTableName.contentobject_version = ezcontentobject_name.content_version and ";
01530             $versionNameJoins .= eZContentLanguage::sqlFilter( 'ezcontentobject_name', 'ezcontentobject' );
01531         }
01532         return $versionNameJoins;
01533     }
01534 
01535     /*!
01536         \a static
01537         Deprecated. Use 'createPermissionCheckingSQL' instead.
01538     */
01539     static function createPermissionCheckingSQLString( $limitationList )
01540     {
01541         $sqlPermissionChecking = eZContentObjectTreeNode::createPermissionCheckingSQL( $limitationList );
01542         return $sqlPermissionChecking['where'];
01543     }
01544 
01545     /*!
01546         \a static
01547     */
01548     static function createPermissionCheckingSQL( $limitationList, $treeTableName = 'ezcontentobject_tree', $tableAliasName = 'ezcontentobject_tree' )
01549     {
01550         $db = eZDB::instance();
01551 
01552         $sqlPermissionCheckingFrom = '';
01553         $sqlPermissionCheckingWhere = '';
01554         $sqlPermissionTempTables = array();
01555         $groupPermTempTable = false;
01556 
01557         if ( is_array( $limitationList ) && count( $limitationList ) > 0 )
01558         {
01559             $sqlParts = array();
01560             foreach( $limitationList as $limitationArray )
01561             {
01562                 $sqlPartPart = array();
01563                 $sqlPartPartPart = array();
01564                 $sqlPlacementPart = array();
01565 
01566                 $count = 1;
01567                 foreach ( array_keys( $limitationArray ) as $ident )
01568                 {
01569                     switch( $ident )
01570                     {
01571                         case 'Class':
01572                         {
01573                             $sqlPartPart[] = 'ezcontentobject.contentclass_id in (' . implode( ', ', $limitationArray[$ident] ) . ')';
01574                         } break;
01575 
01576                         case 'Section':
01577                         case 'User_Section':
01578                         {
01579                             $sqlPartPart[] = 'ezcontentobject.section_id in (' . implode( ', ', $limitationArray[$ident] ) . ')';
01580                         } break;
01581 
01582                         case 'Owner':
01583                         {
01584                             $user   = eZUser::currentUser();
01585                             $userID = $user->attribute( 'contentobject_id' );
01586                             $sqlPartPart[] = "ezcontentobject.owner_id = '" . $db->escapeString( $userID ) . "'";
01587                         } break;
01588 
01589                         case 'Group':
01590                         {
01591                             if ( !$groupPermTempTable )
01592                             {
01593                                 $user = eZUser::currentUser();
01594                                 $userContentObject = $user->attribute( 'contentobject' );
01595                                 $parentList = $userContentObject->attribute( 'parent_nodes' );
01596 
01597                                 $groupPermTempTable = $db->generateUniqueTempTableName( 'ezgroup_perm_tmp_%' );
01598                                 $sqlPermissionTempTables[] = $groupPermTempTable;
01599 
01600                                 $db->createTempTable( "CREATE TEMPORARY TABLE $groupPermTempTable ( user_id int )" );
01601                                 $db->query( "INSERT INTO $groupPermTempTable
01602                                                     SELECT DISTINCT contentobject_id AS user_id
01603                                                     FROM     ezcontentobject_tree
01604                                                     WHERE    parent_node_id IN ("  . implode( ', ', $parentList ) . ')',
01605                                             eZDBInterface::SERVER_SLAVE );
01606 
01607                                 $sqlPermissionCheckingFrom = ', ' . $groupPermTempTable;
01608                             }
01609                             $sqlPartPart[] = "ezcontentobject.owner_id = $groupPermTempTable.user_id";
01610                         } break;
01611 
01612                         case 'Node':
01613                         {
01614                             $sqlPlacementPart[] = $tableAliasName . '.node_id in (' . implode( ', ', $limitationArray[$ident] ) . ')';
01615                         } break;
01616 
01617                         case 'Subtree':
01618                         {
01619                             $sqlSubtreePart = array();
01620                             foreach ( $limitationArray[$ident] as $limitationPathString )
01621                             {
01622                                 $sqlSubtreePart[] = "$tableAliasName.path_string like '$limitationPathString%'";
01623                             }
01624                             $sqlPlacementPart[] = implode( ' OR ', $sqlSubtreePart );
01625                         } break;
01626 
01627                         case 'User_Subtree':
01628                         {
01629                             $sqlPartUserSubtree = array();
01630                             foreach ( $limitationArray[$ident] as $limitationPathString )
01631                             {
01632                                 $sqlPartUserSubtree[] = "$tableAliasName.path_string like '$limitationPathString%'";
01633                             }
01634                             $sqlPartPart[] = implode( ' OR ', $sqlPartUserSubtree );
01635                         }
01636                     }
01637 
01638                     $count++;
01639                 }
01640                 if ( $sqlPlacementPart )
01641                 {
01642                     $sqlPartPart[] = '( ( ' . implode( ' ) OR ( ', $sqlPlacementPart ) . ' ) )';
01643                 }
01644                 if ( $sqlPartPartPart )
01645                 {
01646                     $sqlPartPart[] = '( ' . implode( ' ) OR ( ', $sqlPartPartPart ) . ' )';
01647                 }
01648                 $sqlParts[] = implode( ' AND ', $sqlPartPart );
01649             }
01650             $sqlPermissionCheckingWhere = ' AND ((' . implode( ') OR (', $sqlParts ) . ')) ';
01651         }
01652 
01653         $sqlPermissionChecking = array( 'from' => $sqlPermissionCheckingFrom,
01654                                         'where' => $sqlPermissionCheckingWhere,
01655                                         'temp_tables' => $sqlPermissionTempTables );
01656 
01657         return $sqlPermissionChecking;
01658     }
01659 
01660 
01661     /*!
01662         \a static
01663 
01664         \param $limit maximum number of nodes in the path to use, starting from last node
01665     */
01666     static function createNodesConditionSQLStringFromPath( $nodePath, $includingLastNodeInThePath, $limit = false )
01667     {
01668         $pathString = false;
01669         $pathArray  = explode( '/', trim( $nodePath, '/' ) );
01670 
01671         $pathArrayCount = count( $pathArray );
01672 
01673         if ( $limit && $includingLastNodeInThePath == false )
01674         {
01675             $limit++;
01676         }
01677 
01678         $sliceOffset = $limit && $pathArrayCount > $limit ? $pathArrayCount - $limit : 0;
01679         $sliceLength = $includingLastNodeInThePath ? $pathArrayCount - $sliceOffset : $pathArrayCount - ( $sliceOffset + 1 );
01680 
01681         // only take a slice when necessary
01682         if ( ( $sliceOffset + $sliceLength ) < $pathArrayCount )
01683         {
01684             $pathArray = array_slice( $pathArray, $sliceOffset, $sliceLength );
01685         }
01686 
01687         if ( $sliceLength == 1 )
01688         {
01689             $pathString = ' node_id = ' . implode( '', $pathArray ) . ' and ';
01690         }
01691         else if ( $sliceLength > 0 )
01692         {
01693             $db = eZDB::instance();
01694             $pathString = ' ' . $db->generateSQLInStatement( $pathArray, 'node_id' ) . ' and ';
01695         }
01696 
01697         return $pathString;
01698     }
01699 
01700     /*!
01701         \a static
01702         If \a $useSettings is true \a $fetchHidden will be ignored.
01703         If \a $useSettings is false \a $fetchHidden will be used.
01704     */
01705     static function createShowInvisibleSQLString( $useSettings, $fetchHidden = true )
01706     {
01707         $showInvisibleNodesCond = '';
01708         $showInvisible          = $fetchHidden;
01709 
01710         if ( $useSettings )
01711             $showInvisible = eZContentObjectTreeNode::showInvisibleNodes();
01712 
01713         if ( !$showInvisible )
01714             $showInvisibleNodesCond = 'AND ezcontentobject_tree.is_invisible = 0';
01715 
01716         return $showInvisibleNodesCond;
01717     }
01718 
01719     /*!
01720      \a static
01721      \returns true if we should show invisible nodes (determined by ini setting), false otherwise.
01722     */
01723     static function showInvisibleNodes()
01724     {
01725         static $cachedResult;
01726 
01727         if ( !isset( $cachedResult ) )
01728         {
01729             $ini = eZINI::instance( 'site.ini' );
01730             $cachedResult = $ini->hasVariable( 'SiteAccessSettings', 'ShowHiddenNodes' ) ?
01731                             $ini->variable( 'SiteAccessSettings', 'ShowHiddenNodes' ) == 'true' :
01732                             true;
01733         }
01734 
01735         return $cachedResult;
01736     }
01737 
01738     /*!
01739         \a static
01740     */
01741     static function getLimitationList( &$limitation )
01742     {
01743         //include_once( "kernel/classes/datatypes/ezuser/ezuser.php" );
01744         $currentUser = eZUser::currentUser();
01745         $currentUserID = $currentUser->attribute( 'contentobject_id' );
01746         $limitationList = array();
01747 
01748         if ( $limitation !== false )
01749         {
01750             $limitationList = $limitation;
01751         }
01752         else if ( isset( $GLOBALS['ezpolicylimitation_list'][$currentUserID]['content']['read'] ) )
01753         {
01754             $limitationList =& $GLOBALS['ezpolicylimitation_list'][$currentUserID]['content']['read'];
01755             eZDebugSetting::writeDebug( 'kernel-content-treenode', $limitationList, "limitation list"  );
01756         }
01757         else
01758         {
01759             $accessResult = $currentUser->hasAccessTo( 'content', 'read' );
01760 
01761             if ( $accessResult['accessWord'] == 'no' )
01762             {
01763                 $limitationList = false;
01764                 $GLOBALS['ezpolicylimitation_list'][$currentUserID]['content']['read'] = false;
01765             }
01766             else if ( $accessResult['accessWord'] == 'limited' )
01767             {
01768                 $limitationList = $accessResult['policies'];
01769                 $GLOBALS['ezpolicylimitation_list'][$currentUserID]['content']['read'] = $accessResult['policies'];
01770             }
01771         }
01772 
01773         return $limitationList;
01774     }
01775 
01776     /*!
01777      \sa subTree
01778     */
01779     static function subTreeByNodeID( $params = false, $nodeID = 0 )
01780     {
01781         if ( !is_numeric( $nodeID ) and !is_array( $nodeID ) )
01782         {
01783             return null;
01784         }
01785 
01786         if ( $params === false )
01787         {
01788             $params = array( 'Depth'                    => false,
01789                              'Offset'                   => false,
01790                              //'OnlyTranslated'           => false,
01791                              'Language'                 => false,
01792                              'Limit'                    => false,
01793                              'SortBy'                   => false,
01794                              'AttributeFilter'          => false,
01795                              'ExtendedAttributeFilter'  => false,
01796                              'ClassFilterType'          => false,
01797                              'ClassFilterArray'         => false,
01798                              'GroupBy'                  => false );
01799         }
01800 
01801         $offset           = ( isset( $params['Offset'] ) && is_numeric( $params['Offset'] ) ) ? $params['Offset']             : false;
01802         //$onlyTranslated   = ( isset( $params['OnlyTranslated']      ) )                       ? $params['OnlyTranslated']     : false;
01803         $language         = ( isset( $params['Language']      ) )                             ? $params['Language']           : false;
01804         $limit            = ( isset( $params['Limit']  ) && is_numeric( $params['Limit']  ) ) ? $params['Limit']              : false;
01805         $depth            = ( isset( $params['Depth']  ) && is_numeric( $params['Depth']  ) ) ? $params['Depth']              : false;
01806         $depthOperator    = ( isset( $params['DepthOperator']     ) )                         ? $params['DepthOperator']      : false;
01807         $asObject         = ( isset( $params['AsObject']          ) )                         ? $params['AsObject']           : true;
01808         $loadDataMap      = ( isset( $params['LoadDataMap'] ) )                               ? $params['LoadDataMap']        : false;
01809         $groupBy          = ( isset( $params['GroupBy']           ) )                         ? $params['GroupBy']            : false;
01810         $mainNodeOnly     = ( isset( $params['MainNodeOnly']      ) )                         ? $params['MainNodeOnly']       : false;
01811         $ignoreVisibility = ( isset( $params['IgnoreVisibility']  ) )                         ? $params['IgnoreVisibility']   : false;
01812         $objectNameFilter = ( isset( $params['ObjectNameFilter']  ) )                         ? $params['ObjectNameFilter']   : false;
01813 
01814         if ( $offset < 0 )
01815         {
01816             $offset = abs( $offset );
01817         }
01818 
01819         if ( !isset( $params['SortBy'] ) )
01820             $params['SortBy'] = false;
01821         if ( !isset( $params['ClassFilterType'] ) )
01822             $params['ClassFilterType'] = false;
01823 
01824         $allowCustomSorting = false;
01825         if ( isset( $params['ExtendedAttributeFilter'] ) && is_array ( $params['ExtendedAttributeFilter'] ) )
01826         {
01827             $allowCustomSorting = true;
01828         }
01829 
01830         $sortingInfo             = eZContentObjectTreeNode::createSortingSQLStrings( $params['SortBy'], 'ezcontentobject_tree', $allowCustomSorting );
01831         $classCondition          = eZContentObjectTreeNode::createClassFilteringSQLString( $params['ClassFilterType'], $params['ClassFilterArray'] );
01832         if ( $classCondition === false )
01833         {
01834             eZDebug::writeNotice( "Class filter returned false" );
01835             return null;
01836         }
01837 
01838         $attributeFilter         = eZContentObjectTreeNode::createAttributeFilterSQLStrings( $params['AttributeFilter'], $sortingInfo );
01839         if ( $attributeFilter === false )
01840         {
01841             return null;
01842         }
01843         $extendedAttributeFilter = eZContentObjectTreeNode::createExtendedAttributeFilterSQLStrings( $params['ExtendedAttributeFilter'] );
01844         $mainNodeOnlyCond        = eZContentObjectTreeNode::createMainNodeConditionSQLString( $mainNodeOnly );
01845 
01846         $pathStringCond     = '';
01847         $notEqParentString  = '';
01848         // If the node(s) doesn't exist we return null.
01849         if ( !eZContentObjectTreeNode::createPathConditionAndNotEqParentSQLStrings( $pathStringCond, $notEqParentString, $nodeID, $depth, $depthOperator ) )
01850         {
01851             return null;
01852         }
01853 
01854         if ( $language )
01855         {
01856             if ( !is_array( $language ) )
01857             {
01858                 $language = array( $language );
01859             }
01860             // This call must occur after eZContentObjectTreeNode::createPathConditionAndNotEqParentSQLStrings,
01861             // because the parent node may not exist in Language
01862             eZContentLanguage::setPrioritizedLanguages( $language );
01863         }
01864 
01865         $groupBySelectText  = '';
01866         $groupByText        = '';
01867         eZContentObjectTreeNode::createGroupBySQLStrings( $groupBySelectText, $groupByText, $groupBy );
01868 
01869         $useVersionName     = true;
01870 
01871         $versionNameTables  = eZContentObjectTreeNode::createVersionNameTablesSQLString ( $useVersionName );
01872         $versionNameTargets = eZContentObjectTreeNode::createVersionNameTargetsSQLString( $useVersionName );
01873         $versionNameJoins   = eZContentObjectTreeNode::createVersionNameJoinsSQLString  ( $useVersionName, false );
01874 
01875         $languageFilter = ' AND ' . eZContentLanguage::languagesSQLFilter( 'ezcontentobject' );
01876 
01877         if ( $language )
01878         {
01879             eZContentLanguage::clearPrioritizedLanguages();
01880         }
01881         $objectNameFilterSQL = eZContentObjectTreeNode::createObjectNameFilterConditionSQLString( $objectNameFilter );
01882 
01883         $limitation = ( isset( $params['Limitation']  ) && is_array( $params['Limitation']  ) ) ? $params['Limitation']: false;
01884         $limitationList = eZContentObjectTreeNode::getLimitationList( $limitation );
01885         $sqlPermissionChecking = eZContentObjectTreeNode::createPermissionCheckingSQL( $limitationList );
01886 
01887         // Determine whether we should show invisible nodes.
01888         $showInvisibleNodesCond = eZContentObjectTreeNode::createShowInvisibleSQLString( !$ignoreVisibility );
01889 
01890         $query = "SELECT DISTINCT
01891                        ezcontentobject.*,
01892                        ezcontentobject_tree.*,
01893                        ezcontentclass.serialized_name_list as class_serialized_name_list,
01894                        ezcontentclass.identifier as class_identifier,
01895                        ezcontentclass.is_container as is_container
01896                        $groupBySelectText
01897                        $versionNameTargets
01898                        $sortingInfo[attributeTargetSQL]
01899                        $extendedAttributeFilter[columns]
01900                    FROM
01901                       ezcontentobject_tree,
01902                       ezcontentobject,ezcontentclass
01903                       $versionNameTables
01904                       $sortingInfo[attributeFromSQL]
01905                       $attributeFilter[from]
01906                       $extendedAttributeFilter[tables]
01907                       $sqlPermissionChecking[from]
01908                    WHERE
01909                       $pathStringCond
01910                       $extendedAttributeFilter[joins]
01911                       $sortingInfo[attributeWhereSQL]
01912                       $attributeFilter[where]
01913                       ezcontentclass.version=0 AND
01914                       $notEqParentString
01915                       ezcontentobject_tree.contentobject_id = ezcontentobject.id  AND
01916                       ezcontentclass.id = ezcontentobject.contentclass_id AND
01917                       $mainNodeOnlyCond
01918                       $classCondition
01919                       $versionNameJoins
01920                       $showInvisibleNodesCond
01921                       $sqlPermissionChecking[where]
01922                       $objectNameFilterSQL
01923                       $languageFilter
01924                 $groupByText";
01925 
01926         if ( $sortingInfo['sortingFields'] )
01927             $query .= " ORDER BY $sortingInfo[sortingFields]";
01928 
01929         $db = eZDB::instance();
01930 
01931         $server = count( $sqlPermissionChecking['temp_tables'] ) > 0 ? eZDBInterface::SERVER_SLAVE : false;
01932 
01933         if ( !$offset && !$limit )
01934         {
01935             $nodeListArray = $db->arrayQuery( $query, array(), $server );
01936         }
01937         else
01938         {
01939             $nodeListArray = $db->arrayQuery( $query, array( 'offset' => $offset,
01940                                                              'limit'  => $limit ),
01941                                                       $server );
01942         }
01943 
01944         if ( $asObject )
01945         {
01946             $retNodeList = eZContentObjectTreeNode::makeObjectsArray( $nodeListArray );
01947             if ( $loadDataMap )
01948                 eZContentObject::fillNodeListAttributes( $retNodeList );
01949         }
01950         else
01951         {
01952             $retNodeList = $nodeListArray;
01953         }
01954 
01955         // cleanup temp tables
01956         $db->dropTempTableList( $sqlPermissionChecking['temp_tables'] );
01957 
01958         return $retNodeList;
01959     }
01960 
01961     /*!
01962     */
01963     function subTree( $params = false )
01964     {
01965         return eZContentObjectTreeNode::subTreeByNodeID( $params, $this->attribute( 'node_id' ) );
01966     }
01967 
01968     /*!
01969     Retrieve subtrees from multiple paths.
01970 
01971     This method composes a list of objects retrieved from various node paths,
01972     sorted by criteria that are globally applied to the whole list.
01973 
01974     It is for example useful for an RSS feed that serves content from
01975     several node paths. The respective subtrees need to be amalgated and
01976     the resulting object listed sorted by publishing date to show the latest
01977     entries in chronological order.
01978 
01979     The first parameter is a multi-dimensional array containing the
01980     node IDs and filter criteria assigned to each of the nodes:
01981 
01982     array(
01983         [node_1] => array(
01984                         'ClassFilterType' =>    [filter_type],
01985                         'ClassFilterArray'  =>  [filter_array]
01986                         ),
01987          [node_2] => array(
01988                         'ClassFilterType' =>    [filter_type],
01989                         'ClassFilterArray'  =>  [filter_array]
01990                         )
01991          )
01992 
01993     The second parameter is a single-dimensional array with criteria
01994     applied to the list of objects retrieved from the various subtrees:
01995 
01996     array(
01997         'SortBy' => [sorting-criteria]
01998         )
01999     */
02000     static function subTreeMultiPaths( $nodesParams, $listParams = NULL )
02001     {
02002         if( !is_array( $nodesParams ) || !count( $nodesParams ) )
02003         {
02004             eZDebug::writeWarning( __CLASS__.'::'.__FUNCTION__.': Nodes parameter must be an array with at least one key.' );
02005             return null;
02006         }
02007 
02008         if( is_null( $listParams ) )
02009         {
02010             $listParams = array(
02011                              'SortBy'                   => false,
02012                              'Offset'                   => false,
02013                              'Limit'                    => false,
02014                              'SortBy'                   => false,
02015                              'GroupBy'                  => false );
02016         }
02017 
02018         $offset           = ( isset( $listParams['Offset'] ) && is_numeric( $listParams['Offset'] ) ) ? $listParams['Offset']             : false;
02019         $limit            = ( isset( $listParams['Limit']  ) && is_numeric( $listParams['Limit']  ) ) ? $listParams['Limit']              : false;
02020         $groupBy          = ( isset( $listParams['GroupBy']                                       ) ) ? $listParams['GroupBy']            : false;
02021         if ( !isset( $listParams['SortBy'] ) )
02022         {
02023             $listParams['SortBy'] = false;
02024         }
02025         $sortBy = $listParams['SortBy'];
02026 
02027         $queryNodes = '';
02028 
02029         foreach( $nodesParams as $nodeParams )
02030         {
02031             $nodeID = $nodeParams['ParentNodeID'];
02032 
02033             if ( !is_numeric( $nodeID ) && !is_array( $nodeID ) )
02034             {
02035                 eZDebug::writeWarning( __CLASS__.'::'.__FUNCTION__.': Nodes parameter must be numeric or an array with numeric values.' );
02036                 $retValue = null;
02037                 return $retValue;
02038             }
02039 
02040             if ( is_null( $nodeParams ) )
02041             {
02042                 $nodeParams = array(
02043                                  'Depth'                    => false,
02044                                  //'OnlyTranslated'           => false,
02045                                  'Language'                 => false,
02046                                  'AttributeFilter'          => false,
02047                                  'ExtendedAttributeFilter'  => false,
02048                                  'ClassFilterType'          => false,
02049                                  'ClassFilterArray'         => false );
02050             }
02051 
02052             //$onlyTranslated   = ( isset( $nodeParams['OnlyTranslated']    ) )                       ? $nodeParams['OnlyTranslated']     : false;
02053             $language         = ( isset( $nodeParams['Language']          ) )                             ? $nodeParams['Language']           : false;
02054             $depth            = ( isset( $nodeParams['Depth']  ) && is_numeric( $nodeParams['Depth']  ) ) ? $nodeParams['Depth']              : false;
02055             $depthOperator    = ( isset( $nodeParams['DepthOperator']     ) )                         ? $nodeParams['DepthOperator']      : false;
02056             $asObject         = ( isset( $nodeParams['AsObject']          ) )                         ? $nodeParams['AsObject']           : true;
02057             $mainNodeOnly     = ( isset( $nodeParams['MainNodeOnly']      ) )                         ? $nodeParams['MainNodeOnly']       : false;
02058             $ignoreVisibility = ( isset( $nodeParams['IgnoreVisibility']  ) )                         ? $nodeParams['IgnoreVisibility']   : false;
02059             if ( !isset( $nodeParams['ClassFilterType'] ) )
02060             {
02061                 $nodeParams['ClassFilterType'] = false;
02062             }
02063 
02064             if ( $language )
02065             {
02066                 if ( !is_array( $language ) )
02067                 {
02068                     $language = array( $language );
02069                 }
02070                 eZContentLanguage::setPrioritizedLanguages( $language );
02071             }
02072 
02073             $sortingInfo             = eZContentObjectTreeNode::createSortingSQLStrings( $sortBy );
02074             $classCondition          = eZContentObjectTreeNode::createClassFilteringSQLString( $nodeParams['ClassFilterType'], $nodeParams['ClassFilterArray'] );
02075             $attributeFilter         = eZContentObjectTreeNode::createAttributeFilterSQLStrings( $nodeParams['AttributeFilter'], $sortingInfo );
02076             $extendedAttributeFilter = eZContentObjectTreeNode::createExtendedAttributeFilterSQLStrings( $nodeParams['ExtendedAttributeFilter'] );
02077             $mainNodeOnlyCond        = eZContentObjectTreeNode::createMainNodeConditionSQLString( $mainNodeOnly );
02078 
02079             $pathStringCond     = '';
02080             $notEqParentString  = '';
02081             // If the node(s) doesn't exist we return null.
02082 
02083             if ( !eZContentObjectTreeNode::createPathConditionAndNotEqParentSQLStrings( $pathStringCond, $notEqParentString, $nodeID, $depth, $depthOperator ) )
02084             {
02085                 $retValue = null;
02086                 return $retValue;
02087             }
02088 
02089             $useVersionName     = true;
02090             $versionNameTables  = eZContentObjectTreeNode::createVersionNameTablesSQLString ( $useVersionName );
02091             $versionNameTargets = eZContentObjectTreeNode::createVersionNameTargetsSQLString( $useVersionName );
02092             $versionNameJoins   = eZContentObjectTreeNode::createVersionNameJoinsSQLString  ( $useVersionName, false );
02093 
02094             $languageFilter = ' AND ' . eZContentLanguage::languagesSQLFilter( 'ezcontentobject' );
02095 
02096             if ( $language )
02097             {
02098                 eZContentLanguage::clearPrioritizedLanguages();
02099             }
02100 
02101             $limitation = ( isset( $nodeParams['Limitation']  ) && is_array( $nodeParams['Limitation']  ) ) ? $nodeParams['Limitation']: false;
02102             $limitationList = eZContentObjectTreeNode::getLimitationList( $limitation );
02103             $sqlPermissionChecking = eZContentObjectTreeNode::createPermissionCheckingSQL( $limitationList );
02104 
02105             // Determine whether we should show invisible nodes.
02106             $showInvisibleNodesCond = eZContentObjectTreeNode::createShowInvisibleSQLString( !$ignoreVisibility );
02107 
02108             $queryNodes .= " (
02109                           $pathStringCond
02110                           $extendedAttributeFilter[joins]
02111                           $sortingInfo[attributeWhereSQL]
02112                           $attributeFilter[where]
02113                           ezcontentclass.version=0 AND
02114                           $notEqParentString
02115                           ezcontentobject_tree.contentobject_id = ezcontentobject.id  AND
02116                           ezcontentclass.id = ezcontentobject.contentclass_id AND
02117                           $mainNodeOnlyCond
02118                           $classCondition
02119                           $versionNameJoins
02120                           $showInvisibleNodesCond
02121                           $sqlPermissionChecking[where]
02122                           $languageFilter
02123                       )
02124                       OR";
02125         }
02126 
02127         $groupBySelectText  = '';
02128         $groupByText        = '';
02129         eZContentObjectTreeNode::createGroupBySQLStrings( $groupBySelectText, $groupByText, $groupBy );
02130 
02131         $query = "SELECT DISTINCT
02132                        ezcontentobject.*,
02133                        ezcontentobject_tree.*,
02134                        ezcontentclass.serialized_name_list as class_serialized_name_list,
02135                        ezcontentclass.identifier as class_identifier
02136                        $groupBySelectText
02137                        $versionNameTargets
02138                        $sortingInfo[attributeTargetSQL]
02139                        , ".$nodeParams['ResultID']." AS resultid
02140                    FROM
02141                       ezcontentobject_tree,
02142                       ezcontentobject,ezcontentclass
02143                       $versionNameTables
02144                       $sortingInfo[attributeFromSQL]
02145                       $attributeFilter[from]
02146                       $extendedAttributeFilter[tables]
02147                       $sqlPermissionChecking[from]
02148                    WHERE
02149                       ".substr($queryNodes, 0, -2)."
02150                 $groupByText";
02151 
02152         if ( $sortingInfo['sortingFields'] )
02153         {
02154             $query .= " ORDER BY $sortingInfo[sortingFields]";
02155         }
02156 
02157         $db = eZDB::instance();
02158 
02159         $server = count( $sqlPermissionChecking['temp_tables'] ) > 0 ? eZDBInterface::SERVER_SLAVE : false;
02160 
02161         if ( !$offset && !$limit )
02162         {
02163             $nodeListArray = $db->arrayQuery( $query, array(), $server );
02164         }
02165         else
02166         {
02167             $nodeListArray = $db->arrayQuery( $query, array( 'offset' => $offset,
02168                                                               'limit'  => $limit ),
02169                                                       $server );
02170         }
02171 
02172         if ( $asObject )
02173         {
02174             $retNodeList = eZContentObjectTreeNode::makeObjectsArray( $nodeListArray );
02175         }
02176         else
02177         {
02178             $retNodeList = $nodeListArray;
02179         }
02180 
02181         // cleanup temp tables
02182         $db->dropTempTableList( $sqlPermissionChecking['temp_tables'] );
02183 
02184         return $retNodeList;
02185     }
02186 
02187     static function subTreeGroupByDateField( $field, $type )
02188     {
02189         $divisor = 0;
02190         switch ( $type )
02191         {
02192             case 'year':
02193             {
02194                 $divisor = 60*60*24*365;
02195             } break;
02196             case 'week':
02197             {
02198                 $divisor = 60*60*24*7;
02199             } break;
02200             case 'day':
02201             {
02202                 $divisor = 60*60*24;
02203             } break;
02204             case 'hour':
02205             {
02206                 $divisor = 60*60;
02207             } break;
02208             case 'minute':
02209             {
02210                 $divisor = 60;
02211             } break;
02212             case 'second':
02213             {
02214                 $divisor = 0;
02215             } break;
02216             default:
02217             {
02218                 eZDebug::writeError( "Unknown field type $type",
02219                                      'eZContentObjectTreeNode::subTreeGroupByDateField' );
02220             }
02221         }
02222         if ( $divisor > 0 )
02223             $text = "( $field / $divisor ) AS groupbyfield";
02224         else
02225             $text = "$field AS groupbyfield";
02226         return array( 'select' => $text,
02227                       'group_field' => "( $field / $divisor )" );
02228     }
02229 
02230     /*!
02231      \sa subTreeCount
02232     */
02233     static function subTreeCountByNodeID( $params = array(), $nodeID )
02234     {
02235         if ( !is_numeric( $nodeID ) and !is_array( $nodeID ) )
02236         {
02237             return null;
02238         }
02239 
02240         $language = ( isset( $params['Language'] ) ) ? $params['Language'] : false;
02241 
02242         if ( $language )
02243         {
02244             if ( !is_array( $language ) )
02245             {
02246                 $language = array( $language );
02247             }
02248             eZContentLanguage::setPrioritizedLanguages( $language );
02249         }
02250 
02251         $depth         = isset( $params['Depth'] ) && is_numeric( $params['Depth'] ) ? $params['Depth']              : false;
02252         $depthOperator = isset( $params['DepthOperator'] )                           ? $params['DepthOperator']      : false;
02253 
02254         $pathStringCond     = '';
02255         $notEqParentString  = '';
02256         // If the node(s) doesn't exist we return null.
02257         if ( !eZContentObjectTreeNode::createPathConditionAndNotEqParentSQLStrings( $pathStringCond, $notEqParentString, $nodeID, $depth, $depthOperator ) )
02258         {
02259             return null;
02260         }
02261 
02262         $db = eZDB::instance();
02263 
02264         $limitation = ( isset( $params['Limitation']  ) && is_array( $params['Limitation']  ) ) ? $params['Limitation']: false;
02265         $limitationList = eZContentObjectTreeNode::getLimitationList( $limitation );
02266 
02267         $ini = eZINI::instance();
02268 
02269         // Check for class filtering
02270         $classCondition = '';
02271 
02272         if ( isset( $params['ClassFilterType'] ) and isset( $params['ClassFilterArray'] ) and
02273              ( $params['ClassFilterType'] == 'include' or $params['ClassFilterType'] == 'exclude' )
02274              and count( $params['ClassFilterArray'] ) > 0 )
02275         {
02276             $classCondition = '  ';
02277             $i = 0;
02278             $classCount = count( $params['ClassFilterArray'] );
02279             $classIDArray = array();
02280             foreach ( $params['ClassFilterArray'] as $classID )
02281             {
02282                 $originalClassID = $classID;
02283                 // Check if classes are recerenced by identifier
02284                 if ( is_string( $classID ) && !is_numeric( $classID ) )
02285                 {
02286                     $classID = eZContentObjectTreeNode::classIDByIdentifier( $classID );
02287                 }
02288                 if ( is_numeric( $classID ) )
02289                 {
02290                     $classIDArray[] = $classID;
02291                 }
02292                 else
02293                 {
02294                     eZDebugSetting::writeWarning( 'kernel-content-class', "Invalid class identifier in subTree() classfilterarray, classID : " . $originalClassID );
02295                 }
02296             }
02297             if ( count( $classIDArray ) > 0  )
02298             {
02299                 $classCondition .= " ezcontentobject.contentclass_id ";
02300                 if ( $params['ClassFilterType'] == 'include' )
02301                     $classCondition .= " IN ";
02302                 else
02303                     $classCondition .= " NOT IN ";
02304 
02305                 $classIDString =  implode( ', ', $classIDArray );
02306                 $classCondition .= ' ( ' . $classIDString . ' ) AND';
02307             }
02308         }
02309 
02310 
02311         // Main node check
02312         $mainNodeOnlyCond = '';
02313         if ( isset( $params['MainNodeOnly'] ) && $params['MainNodeOnly'] === true )
02314         {
02315             $mainNodeOnlyCond = 'ezcontentobject_tree.node_id = ezcontentobject_tree.main_node_id AND';
02316         }
02317 
02318         // Attribute filtering
02319         // Check for attribute filtering
02320         $attributeFilterFromSQL = "";
02321         $attributeFilterWhereSQL = "";
02322 
02323         $totalAttributesFiltersCount = 0;
02324         $invalidAttributesFiltersCount = 0;
02325 
02326         if ( isset( $params['AttributeFilter'] ) )
02327         {
02328             $filterArray = $params['AttributeFilter'];
02329 
02330             // Check if first value of array is a string.
02331             // To check for and/or filtering
02332             $filterJoinType = 'AND';
02333             if ( is_string( $filterArray[0] ) )
02334             {
02335                 if ( strtolower( $filterArray[0] ) == 'or' )
02336                 {
02337                     $filterJoinType = 'OR';
02338                 }
02339                 else if ( strtolower( $filterArray[0] ) == 'and' )
02340                 {
02341                     $filterJoinType = 'AND';
02342                 }
02343                 unset( $filterArray[0] );
02344             }
02345 
02346             $attibuteFilterJoinSQL = "";
02347             $filterCount = 0;
02348 
02349             if ( is_array( $filterArray ) )
02350             {
02351                 // Handle attribute filters and generate SQL
02352                 $totalAttributesFiltersCount = count( $filterArray );
02353 
02354                 foreach ( $filterArray as $filter )
02355                 {
02356                     $isFilterValid = true; // by default assumes that filter is valid
02357 
02358                     $filterAttributeID = $filter[0];
02359                     $filterType = $filter[1];
02360                     $filterValue = is_array( $filter[2] ) ? '' : $db->escapeString( $filter[2] );
02361 
02362                     $useAttributeFilter = false;
02363                     switch ( $filterAttributeID )
02364                     {
02365                         case 'path':
02366                         {
02367                             $filterField = 'path_string';
02368                         } break;
02369                         case 'published':
02370                         {
02371                             $filterField = 'ezcontentobject.published';
02372                         } break;
02373                         case 'modified':
02374                         {
02375                             $filterField = 'ezcontentobject.modified';
02376                         } break;
02377                         case 'modified_subnode':
02378                         {
02379                             $filterField = 'modified_subnode';
02380                         } break;
02381                         case 'section':
02382                         {
02383                             $filterField = 'ezcontentobject.section_id';
02384                         } break;
02385                         case 'depth':
02386                         {
02387                             $filterField = 'depth';
02388                         } break;
02389                         case 'class_identifier':
02390                         {
02391                             $filterField = 'ezcontentclass.identifier';
02392                         } break;
02393                         case 'class_name':
02394                         {
02395                             $classNameFilter = eZContentClassName::sqlFilter();
02396                             $filterField .= $classNameFilter['nameField'];
02397                             $attributeFromSQL .= ", $classNameFilter[from]";
02398                             $attributeWhereSQL .= "$classNameFilter[where] AND ";
02399                         } break;
02400                         case 'priority':
02401                         {
02402                             $filterField = 'ezcontentobject_tree.priority';
02403                         } break;
02404                         case 'name':
02405                         {
02406                             $filterField = 'ezcontentobject_name.name';
02407                         } break;
02408                         case 'owner':
02409                         {
02410                             $filterField = 'ezcontentobject.owner_id';
02411                         } break;
02412                         default:
02413                         {
02414                             $useAttributeFilter = true;
02415                         } break;
02416                     }
02417 
02418                     if ( $useAttributeFilter )
02419                     {
02420                         if ( !is_numeric( $filterAttributeID ) )
02421                             $filterAttributeID = eZContentObjectTreeNode::classAttributeIDByIdentifier( $filterAttributeID );
02422 
02423                         if ( $filterAttributeID === false )
02424                         {
02425                             $isFilterValid = false;
02426                             if( $filterJoinType === 'AND' )
02427                             {
02428                                 // go out
02429                                 $invalidAttributesFiltersCount = $totalAttributesFiltersCount;
02430                                 break;
02431                             }
02432 
02433                             // check next filter
02434                             ++$invalidAttributesFiltersCount;
02435                         }
02436                         else
02437                         {
02438                             // Check datatype for filtering
02439                             $filterDataType = eZContentObjectTreeNode::sortKeyByClassAttributeID( $filterAttributeID );
02440                             if ( $filterDataType === false )
02441                             {
02442                                 $isFilterValid = false;
02443                                 if( $filterJoinType === 'AND' )
02444                                 {
02445                                     // go out
02446                                     $invalidAttributesFiltersCount = $totalAttributesFiltersCount;
02447                                     break;
02448                                 }
02449 
02450                                 // check next filter
02451                                 ++$invalidAttributesFiltersCount;
02452                             }
02453                             else
02454                             {
02455                                 $sortKey = false;
02456                                 if ( $filterDataType == 'string' )
02457                                 {
02458                                     $sortKey = 'sort_key_string';
02459                                 }
02460                                 else
02461                                 {
02462                                     $sortKey = 'sort_key_int';
02463                                 }
02464 
02465                                 $filterField = "a$filterCount.$sortKey";
02466 
02467                                 // Use the same joins as we do when sorting,
02468                                 // if more attributes are filtered by we will append them
02469                                 $attributeFilterFromSQL .= ", ezcontentobject_attribute a$filterCount ";
02470                                 $attributeFilterWhereSQL .= "
02471                                     a$filterCount.contentobject_id = ezcontentobject.id AND
02472                                        a$filterCount.version = ezcontentobject.current_version AND
02473                                        a$filterCount.contentclassattribute_id = $filterAttributeID AND ";
02474                                 $attributeFilterWhereSQL .= eZContentLanguage::sqlFilter( "a$filterCount", 'ezcontentobject' );
02475                                 $attributeFilterWhereSQL .= ' AND ';
02476                             }
02477 
02478                         }
02479                     }
02480 
02481                     if ( $isFilterValid )
02482                     {
02483                         $hasFilterOperator = true;
02484                         // Controls quotes around filter value, some filters do this manually
02485                         $noQuotes = false;
02486                         // Controls if $filterValue or $folder[2] is used, $filterValue is already escaped
02487                         $unEscape = false;
02488 
02489                         switch ( $filterType )
02490                         {
02491                             case '=' :
02492                             {
02493                                 $filterOperator = '=';
02494                             }break;
02495 
02496                             case '!=' :
02497                             {
02498                                 $filterOperator = '<>';
02499                             }break;
02500 
02501                             case '>' :
02502                             {
02503                                 $filterOperator = '>';
02504                             }break;
02505 
02506                             case '<' :
02507                             {
02508                                 $filterOperator = '<';
02509                             }break;
02510 
02511                             case '<=' :
02512                             {
02513                                 $filterOperator = '<=';
02514                             }break;
02515 
02516                             case '>=' :
02517                             {
02518                                 $filterOperator = '>=';
02519                             }break;
02520 
02521                             case 'like':
02522                             case 'not_like':
02523                             {
02524                                 $filterOperator = ( $filterType == 'like' ? 'LIKE' : 'NOT LIKE' );
02525                                 // We escape the string ourselves, this MUST be done before wildcard replace
02526                                 $filter[2] = $db->escapeString( $filter[2] );
02527                                 $unEscape = true;
02528                                 // Since * is used as wildcard we need to transform the string to
02529                                 // use % as wildcard. The following rules apply:
02530                                 // - % -> \%
02531                                 // - * -> %
02532                                 // - \* -> *
02533                                 // - \\ -> \
02534 
02535                                 $filter[2] = preg_replace( array( '#%#m',
02536                                                                   '#(?<!\\\\)\\*#m',
02537                                                                   '#(?<!\\\\)\\\\\\*#m',
02538                                                                   '#\\\\\\\\#m' ),
02539                                                            array( '\\%',
02540                                                                   '%',
02541                                                                   '*',
02542                                                                   '\\\\' ),
02543                                                            $filter[2] );
02544                             } break;
02545 
02546                             case 'in':
02547                             case 'not_in' :
02548                             {
02549                                 $filterOperator = ( $filterType == 'in' ? 'IN' : 'NOT IN' );
02550                                 // Turn off quotes for value, we do this ourselves
02551                                 $noQuotes = true;
02552                                 if ( is_array( $filter[2] ) )
02553                                 {
02554                                     reset( $filter[2] );
02555                                     while ( list( $key, $value ) = each( $filter[2] ) )
02556                                     {
02557                                         // Non-numerics must be escaped to avoid SQL injection
02558                                         $filter[2][$key] = is_numeric( $value ) ? $value : "'" . $db->escapeString( $value ) . "'";
02559                                     }
02560                                     $filterValue = '(' .  implode( ",", $filter[2] ) . ')';
02561                                 }
02562                                 else
02563                                 {
02564                                     $hasFilterOperator = false;
02565                                 }
02566                             } break;
02567 
02568                             case 'between':
02569                             case 'not_between' :
02570                             {
02571                                 $filterOperator = ( $filterType == 'between' ? 'BETWEEN' : 'NOT BETWEEN' );
02572                                 // Turn off quotes for value, we do this ourselves
02573                                 $noQuotes = true;
02574                                 if ( is_array( $filter[2] ) )
02575                                 {
02576                                     // Check for non-numerics to avoid SQL injection
02577                                     if ( !is_numeric( $filter[2][0] ) )
02578                                         $filter[2][0] = "'" . $db->escapeString( $filter[2][0] ) . "'";
02579                                     if ( !is_numeric( $filter[2][1] ) )
02580                                         $filter[2][1] = "'" . $db->escapeString( $filter[2][1] ) . "'";
02581 
02582                                     $filterValue = $filter[2][0] . ' AND ' . $filter[2][1];
02583                                 }
02584                             } break;
02585 
02586                             default :
02587                             {
02588                                 $hasFilterOperator = false;
02589                                 eZDebug::writeError( "Unknown attribute filter type: $filterType", "eZContentObjectTreeNode::subTree()" );
02590                             }break;
02591 
02592                         }
02593                         if ( $hasFilterOperator )
02594                         {
02595                             if ( $filterCount > 0 )
02596                                 $attibuteFilterJoinSQL .= " $filterJoinType ";
02597 
02598                             // If $unEscape is true we get the filter value from the 2nd element instead
02599                             // which must have been escaped by filter type
02600                             $filterValue = $unEscape ? $filter[2] : $filterValue;
02601 
02602                             $attibuteFilterJoinSQL .= "$filterField $filterOperator ";
02603                             $attibuteFilterJoinSQL .= $noQuotes ? "$filterValue " : "'$filterValue' ";
02604 
02605                             $filterCount++;
02606                         }
02607                     }
02608                 } // end of 'foreach ( $filterArray as $filter )'
02609 
02610                 if ( $totalAttributesFiltersCount == $invalidAttributesFiltersCount )
02611                 {
02612                     $attributeFilterFromSQL = "";
02613                     $attributeFilterWhereSQL = "";
02614 
02615                     eZDebug::writeNotice( "Attribute filter returned false" );
02616                     return 0;
02617                 }
02618                 else
02619                 {
02620                     if ( $filterCount > 0 )
02621                         $attributeFilterWhereSQL .= "\n                            ( " . $attibuteFilterJoinSQL . " ) AND ";
02622                 }
02623             } // end of 'if ( is_array( $filterArray ) )'
02624         }
02625 
02626         //$onlyTranslated   = ( isset( $params['OnlyTranslated'] ) ) ? $params['OnlyTranslated']     : false;
02627 
02628         $useVersionName     = true;
02629 
02630         $versionNameTables  = eZContentObjectTreeNode::createVersionNameTablesSQLString ( $useVersionName );
02631         $versionNameTargets = eZContentObjectTreeNode::createVersionNameTargetsSQLString( $useVersionName );
02632         $versionNameJoins   = eZContentObjectTreeNode::createVersionNameJoinsSQLString  ( $useVersionName, false );
02633 
02634         $languageFilter = ' AND '.eZContentLanguage::languagesSQLFilter( 'ezcontentobject' );
02635 
02636         if ( $language )
02637         {
02638             eZContentLanguage::clearPrioritizedLanguages();
02639         }
02640         $objectNameFilter = ( isset( $params['ObjectNameFilter']  ) ) ? $params['ObjectNameFilter']   : false;
02641         $objectNameFilterSQL = eZContentObjectTreeNode::createObjectNameFilterConditionSQLString( $objectNameFilter );
02642 
02643         $extendedAttributeFilter = eZContentObjectTreeNode::createExtendedAttributeFilterSQLStrings( $params['ExtendedAttributeFilter'] );
02644 
02645         // Determine whether we should show invisible nodes.
02646         $ignoreVisibility = isset( $params['IgnoreVisibility'] ) ? $params['IgnoreVisibility'] : false;
02647         $showInvisibleNodesCond = eZContentObjectTreeNode::createShowInvisibleSQLString( !$ignoreVisibility );
02648 
02649         $sqlPermissionCheckingFrom = '';
02650         $sqlPermissionCheckingWhere = '';
02651         $sqlPermissionTempTables = array();
02652         $groupPermTempTable = false;
02653 
02654         if ( $limitationList !== false && count( $limitationList ) > 0 )
02655         {
02656             $sqlParts = array();
02657 
02658             foreach( $limitationList as $limitationArray )
02659             {
02660                 $sqlPartPart = array();
02661                 $sqlPartPartPart = array();
02662 
02663                 foreach ( array_keys( $limitationArray ) as $ident )
02664                 {
02665                     switch( $ident )
02666                     {
02667                         case 'Class':
02668                         {
02669                             $sqlPartPart[] = 'ezcontentobject.contentclass_id in (' . implode( ', ', $limitationArray[$ident] ) . ')';
02670                         } break;
02671 
02672                         case 'Section':
02673                         case 'User_Section':
02674                         {
02675                             $sqlPartPart[] = 'ezcontentobject.section_id in (' . implode( ', ', $limitationArray[$ident] ) . ')';
02676                         } break;
02677 
02678                         case 'Owner':
02679                         {
02680                             $user = eZUser::currentUser();
02681                             $userID = $user->attribute( 'contentobject_id' );
02682                             $sqlPartPart[] = "ezcontentobject.owner_id = '" . $db->escapeString( $userID ) . "'";
02683                         } break;
02684 
02685                         case 'Group':
02686                         {
02687                             if ( !$groupPermTempTable )
02688                             {
02689                                 $user = eZUser::currentUser();
02690                                 $userContentObject = $user->attribute( 'contentobject' );
02691                                 $parentList = $userContentObject->attribute( 'parent_nodes' );
02692 
02693                                 $groupPermTempTable = $db->generateUniqueTempTableName( 'ezgroup_perm_tmp_%' );
02694                                 $sqlPermissionTempTables[] = $groupPermTempTable;
02695 
02696                                 $db->createTempTable( "CREATE TEMPORARY TABLE $groupPermTempTable ( user_id int )" );
02697                                 $db->query( "INSERT INTO $groupPermTempTable
02698                                                     SELECT DISTINCT contentobject_id AS user_id
02699                                                     FROM     ezcontentobject_tree
02700                                                     WHERE    parent_node_id IN ("  . implode( ', ', $parentList ) . ')' );
02701 
02702                                 $sqlPermissionCheckingFrom = ', ' . $groupPermTempTable;
02703                             }
02704                             $sqlPartPart[] = "ezcontentobject.owner_id = $groupPermTempTable.user_id";
02705                         } break;
02706 
02707                         case 'Node':
02708                         {
02709                             $sqlPartPartPart[] = 'ezcontentobject_tree.node_id in (' . implode( ', ', $limitationArray[$ident] ) . ')';
02710                         } break;
02711 
02712                         case 'Subtree':
02713                         {
02714                             foreach ( $limitationArray[$ident] as $limitationPathString )
02715                             {
02716                                 $sqlPartPartPart[] = "ezcontentobject_tree.path_string like '$limitationPathString%'";
02717                             }
02718                         } break;
02719 
02720                         case 'User_Subtree':
02721                         {
02722                             $pathArray = $limitationArray[$ident];
02723                             $sqlPartUserSubtree = array();
02724                             foreach ( $pathArray as $limitationPathString )
02725                             {
02726                                 $sqlPartUserSubtree[] = "ezcontentobject_tree.path_string like '$limitationPathString%'";
02727                             }
02728                             $sqlPartPart[] = implode( ' OR ', $sqlPartUserSubtree );
02729                         }
02730                     }
02731                 }
02732                 if ( $sqlPartPartPart )
02733                 {
02734                     $sqlPartPart[] = '( ' . implode( ' ) OR ( ', $sqlPartPartPart ). ' )';
02735                 }
02736                 $sqlParts[] = implode( ' AND ', $sqlPartPart );
02737             }
02738 
02739             $sqlPermissionCheckingWhere = ' AND ((' . implode( ') or (', $sqlParts ) . ')) ';
02740             $sqlPermissionChecking = array( 'from' => $sqlPermissionCheckingFrom,
02741                                             'where' => $sqlPermissionCheckingWhere );
02742 
02743             $query = "SELECT
02744                             count( DISTINCT ezcontentobject_tree.node_id ) as count
02745                       FROM
02746                            ezcontentobject_tree,
02747                            ezcontentobject,ezcontentclass
02748                            $versionNameTables
02749                            $attributeFilterFromSQL
02750                            $extendedAttributeFilter[tables]
02751                            $sqlPermissionChecking[from]
02752                       WHERE $pathStringCond
02753                             $extendedAttributeFilter[joins]
02754                             $mainNodeOnlyCond
02755                             $classCondition
02756                             $attributeFilterWhereSQL
02757                             ezcontentclass.version=0 AND
02758                             $notEqParentString
02759                             ezcontentobject_tree.contentobject_id = ezcontentobject.id  AND
02760                             ezcontentclass.id = ezcontentobject.contentclass_id AND
02761                             $versionNameJoins
02762                             $showInvisibleNodesCond
02763                             $sqlPermissionChecking[where]
02764                             $objectNameFilterSQL
02765                             $languageFilter ";
02766 
02767         }
02768         else
02769         {
02770             $query="SELECT
02771                           count( DISTINCT ezcontentobject_tree.node_id ) as count
02772                     FROM
02773                           ezcontentobject_tree,
02774                           ezcontentobject,
02775                           ezcontentclass
02776                           $versionNameTables
02777                           $attributeFilterFromSQL
02778                           $extendedAttributeFilter[tables]
02779                     WHERE
02780                            $pathStringCond
02781                            $extendedAttributeFilter[joins]
02782                            $mainNodeOnlyCond
02783                            $classCondition
02784                            $attributeFilterWhereSQL
02785                            ezcontentclass.version=0 AND
02786                            $notEqParentString
02787                            ezcontentobject_tree.contentobject_id = ezcontentobject.id AND
02788                            ezcontentclass.id = ezcontentobject.contentclass_id AND
02789                            $versionNameJoins
02790                            $showInvisibleNodesCond
02791                            $objectNameFilterSQL
02792                            $languageFilter ";
02793         }
02794 
02795         $server = count( $sqlPermissionTempTables ) > 0 ? eZDBInterface::SERVER_SLAVE : false;
02796 
02797         $nodeListArray = $db->arrayQuery( $query, array(), $server );
02798 
02799         // cleanup temp tables
02800         $db->dropTempTableList( $sqlPermissionTempTables );
02801 
02802         return $nodeListArray[0]['count'];
02803     }
02804 
02805     /*!
02806      Count number of subnodes
02807 
02808      \param params array
02809     */
02810     function subTreeCount( $params = array() )
02811     {
02812         return eZContentObjectTreeNode::subTreeCountByNodeID( $params, $this->attribute( 'node_id' ) );
02813     }
02814 
02815     /*!
02816       \return The date/time list when object were published
02817     */
02818     static function calendar( $params = false, $nodeID = 0 )
02819     {
02820         if ( !is_numeric( $nodeID ) and !is_array( $nodeID ) )
02821         {
02822             return array();
02823         }
02824 
02825         if ( $params === false )
02826         {
02827             $params = array( 'Depth'                    => false,
02828                              'Offset'                   => false,
02829                              'Limit'                    => false,
02830                              'AttributeFilter'          => false,
02831                              'ExtendedAttributeFilter'  => false,
02832                              'ClassFilterType'          => false,
02833                              'ClassFilterArray'         => false,
02834                              'GroupBy'                  => false );
02835         }
02836 
02837         $offset           = ( isset( $params['Offset'] ) && is_numeric( $params['Offset'] ) ) ? $params['Offset']             : false;
02838         $limit            = ( isset( $params['Limit']  ) && is_numeric( $params['Limit']  ) ) ? $params['Limit']              : false;
02839         $depth            = ( isset( $params['Depth']  ) && is_numeric( $params['Depth']  ) ) ? $params['Depth']              : false;
02840         $depthOperator    = ( isset( $params['DepthOperator']     ) )                         ? $params['DepthOperator']      : false;
02841         $groupBy          = ( isset( $params['GroupBy']           ) )                         ? $params['GroupBy']            : false;
02842         $mainNodeOnly     = ( isset( $params['MainNodeOnly']      ) )                         ? $params['MainNodeOnly']       : false;
02843         $ignoreVisibility = ( isset( $params['IgnoreVisibility']  ) )                         ? $params['IgnoreVisibility']   : false;
02844         if ( !isset( $params['ClassFilterType'] ) )
02845             $params['ClassFilterType'] = false;
02846 
02847         $classCondition          = eZContentObjectTreeNode::createClassFilteringSQLString( $params['ClassFilterType'], $params['ClassFilterArray'] );
02848         $attributeFilter         = eZContentObjectTreeNode::createAttributeFilterSQLStrings( $params['AttributeFilter'], $sortingInfo );
02849         $extendedAttributeFilter = eZContentObjectTreeNode::createExtendedAttributeFilterSQLStrings( $params['ExtendedAttributeFilter'] );
02850         $mainNodeOnlyCond        = eZContentObjectTreeNode::createMainNodeConditionSQLString( $mainNodeOnly );
02851 
02852         $pathStringCond     = '';
02853         $notEqParentString  = '';
02854         eZContentObjectTreeNode::createPathConditionAndNotEqParentSQLStrings( $pathStringCond, $notEqParentString, $nodeID, $depth, $depthOperator );
02855 
02856         $groupBySelectText  = '';
02857         $groupByText        = '';
02858         eZContentObjectTreeNode::createGroupBySQLStrings( $groupBySelectText, $groupByText, $groupBy );
02859 
02860         $useVersionName     = true;
02861         $versionNameTables  = eZContentObjectTreeNode::createVersionNameTablesSQLString( $useVersionName );
02862         $versionNameJoins   = eZContentObjectTreeNode::createVersionNameJoinsSQLString( $useVersionName, false );
02863 
02864         $limitation = ( isset( $params['Limitation']  ) && is_array( $params['Limitation']  ) ) ? $params['Limitation']: false;
02865         $limitationList = eZContentObjectTreeNode::getLimitationList( $limitation );
02866         $sqlPermissionChecking = eZContentObjectTreeNode::createPermissionCheckingSQL( $limitationList );
02867 
02868         // Determine whether we should show invisible nodes.
02869         $showInvisibleNodesCond = eZContentObjectTreeNode::createShowInvisibleSQLString( !$ignoreVisibility );
02870 
02871         $query = "SELECT DISTINCT
02872                          ezcontentobject.published as published
02873                          $groupBySelectText
02874                    FROM
02875                       ezcontentobject_tree,
02876                       ezcontentobject,ezcontentclass
02877                       $versionNameTables
02878                       $attributeFilter[from]
02879                       $extendedAttributeFilter[tables]
02880                       $sqlPermissionChecking[from]
02881                    WHERE
02882                       $pathStringCond
02883                       $extendedAttributeFilter[joins]
02884                       $attributeFilter[where]
02885                       ezcontentclass.version=0
02886                       AND
02887                       $notEqParentString
02888                       $mainNodeOnlyCond
02889                       ezcontentobject_tree.contentobject_id = ezcontentobject.id AND
02890                       ezcontentclass.id = ezcontentobject.contentclass_id AND
02891                       $classCondition
02892                       $versionNameJoins
02893                       $showInvisibleNodesCond
02894                       $sqlPermissionChecking[where]
02895                 $groupByText ";
02896 
02897 
02898         $db = eZDB::instance();
02899 
02900         $server = count( $sqlPermissionChecking['temp_tables'] ) > 0 ? eZDBInterface::SERVER_SLAVE : false;
02901 
02902         if ( !$offset && !$limit )
02903         {
02904             $nodeListArray = $db->arrayQuery( $query, array(), $server );
02905         }
02906         else
02907         {
02908             $nodeListArray = $db->arrayQuery( $query, array( 'offset' => $offset,
02909                                                               'limit'  => $limit ),
02910                                                       $server );
02911         }
02912 
02913         // cleanup temp tables
02914         $db->dropTempTableList( $sqlPermissionChecking['temp_tables'] );
02915 
02916         return $nodeListArray;
02917     }
02918     /*!
02919      \return the children(s) of the current node as an array of eZContentObjectTreeNode objects
02920     */
02921     function childrenByName( $name )
02922     {
02923         $nodeID = $this->attribute( 'node_id' );
02924 
02925         $fromNode = $nodeID ;
02926 
02927         $nodePath = $this->attribute( 'path_string' );
02928         $nodeDepth = $this->attribute( 'depth' );
02929 
02930         $childrensPath = $nodePath ;
02931 
02932         $db = eZDB::instance();
02933         $pathString = " path_string like '$childrensPath%' and ";
02934         $depthCond = '';
02935         $nodeDepth = $this->Depth + 1;
02936         $depthCond = ' depth <= ' . $nodeDepth . ' and ';
02937 
02938         $ini = eZINI::instance();
02939         $db = eZDB::instance();
02940 
02941         $name = $db->escapeString( $name );
02942         $query = "SELECT ezcontentobject.*,
02943                              ezcontentobject_tree.*,
02944                              ezcontentclass.serialized_name_list as class_serialized_name_list,
02945                              ezcontentclass.identifier as class_identifier,
02946                              ezcontentclass.is_container as is_container
02947                       FROM
02948                             ezcontentobject_tree,
02949                             ezcontentobject,ezcontentclass
02950                       WHERE $pathString
02951                             $depthCond
02952                             ezcontentobject.name = '$name' AND
02953                             ezcontentclass.version=0 AND
02954                             node_id != $fromNode AND
02955                             ezcontentobject_tree.contentobject_id = ezcontentobject.id  AND
02956                             ezcontentclass.id = ezcontentobject.contentclass_id";
02957 
02958         $nodeListArray = $db->arrayQuery( $query );
02959 
02960         return eZContentObjectTreeNode::makeObjectsArray( $nodeListArray );
02961     }
02962 
02963     /*!
02964      Returns the first level children in sorted order.
02965     */
02966     function children()
02967     {
02968         return $this->subTree( array( 'Depth' => 1,
02969                                       'DepthOperator' => 'eq',
02970                                       'SortBy' => $this->sortArray() ) );
02971     }
02972 
02973     /*!
02974      Returns the number of children for the current node.
02975      \params $checkPolicies If \c true it will only include nodes which can be read using the current policies,
02976                             if \c false all nodes are included in count.
02977     */
02978     function childrenCount( $checkPolicies = true )
02979     {
02980         $params = array( 'Depth' => 1,
02981                          'DepthOperator' => 'eq' );
02982         if ( !$checkPolicies )
02983             $params['Limitation'] = array();
02984         return $this->subTreeCount( $params );
02985     }
02986 
02987     /*!
02988      Get amount views of content node.
02989     */
02990     function viewCount()
02991     {
02992         //include_once( 'kernel/classes/ezviewcounter.php' );
02993         $count = eZViewCounter::fetch( $this->attribute( 'node_id' ), false );
02994         return (int) $count['count'];
02995     }
02996 
02997     /*!
02998      \return the field name for the sort order number \a $sortOrder.
02999              Gives a warning if the number is unknown and return \c 'path'.
03000     */
03001     static function sortFieldName( $sortOrder )
03002     {
03003         switch ( $sortOrder )
03004         {
03005             default:
03006                 eZDebug::writeWarning( 'Unknown sort order: ' . $sortOrder, 'eZContentObjectTreeNode::sortFieldName' );
03007             case 1:
03008                 return 'path';
03009             case 2:
03010                 return 'published';
03011             case 3:
03012                 return 'modified';
03013             case 4:
03014                 return 'section';
03015             case 5:
03016                 return 'depth';
03017             case 6:
03018                 return 'class_identifier';
03019             case 7:
03020                 return 'class_name';
03021             case 8:
03022                 return 'priority';
03023             case 9:
03024                 return 'name';
03025             case 10:
03026                 return 'modified_subnode';
03027         }
03028     }
03029 
03030     /*!
03031      \return the field name for the sort order number \a $sortOrder.
03032              Gives a warning if the number is unknown and return \c 'path'.
03033     */
03034     static function sortFieldID( $sortFieldName )
03035     {
03036         switch ( $sortFieldName )
03037         {
03038             default:
03039                 eZDebug::writeWarning( 'Unknown sort order: ' . $sortFieldName, 'eZContentObjectTreeNode::sortFieldID()' );
03040             case 'path':
03041                 return 1;
03042             case 'published':
03043                 return 2;
03044             case 'modified':
03045                 return 3;
03046             case 'section':
03047                 return 4;
03048             case 'depth':
03049                 return 5;
03050             case 'class_identifier':
03051                 return 6;
03052             case 'class_name':
03053                 return 7;
03054             case 'priority':
03055                 return 8;
03056             case 'name':
03057                 return 9;
03058             case 'modified_subnode':
03059                 return 10;
03060         }
03061     }
03062 
03063     /*!
03064      \return an array which defines the sorting method for this node.
03065      The array will contain one element which is an array with sort field
03066      and sort order.
03067     */
03068     function sortArray()
03069     {
03070         return eZContentObjectTreeNode::sortArrayBySortFieldAndSortOrder( $this->attribute( 'sort_field' ),
03071                                                                           $this->attribute( 'sort_order' ) );
03072     }
03073 
03074     /*!
03075      \static
03076      \return an array which defines the sorting method for this node.
03077      The array will contain one element which is an array with sort field
03078      and sort order.
03079     */
03080     static function sortArrayBySortFieldAndSortOrder( $sortField, $sortOrder )
03081     {
03082         return array( array( eZContentObjectTreeNode::sortFieldName( $sortField ),
03083                               $sortOrder ) );
03084     }
03085 
03086     /*!
03087      Will assign a section to the current node and all child objects.
03088      Only main node assignments will be updated.
03089      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
03090      the calls within a db transaction; thus within db->begin and db->commit.
03091     */
03092     static function assignSectionToSubTree( $nodeID, $sectionID, $oldSectionID = false )
03093     {
03094         $db = eZDB::instance();
03095 
03096         $node = eZContentObjectTreeNode::fetch( $nodeID );
03097         $nodePath =  $node->attribute( 'path_string' );
03098 
03099         $sectionID =(int) $sectionID;
03100 
03101         $pathString = " path_string like '$nodePath%' AND ";
03102 
03103         // fetch the object id's which needs to be updated
03104         $objectIDArray = $db->arrayQuery( "SELECT
03105                                                    ezcontentobject.id
03106                                             FROM
03107                                                    ezcontentobject_tree, ezcontentobject
03108                                             WHERE
03109                                                   $pathString
03110                                                   ezcontentobject_tree.contentobject_id=ezcontentobject.id AND
03111                                                   ezcontentobject_tree.main_node_id=ezcontentobject_tree.node_id" );
03112         if ( count( $objectIDArray ) == 0 )
03113             return;
03114 
03115         // Who assigns which section at which node should be logged.
03116         //include_once( 'kernel/classes/ezsection.php' );
03117         $section = eZSection::fetch( $sectionID );
03118         $object = $node->object();
03119         //include_once( "kernel/classes/ezaudit.php" );
03120         eZAudit::writeAudit( 'section-assign', array( 'Section ID' => $sectionID, 'Section name' => $section->attribute( 'name' ),
03121                                                       'Node ID' => $nodeID,
03122                                                       'Content object ID' => $object->attribute( 'id' ),
03123                                                       'Content object name' => $object->attribute( 'name' ),
03124                                                       'Comment' => 'Assigned a section to the current node and all child objects: eZContentObjectTreeNode::assignSectionToSubTree()' ) );
03125 
03126         $objectSimpleIDArray = array();
03127         $inSQL   = array();
03128         $inSQLs  = array();
03129         $counter = 0;
03130         foreach ( $objectIDArray as $objectID )
03131         {
03132             $objectSimpleIDArray[] = $objectID['id'];
03133             if ( $counter < 99 )
03134             {
03135                 $inSQL[] = $objectID['id'];
03136                 ++$counter;
03137             }
03138             else
03139             {
03140                 $inSQL[]  = $objectID['id'];
03141                 $counter  = 0;
03142                 $inSQLs[] = $inSQL;
03143                 $inSQL    = array();
03144             }
03145         }
03146         $inSQLs[] = $inSQL;
03147 
03148         $filterPart = '';
03149         if ( $oldSectionID !== false )
03150         {
03151             $oldSectionID =(int) $oldSectionID;
03152             $filterPart = " section_id = '$oldSectionID' and ";
03153         }
03154 
03155         $sets = count( $inSQLs );
03156 
03157         $db->begin();
03158         for ( $i = 0; $i < $sets; ++$i )
03159         {
03160             $inPart = implode( ',', $inSQLs[$i] );
03161             $db->query( "UPDATE ezcontentobject SET section_id='$sectionID' WHERE $filterPart id IN ( $inPart )" );
03162             $db->query( "UPDATE ezsearch_object_word_link SET section_id='$sectionID' WHERE $filterPart contentobject_id IN ( $inPart )" );
03163         }
03164         $db->commit();
03165 
03166         // clear caches for updated objects
03167         eZContentObject::clearCache( $objectSimpleIDArray );
03168     }
03169 
03170     /*!
03171      \static
03172      Updates the main node selection for the content object \a $objectID.
03173 
03174      \param $mainNodeID The ID of the node that should be that main node
03175      \param $objectID The ID of the object that all nodes belong to
03176      \param $version The version of the object to update node assignments, use \c false for currently published version.
03177      \param $parentMainNodeID The ID of the parent node of the new main placement
03178 
03179      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
03180      the calls within a db transaction; thus within db->begin and db->commit.
03181     */
03182     static function updateMainNodeID( $mainNodeID, $objectID, $version = false, $parentMainNodeID, $updateSection = true )
03183     {
03184         $mainNodeID = (int)$mainNodeID;
03185         $parentMainNodeID = (int)$parentMainNodeID;
03186         $objectID = (int)$objectID;
03187         $version = (int)$version;
03188 
03189         $db = eZDB::instance();
03190         $db->begin();
03191         $db->query( "UPDATE ezcontentobject_tree SET main_node_id=$mainNodeID WHERE contentobject_id=$objectID" );
03192         if ( !$version )
03193         {
03194             $rows = $db->arrayQuery( "SELECT current_version FROM ezcontentobject WHERE id=$objectID" );
03195             $version = $rows[0]['current_version'];
03196         }
03197         $db->query( "UPDATE eznode_assignment SET is_main=1 WHERE contentobject_id=$objectID AND contentobject_version=$version AND parent_node=$parentMainNodeID" );
03198         $db->query( "UPDATE eznode_assignment SET is_main=0 WHERE contentobject_id=$objectID AND contentobject_version=$version AND parent_node!=$parentMainNodeID" );
03199 
03200         $contentObject = eZContentObject::fetch( $objectID );
03201         $parentContentObject = eZContentObject::fetchByNodeID( $parentMainNodeID );
03202         if ( $updateSection && $contentObject->attribute( 'section_id' ) != $parentContentObject->attribute( 'section_id' ) )
03203         {
03204             $newSectionID = $parentContentObject->attribute( 'section_id' );
03205             eZContentObjectTreeNode::assignSectionToSubTree( $mainNodeID, $newSectionID );
03206         }
03207 
03208         $db->commit();
03209 
03210     }
03211 
03212     function fetchByCRC( $pathStr )
03213     {
03214         eZDebug::writeWarning( "Obsolete: use eZURLAlias instead", 'eZContentObjectTreeNode::fetchByCRC' );
03215         return null;
03216     }
03217 
03218     static function fetchByContentObjectID( $contentObjectID, $asObject = true, $contentObjectVersion = false )
03219     {
03220         $conds = array( 'contentobject_id' => $contentObjectID );
03221         if ( $contentObjectVersion !== false )
03222         {
03223             $conds['contentobject_version'] = $contentObjectVersion;
03224         }
03225         return eZPersistentObject::fetchObjectList( eZContentObjectTreeNode::definition(),
03226                                                     null,
03227                                                     $conds,
03228                                                     null,
03229                                                     null,
03230                                                     $asObject );
03231     }
03232 
03233     static function fetchByRemoteID( $remoteID, $asObject = true )
03234     {
03235         return eZContentObjectTreeNode::fetch( false, false, $asObject, array( "remote_id" => $remoteID ) );
03236     }
03237 
03238     static function fetchByPath( $pathString, $asObject = true )
03239     {
03240         return eZContentObjectTreeNode::fetch( false, false, $asObject, array( "path_string" => $pathString ) );
03241     }
03242 
03243     static function fetchByURLPath( $pathString, $asObject = true )
03244     {
03245         if ( $pathString == "" )
03246         {
03247             eZDebug::writeWarning( 'Can not fetch, given URLPath is empty', 'eZContentObjectTreeNode::fetchByURLPath' );
03248             return null;
03249         }
03250 
03251         return eZContentObjectTreeNode::fetch( false, false, $asObject, array( "path_identification_string" => $pathString ) );
03252     }
03253 
03254     /**
03255      * Fetches path_identification_string for a list of nodes
03256      *
03257      * @param array(int) $nodeList
03258      *
03259      * @return array Associative array
03260      **/
03261     static function fetchAliasesFromNodeList( $nodeList )
03262     {
03263         if ( !is_array( $nodeList ) || count( $nodeList ) < 1 )
03264             return array();
03265 
03266         $db = eZDB::instance();
03267         $where = $db->generateSQLINStatement( $nodeList, 'node_id', false, false, 'int' );
03268         $query = "SELECT node_id, path_identification_string FROM ezcontentobject_tree WHERE $where";
03269         $pathListArray = $db->arrayQuery( $query );
03270         return $pathListArray;
03271     }
03272 
03273     static function findMainNode( $objectID, $asObject = false )
03274     {
03275         $objectID = (int)$objectID;
03276         $query="SELECT ezcontentobject.*,
03277                            ezcontentobject_tree.*,
03278                            ezcontentclass.serialized_name_list as class_serialized_name_list,
03279                            ezcontentclass.identifier as class_identifier,
03280                            ezcontentclass.is_container as is_container
03281                     FROM ezcontentobject_tree,
03282                          ezcontentobject,
03283                          ezcontentclass
03284                     WHERE ezcontentobject_tree.contentobject_id=$objectID AND
03285                           ezcontentobject_tree.main_node_id = ezcontentobject_tree.node_id AND
03286                           ezcontentobject_tree.contentobject_id=ezcontentobject.id AND
03287                           ezcontentclass.version=0  AND
03288                           ezcontentclass.id = ezcontentobject.contentclass_id";
03289         $db = eZDB::instance();
03290         $nodeListArray = $db->arrayQuery( $query );
03291         if ( count( $nodeListArray ) == 1 )
03292         {
03293             if ( $asObject )
03294             {
03295                 $retNodeArray = eZContentObjectTreeNode::makeObjectsArray( $nodeListArray );
03296                 return $retNodeArray[0];
03297             }
03298             else
03299             {
03300                 return $nodeListArray[0]['node_id'];
03301             }
03302 
03303         }
03304         else if ( count( $nodeListArray ) > 1 )
03305         {
03306             eZDebug::writeError( $nodeListArray , "There are more then one main_node for objectID: $objectID" );
03307         }
03308 
03309         return null;
03310     }
03311 
03312     /**
03313      * Fetches the main nodes for an array of object id's
03314      * @param array(int) $objectIDArray an array of object IDs
03315      * @param bool $asObject
03316      *        Wether to return the result as an array of eZContentObjectTreeNode
03317      *        (true) or as an array of associative arrays (false)
03318      * @return array(array|eZContentObjectTreeNode)
03319      **/
03320     static function findMainNodeArray( $objectIDArray, $asObject = true )
03321     {
03322         if ( count( $objectIDArray ) )
03323         {
03324             $db = eZDB::instance();
03325             $objectIDINSQL = $db->generateSQLINStatement( $objectIDArray, 'ezcontentobject_tree.contentobject_id', false, false, 'int' );
03326             $query="SELECT ezcontentobject.*,
03327                            ezcontentobject_tree.*,
03328                            ezcontentclass.serialized_name_list as class_serialized_name_list,
03329                            ezcontentclass.identifier as class_identifier,
03330                            ezcontentclass.is_container as is_container
03331                     FROM ezcontentobject_tree,
03332                          ezcontentobject,
03333                          ezcontentclass
03334                     WHERE $objectIDINSQL AND
03335                           ezcontentobject_tree.main_node_id = ezcontentobject_tree.node_id AND
03336                           ezcontentobject_tree.contentobject_id=ezcontentobject.id AND
03337                           ezcontentclass.version=0  AND
03338                           ezcontentclass.id = ezcontentobject.contentclass_id";
03339 
03340             $nodeListArray = $db->arrayQuery( $query );
03341             if ( $asObject )
03342             {
03343                 $retNodeArray = eZContentObjectTreeNode::makeObjectsArray( $nodeListArray );
03344                 return $retNodeArray;
03345             }
03346             else
03347             {
03348                 return $nodeListArray;
03349             }
03350         }
03351         return null;
03352     }
03353 
03354 
03355     /*!
03356      \static
03357      Fetch node by $nodeID. If $nodeID is an array of ids then list of nodes will be returned.
03358     */
03359     static function fetch( $nodeID = false, $lang = false, $asObject = true, $conditions = false )
03360     {
03361         $returnValue = null;
03362         $db = eZDB::instance();
03363         if ( ( is_numeric( $nodeID ) && $nodeID == 1 ) ||
03364              ( is_array( $nodeID ) && count( $nodeID ) === 1 && $nodeID[0] == 1 ) )
03365         {
03366             $query = "SELECT *
03367                 FROM ezcontentobject_tree
03368                 WHERE node_id = 1";
03369         }
03370         else
03371         {
03372             $versionNameTables = ', ezcontentobject_name ';
03373             $versionNameTargets = ', ezcontentobject_name.name as name,  ezcontentobject_name.real_translation ';
03374             $versionNameJoins = " and  ezcontentobject_tree.contentobject_id = ezcontentobject_name.contentobject_id and
03375                                   ezcontentobject_tree.contentobject_version = ezcontentobject_name.content_version and ";
03376             if ( $lang )
03377             {
03378                 $lang = $db->escapeString( $lang );
03379                 $versionNameJoins .= " ezcontentobject_name.content_translation = '$lang' ";
03380             }
03381             else
03382             {
03383                 $versionNameJoins .= eZContentLanguage::sqlFilter( 'ezcontentobject_name', 'ezcontentobject' );
03384             }
03385 
03386             $languageFilter = ' AND '.eZContentLanguage::languagesSQLFilter( 'ezcontentobject' );
03387 
03388             $sqlCondition = '';
03389 
03390             if ( $nodeID !== false )
03391             {
03392                 if ( is_array( $nodeID ) )
03393                 {
03394                     if( count( $nodeID ) === 1 )
03395                     {
03396                         $sqlCondition = 'node_id = ' . (int) $nodeID[0] . ' AND ';
03397                     }
03398                     else
03399                     {
03400                         $sqlCondition = $db->generateSQLInStatement( $nodeID, 'node_id', false, true, 'int' ) . ' AND ';
03401                     }
03402                 }
03403                 else
03404                 {
03405                     $sqlCondition = 'node_id = ' . (int) $nodeID . ' AND ';
03406                 }
03407             }
03408 
03409             if ( is_array( $conditions ) )
03410             {
03411                 foreach( $conditions as $key => $condition )
03412                 {
03413                     if ( is_string( $condition ) )
03414                     {
03415                         $condition = $db->escapeString( $condition );
03416                         $condition = "'$condition'";
03417                     }
03418 
03419                     $sqlCondition .= "ezcontentobject_tree." . $db->escapeString( $key ) . "=$condition AND ";
03420                 }
03421             }
03422 
03423             if ( $sqlCondition == '' )
03424             {
03425                 eZDebug::writeWarning( 'Cannot fetch node, emtpy ID or no conditions given', 'eZContentObjectTreeNode::fetch' );
03426                 return $returnValue;
03427             }
03428 
03429             $query="SELECT ezcontentobject.*,
03430                        ezcontentobject_tree.*,
03431                        ezcontentclass.serialized_name_list as class_serialized_name_list,
03432                        ezcontentclass.identifier as class_identifier,
03433                        ezcontentclass.is_container as is_container
03434                        $versionNameTargets
03435                 FROM ezcontentobject_tree,
03436                      ezcontentobject,
03437                      ezcontentclass
03438                      $versionNameTables
03439                 WHERE $sqlCondition
03440                       ezcontentobject_tree.contentobject_id=ezcontentobject.id AND
03441                       ezcontentclass.version=0  AND
03442                       ezcontentclass.id = ezcontentobject.contentclass_id
03443                       $languageFilter
03444                       $versionNameJoins";
03445         }
03446         $nodeListArray = $db->arrayQuery( $query );
03447 
03448         if ( count( $nodeListArray ) > 0 )
03449         {
03450             if ( $asObject )
03451             {
03452                 $returnValue = eZContentObjectTreeNode::makeObjectsArray( $nodeListArray );
03453                 if ( count( $returnValue ) === 1 )
03454                     $returnValue = $returnValue[0];
03455             }
03456             else
03457             {
03458                 if ( count( $nodeListArray ) === 1 )
03459                     $returnValue = $nodeListArray[0];
03460                 else
03461                     $returnValue = $nodeListArray;
03462             }
03463         }
03464 
03465         return $returnValue;
03466     }
03467 
03468     /*!
03469      \static
03470      Finds the node for the object \a $contentObjectID which placed as child of node \a $parentNodeID.
03471      \return An eZContentObjectTreeNode object or \c null if no node was found.
03472     */
03473     static function fetchNode( $contentObjectID, $parentNodeID )
03474     {
03475         $returnValue = null;
03476         $ini = eZINI::instance();
03477         $db = eZDB::instance();
03478         $contentObjectID =(int) $contentObjectID;
03479         $parentNodeID =(int) $parentNodeID;
03480         $query = "SELECT ezcontentobject_tree.*
03481                   FROM ezcontentobject_tree, ezcontentobject
03482                   WHERE ezcontentobject_tree.contentobject_id = '$contentObjectID' AND
03483                         ezcontentobject.id = '$contentObjectID' AND
03484                         ezcontentobject_tree.parent_node_id = '$parentNodeID' AND ".
03485                         eZContentLanguage::languagesSQLFilter( 'ezcontentobject' );
03486 
03487         $nodeListArray = $db->arrayQuery( $query );
03488         if ( count( $nodeListArray ) == 1 )
03489         {
03490             $retNodeArray = eZContentObjectTreeNode::makeObjectsArray( $nodeListArray, false );
03491             $returnValue = $retNodeArray[0];
03492         }
03493         return $returnValue;
03494     }
03495 
03496     /*!
03497      \note The reference for the return value is required to workaround
03498            a bug with PHP references.
03499     */
03500     function fetchParent()
03501     {
03502         return $this->fetch( $this->attribute( 'parent_node_id' ) );
03503     }
03504 
03505     /*!
03506      \note The reference for the return value is required to workaround
03507            a bug with PHP references.
03508     */
03509     function pathArray()
03510     {
03511         $pathString = $this->attribute( 'path_string' );
03512         $pathItems = explode( '/', $pathString );
03513         $pathArray = array();
03514         foreach ( $pathItems as $pathItem )
03515         {
03516             if ( $pathItem != '' )
03517                 $pathArray[] = (int) $pathItem;
03518         }
03519         return $pathArray;
03520     }
03521 
03522 
03523     function fetchPath()
03524     {
03525         $nodePath = $this->attribute( 'path_string' );
03526 
03527         return eZContentObjectTreeNode::fetchNodesByPathString( $nodePath, false, true );
03528     }
03529 
03530     /*!
03531      \static
03532      \return An array with content node objects that is present in the node path \a $nodePath.
03533      \param $withLastNode If \c true the last node in the path is included in the list.
03534                           The last node is the node which the path was fetched from.
03535      \param $asObjects If \c true then return PHP objects, if not return raw row data.
03536      \param $limit maximum number of nodes in the path to use, starting from last node
03537     */
03538     static function fetchNodesByPathString( $nodePath, $withLastNode = false, $asObjects = true, $limit = false )
03539     {
03540         $nodesListArray = array();
03541         $pathString = eZContentObjectTreeNode::createNodesConditionSQLStringFromPath( $nodePath, $withLastNode, $limit );
03542 
03543         if ( $pathString  )
03544         {
03545             $useVersionName     = true;
03546             $versionNameTables  = eZContentObjectTreeNode::createVersionNameTablesSQLString ( $useVersionName );
03547             $versionNameTargets = eZContentObjectTreeNode::createVersionNameTargetsSQLString( $useVersionName );
03548             $versionNameJoins   = eZContentObjectTreeNode::createVersionNameJoinsSQLString  ( $useVersionName );
03549 
03550             $query = "SELECT ezcontentobject.*,
03551                              ezcontentobject_tree.*,
03552                              ezcontentclass.serialized_name_list as class_serialized_name_list,
03553                              ezcontentclass.identifier as class_identifier
03554                              $versionNameTargets
03555                       FROM ezcontentobject_tree,
03556                            ezcontentobject,
03557                            ezcontentclass
03558                            $versionNameTables
03559                       WHERE $pathString
03560                             ezcontentobject_tree.contentobject_id=ezcontentobject.id  AND
03561                             ezcontentclass.version=0 AND
03562                             ezcontentclass.id = ezcontentobject.contentclass_id
03563                             $versionNameJoins
03564                       ORDER BY path_string";
03565 
03566             $db = eZDB::instance();
03567             $nodesListArray = $db->arrayQuery( $query );
03568         }
03569 
03570         if ( $asObjects )
03571         {
03572             return eZContentObjectTreeNode::makeObjectsArray( $nodesListArray );
03573         }
03574         return $nodesListArray;
03575     }
03576 
03577 
03578     /*!
03579      \static
03580      Extracts each node that in the path from db and returns an array of class identifiers
03581      \param $nodePath A string containing the path of the node, it consists of
03582                       node IDs starting from the root and delimited by / (slash).
03583      \param $withLastNode If \c true the last node in the path is included in the list.
03584                           The last node is the node which the path was fetched from.
03585      \param $limit maximum number of nodes in the path to use, starting from last node
03586      \return An array with class identifier and node ID.
03587 
03588      Example
03589      \code
03590      $list = fetchClassIdentifierListByPathString( '/2/10/', false );
03591      \endcode
03592     */
03593     static function fetchClassIdentifierListByPathString( $nodePath, $withLastNode, $limit = false )
03594     {
03595         $itemList = array();
03596         $nodes = eZContentObjectTreeNode::fetchNodesByPathString( $nodePath, $withLastNode, false, $limit );
03597 
03598         foreach ( $nodes as $node )
03599         {
03600             $itemList[]  = array( 'node_id'          => $node['node_id'],
03601                                   'class_identifier' => $node['class_identifier'] );
03602         }
03603 
03604         return $itemList;
03605     }
03606 
03607     /*!
03608      \deprecated This function should no longer be used, use the eZContentClass::instantiate and eZNodeAssignment::create instead.
03609     */
03610     function createObject( $contentClassID, $parentNodeID = 2 )
03611     {
03612         $user = eZUser::currentUser();
03613         $userID = $user->attribute( 'contentobject_id' );
03614 
03615         $class = eZContentClass::fetch( $contentClassID );
03616         $parentNode = eZContentObjectTreeNode::fetch( $parentNodeID );
03617         $parentContentObject = $parentNode->attribute( 'object' );
03618         $sectionID = $parentContentObject->attribute( 'section_id' );
03619         $object = $class->instantiate( $userID, $sectionID );
03620 
03621 //        $parentContentObject = $parentNode->attribute( 'contentobject' );
03622 
03623         $node = eZContentObjectTreeNode::addChildTo( $object->attribute( "id" ), $parentNodeID, true );
03624 //        $object->setAttribute( "main_node_id", $node->attribute( 'node_id' ) );
03625         $node->setAttribute( 'main_node_id', $node->attribute( 'node_id' ) );
03626         $object->store();
03627         $node->store();
03628 
03629         return $object;
03630     }
03631 
03632     /*!
03633      Add a child for this node to the object tree.
03634      \param $contentobjectID      The ID of the contentobject the child-node should point to.
03635      \param $asObject             If true it will return the new child-node as an object, if not it returns the ID.
03636      \param $contentObjectVersion The version to use on the newly created child-node, if
03637                                   false it uses the current_version of the specified object.
03638      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
03639      the calls within a db transaction; thus within db->begin and db->commit.
03640     */
03641     function addChild( $contentobjectID, $asObject = false, $contentObjectVersion = false )
03642     {
03643         return self::addChildTo( $contentobjectID, $this->attribute( 'node_id' ), $asObject, $contentObjectVersion );
03644     }
03645 
03646     /*!
03647      Add a child to the object tree.
03648      \param $contentobjectID      The ID of the contentobject the child-node should point to.
03649      \param $nodeID               The ID of the parent-node to add child-node to.
03650      \param $asObject             If true it will return the new child-node as an object, if not it returns the ID.
03651      \param $contentObjectVersion The version to use on the newly created child-node, if
03652                                   false it uses the current_version of the specified object.
03653      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
03654      the calls within a db transaction; thus within db->begin and db->commit.
03655     */
03656     static function addChildTo( $contentobjectID, $nodeID, $asObject = false, $contentObjectVersion = false )
03657     {
03658         $node = eZContentObjectTreeNode::fetch( $nodeID );
03659         $contentObject = eZContentObject::fetch( $contentobjectID );
03660         if ( !$contentObject )
03661         {
03662             return false;
03663         }
03664 
03665         if ( !$contentObjectVersion )
03666         {
03667             $contentObjectVersion = $contentObject->attribute( 'current_version' );
03668         }
03669 
03670         $db = eZDB::instance();
03671         $parentMainNodeID = $node->attribute( 'node_id' ); //$parent->attribute( 'main_node_id' );
03672         $parentPath = $node->attribute( 'path_string' );
03673         $parentDepth = $node->attribute( 'depth' );
03674         $isInvinsible = $node->attribute( 'is_invisible' );
03675 
03676         $nodeDepth = $parentDepth + 1 ;
03677 
03678         $insertedNode = eZContentObjectTreeNode::create( $parentMainNodeID, $contentobjectID );
03679 
03680         // set default sorting from content class
03681         $contentClass = $contentObject->attribute( 'content_class' );
03682         $insertedNode->setAttribute( 'sort_field', $contentClass->attribute( 'sort_field' ) );
03683         $insertedNode->setAttribute( 'sort_order', $contentClass->attribute( 'sort_order' ) );
03684 
03685         $insertedNode->setAttribute( 'depth', $nodeDepth );
03686         $insertedNode->setAttribute( 'path_string', '/TEMPPATH' );
03687 
03688         $insertedNode->setAttribute( 'contentobject_version', $contentObjectVersion );
03689 
03690         // If the parent node is invisible, the new created node should be invisible as well.
03691         $insertedNode->setAttribute( 'is_invisible', $isInvinsible );
03692 
03693         $db->begin();
03694         $insertedNode->store();
03695         $insertedID = $insertedNode->attribute( 'node_id' );
03696         $newNodePath = $parentPath . $insertedID . '/';
03697         $insertedNode->setAttribute( 'path_string', $newNodePath );
03698         $insertedNode->store();
03699         $db->commit();
03700 
03701         if ( $asObject )
03702         {
03703             return $insertedNode;
03704         }
03705         else
03706         {
03707             return $insertedID;
03708         }
03709     }
03710 
03711     /*!
03712      \return an url alias for the current node. It will generate a unique alias.
03713     */
03714     function pathWithNames( $regenerateCurrent = false )
03715     {
03716         // Only set name if current node is not the content root
03717         $ini = eZINI::instance( 'content.ini' );
03718         $contentRootID = $ini->variable( 'NodeSettings', 'RootNode' );
03719         if ( $this->attribute( 'node_id' ) != $contentRootID )
03720         {
03721             $pathArray = $this->pathArray();
03722             // Get rid of node with ID 1 (a special node)
03723             array_shift( $pathArray );
03724             if ( $regenerateCurrent )
03725             {
03726                 // Get rid of current node, path element for this will be calculated
03727                 array_pop( $pathArray );
03728             }
03729             if ( count( $pathArray ) == 0 )
03730             {
03731                 $path = '';
03732             }
03733             else
03734             {
03735                 //include_once( 'kernel/classes/ezurlaliasml.php' );
03736                 $path = eZURLAliasML::fetchPathByActionList( "eznode", $pathArray );
03737             }
03738 
03739             // Fallback in case fetchPathByActionList() fails,
03740             // then we ask for the path from the parent and generate the current
03741             // entry ourselves.
03742             if ( $path === null )
03743             {
03744                 if ( $this->attribute( 'depth' ) == 0 ) // Top node should just return empty string
03745                 {
03746                     return '';
03747                 }
03748 
03749                 eZDebug::writeError( __CLASS__ . "::" . __FUNCTION__ . "() failed to fetch path of node " . $this->attribute( 'node_id' ) . ", falling back to generated url entries. Run updateniceurls.php to fix the problem." );
03750 
03751                 // Return a perma-link when the path lookup failed, this link will always work
03752                 $path = 'content/view/full/' . $this->attribute( 'node_id' );
03753                 return $path;
03754             }
03755 
03756             if ( $regenerateCurrent )
03757             {
03758                 $nodeName = $this->attribute( 'name' );
03759                 $nodeName = eZURLAliasML::convertToAlias( $nodeName, 'node_' . $this->attribute( 'node_id' ) );
03760 
03761                 if ( $path != '' )
03762                 {
03763                     $path .= '/' . $nodeName ;
03764                 }
03765                 else
03766                 {
03767                     $path  = $nodeName ;
03768                 }
03769             }
03770         }
03771         else
03772         {
03773             $path = '';
03774         }
03775 
03776         if ( $regenerateCurrent )
03777         {
03778             $path = $this->checkPath( $path );
03779         }
03780         return $path;
03781     }
03782 
03783     /*!
03784      Check if a node with the same name already exists. If so create a $name + __x value.
03785     */
03786     function checkPath( $path )
03787     {
03788         $path = eZURLAliasML::cleanURL( $path );
03789         $elements = explode( "/", $path );
03790         $element = array_pop( $elements );
03791         return $this->adjustPathElement( $element );
03792     }
03793 
03794     /*!
03795      Checks the path element $element against reserved words and existing elements.
03796      If the path element is already used, it will append a number and try again.
03797 
03798      The adjusted path element is returned.
03799 
03800      \param $element The desired url element name
03801      \param $useParentFromNodeObject Use the parent from node object as a base
03802                                      for checking name collisions. This is needed
03803                                      when moving nodes, and the url entries are
03804                                      not updated yet.
03805 
03806      \code
03807      echo $node->adjustPathElement( 'Content' ); // outputs Content1
03808      \endcode
03809      */
03810     function adjustPathElement( $element, $useParentFromNodeObject = false )
03811     {
03812         $nodeID       = (int)$this->attribute( 'node_id' );
03813         $parentNodeID = (int)$this->attribute( 'parent_node_id' );
03814         $action       = "eznode:" . $nodeID;
03815 
03816         $elements = eZURLAliasML::fetchByAction( 'eznode', $nodeID );
03817         if ( count( $elements ) > 0 and !$useParentFromNodeObject )
03818         {
03819             $parentElementID = (int)$elements[0]->attribute( 'parent' );
03820             return eZURLAliasML::findUniqueText( $parentElementID, $element, $action );
03821         }
03822         else
03823         {
03824             $parentElements = eZURLAliasML::fetchByAction( 'eznode', $parentNodeID );
03825             if ( count( $parentElements ) > 0 && $parentElements[0]->attribute( 'text' ) != '' )
03826             {
03827                 // Pick one of the parents and get the ID
03828                 $parentElementID = (int)$parentElements[0]->attribute( 'id' );
03829                 return eZURLAliasML::findUniqueText( $parentElementID, $element, $action );
03830             }
03831         }
03832         return eZURLAliasML::findUniqueText( 0, $element, $action );
03833     }
03834 
03835     /*!
03836      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
03837      the calls within a db transaction; thus within db->begin and db->commit.
03838      \deprecated Use updateSubTreePath() instead.
03839      */
03840     function updateURLAlias()
03841     {
03842         eZDebug::writeWarning( __CLASS__ . "::" . __FUNCTION__ . " is deprecated, use updateSubTreePath() instead" );
03843         return $this->updateSubTreePath();
03844     }
03845 
03846     /*!
03847      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
03848      the calls within a db transaction; thus within db->begin and db->commit.
03849      */
03850     function updateSubTreePath( $updateParent = true, $nodeMove = false )
03851     {
03852         //include_once( 'kernel/classes/ezurlaliasml.php' );
03853 
03854         $changeCount = 0;
03855 
03856         $nodeID       = $this->attribute( 'node_id' );
03857         $parentNodeID = $this->attribute( 'parent_node_id' );
03858 
03859         // Only set name if current node is not the content root
03860         $ini = eZINI::instance( 'content.ini' );
03861         $contentRootID = $ini->variable( 'NodeSettings', 'RootNode' );
03862         $obj           = $this->object();
03863         $alwaysMask    = ( $obj->attribute( 'language_mask' ) & 1 );
03864         $languages     = $obj->allLanguages();
03865         $nameList      = array();
03866 
03867         $initialLanguageID      = $obj->attribute( 'initial_language_id' );
03868         $pathIdentificationName = false;
03869         foreach ( $languages as $language )
03870         {
03871             $nodeName = '';
03872             if ( $nodeID != $contentRootID )
03873             {
03874                 $objClass = $obj->attribute( 'content_class' );
03875                 $nodeName = $objClass->urlAliasName( $obj, false, $language->attribute( 'locale' ) );
03876                 //include_once( 'kernel/classes/ezurlaliasfilter.php' );
03877                 $nodeName = eZURLAliasFilter::processFilters( $nodeName, $language, $this );
03878                 $nodeName = eZURLAliasML::convertToAlias( $nodeName, 'node_' . $nodeID );
03879                 $nodeName = $this->adjustPathElement( $nodeName, $nodeMove );
03880 
03881                 // Compatability mode:
03882                 // Store name for the 'path_identification_string' column.
03883                 if ( $initialLanguageID == $language->attribute( 'id' ) )
03884                 {
03885                     $pathIdentificationName = eZURLAliasML::convertToAliasCompat( $nodeName, 'node_' . $nodeID );
03886                 }
03887             }
03888             $nameList[] = array( 'text'     => $nodeName,
03889                                  'language' => $language );
03890         }
03891 
03892         $parentActionName  = "eznode";
03893         $parentActionValue = $parentNodeID;
03894 
03895         $parentElementID = false;
03896         $existingElements = eZURLAliasML::fetchByAction( "eznode", $nodeID );
03897         $existingElementID = null;
03898         if ( count( $existingElements ) > 0 )
03899         {
03900             $existingElementID = $existingElements[0]->attribute( 'id' );
03901             $parentElementID = $existingElements[0]->attribute( 'parent' );
03902         }
03903 
03904         // If we have parent element it means the node is already published
03905         // and we have to see if it has been moved
03906         if ( $parentNodeID != 1 and $updateParent )
03907         {
03908             $parents = eZURLAliasML::fetchByAction( "eznode", $parentNodeID );
03909             if ( count( $parents ) == 0 )
03910             {
03911                 $parentNode = $this->fetchParent();
03912 
03913                 if ( !$parentNode )
03914                 {
03915                     return false;
03916                 }
03917 
03918                 $result = $parentNode->updateSubTreePath();
03919                 if ( !$result )
03920                 {
03921                     return false;
03922                 }
03923                 $parents = eZURLAliasML::fetchByAction( $parentActionName, $parentActionValue );
03924                 if ( count( $parents ) == 0 )
03925                 {
03926                     return false;
03927                 }
03928                 $oldParentElementID = $parentElementID;
03929                 foreach ( $parents as $paren )
03930                 {
03931                     $parentElementID = 0;
03932                     if ( $paren->attribute( 'text' ) != '' )
03933                     {
03934                         $parentElementID = (int)$paren->attribute( 'link' );
03935                         break;
03936                     }
03937                 }
03938             }
03939             else
03940             {
03941                 $oldParentElementID = $parentElementID;
03942                 $parentElementID = 0;
03943                 foreach ( $parents as $paren )
03944                 {
03945                     if ( $paren->attribute( 'text' ) != '' )
03946                     {
03947                         $parentElementID = (int)$paren->attribute( 'link' );
03948                         break;
03949                     }
03950                 }
03951             }
03952         }
03953         else // Parent is ID 1, ie. this node is top-level
03954         {
03955         }
03956 
03957         $this->updatePathIdentificationString( $pathIdentificationName );
03958 
03959         $languageID = $obj->attribute( 'initial_language_id' );
03960         $cleanup    = false;
03961         foreach ( $nameList as $nameEntry )
03962         {
03963             $text     = $nameEntry['text'];
03964             $language = $nameEntry['language'];
03965             $result = eZURLAliasML::storePath( $text, 'eznode:' . $nodeID, $language, false, $alwaysMask, $parentElementID, $cleanup );
03966             if ( $result['status'] === true )
03967                 $changeCount++;
03968         }
03969         return $changeCount;
03970     }
03971 
03972     /*!
03973      \private
03974      Updates the path_identification_string field in ezcontentobject_tree by
03975      fetching the value from the parent and appending $pathIdentificationName.
03976 
03977      \note This stores the current object to the database
03978      */
03979     function updatePathIdentificationString( $pathIdentificationName )
03980     {
03981         // Update the path_identification_string column for the node
03982         $pathIdentificationString = '';
03983         if ( $this->attribute( 'parent_node_id' ) != 1 )
03984         {
03985             if ( !isset( $parentNode ) )
03986                 $parentNode = $this->fetchParent();
03987             $pathIdentificationString = $parentNode->attribute( 'path_identification_string' );
03988         }
03989         if ( strlen( $pathIdentificationString ) > 0 )
03990             $pathIdentificationString .= '/' . $pathIdentificationName;
03991         else
03992             $pathIdentificationString = $pathIdentificationName;
03993         if ( $this->attribute( 'path_identification_string' ) != $pathIdentificationString )
03994         {
03995             $this->setAttribute( 'path_identification_string', $pathIdentificationString );
03996             $this->sync();
03997         }
03998     }
03999 
04000     /*!
04001      \static
04002      \sa removeThis
04003     */
04004     static function removeNode( $nodeID = 0 )
04005     {
04006         $node = eZContentObjectTreeNode::fetch( $nodeID );
04007         if ( !is_object( $node ) )
04008         {
04009             return;
04010         }
04011 
04012         return $node->removeThis();
04013     }
04014 
04015     /*!
04016       Removes the current node.
04017 
04018       \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
04019      the calls within a db transaction; thus within db->begin and db->commit.
04020     */
04021     function removeThis( )
04022     {
04023         //include_once( "kernel/classes/ezrole.php" );
04024         //include_once( "kernel/classes/ezpolicy.php" );
04025         //include_once( "kernel/classes/ezpolicylimitation.php" );
04026 
04027         $ini = eZINI::instance();
04028 
04029         //include_once( "kernel/classes/ezaudit.php" );
04030         if ( eZAudit::isAuditEnabled() )
04031         {
04032             // Set audit params.
04033             $nodeIDAudit = $this->attribute( 'node_id' );
04034             $object = $this->object();
04035             $objectID = $object->attribute( 'id' );
04036             $objectName = $object->attribute( 'name' );
04037 
04038             eZAudit::writeAudit( 'content-delete', array( 'Node ID' => $nodeIDAudit, 'Object ID' => $objectID, 'Content Name' => $objectName,
04039                                                           'Comment' => 'Removed the current node: eZContentObjectTreeNode::removeNode()' ) );
04040         }
04041 
04042         $db = eZDB::instance();
04043         $db->begin();
04044 
04045         $nodePath = $this->attribute( 'path_string' );
04046         $childrensPath = $nodePath ;
04047 
04048         $pathString = " path_string like '$childrensPath%' ";
04049 
04050         $urlAlias = $this->attribute( 'url_alias' );
04051 
04052         // Remove static cache
04053         if ( $ini->variable( 'ContentSettings', 'StaticCache' ) == 'enabled' )
04054         {
04055             //include_once( 'kernel/classes/ezstaticcache.php' );
04056             $staticCache = new eZStaticCache();
04057             $staticCache->removeURL( "/" . $urlAlias );
04058             $staticCache->generateAlwaysUpdatedCache();
04059 
04060             $parent = $this->fetchParent();
04061         }
04062 
04063         $db->query( "DELETE FROM ezcontentobject_tree
04064                             WHERE $pathString OR
04065                             path_string = '$nodePath'" );
04066 
04067         // Re-cache parent node
04068         if ( $ini->variable( 'ContentSettings', 'StaticCache' ) == 'enabled' )
04069         {
04070             if ( $parent )
04071             {
04072                 $staticCache->cacheURL( "/" . $parent->urlAlias() );
04073             }
04074         }
04075 
04076         // Clean up URL alias entries
04077         eZURLAliasML::removeByAction( 'eznode', $this->attribute( 'node_id' ) );
04078 
04079         // Clean up content cache
04080         //include_once( 'kernel/classes/ezcontentcachemanager.php' );
04081         eZContentCacheManager::clearContentCacheIfNeeded( $this->attribute( 'contentobject_id' ) );
04082 
04083         $parentNode = $this->attribute( 'parent' );
04084         if ( is_object( $parentNode ) )
04085         {
04086             eZContentCacheManager::clearContentCacheIfNeeded( $parentNode->attribute( 'contentobject_id' ) );
04087             $parentNode->updateAndStoreModified();
04088         }
04089 
04090         // Clean up policies and limitations
04091         eZRole::cleanupByNode( $this );
04092 
04093         // Clean up recent items
04094         $nodeID = $this->attribute( 'node_id' );
04095         //include_once( 'kernel/classes/ezcontentbrowserecent.php' );
04096         eZContentBrowseRecent::removeRecentByNodeID( $nodeID );
04097 
04098         // Clean up bookmarks
04099         //include_once( 'kernel/classes/ezcontentbrowsebookmark.php' );
04100         eZContentBrowseBookmark::removeByNodeID( $nodeID );
04101 
04102         // Clean up tip-a-friend counter
04103         //include_once( 'kernel/classes/eztipafriendcounter.php' );
04104         eZTipafriendCounter::removeForNode( $nodeID );
04105 
04106         // Clean up view counter
04107         //include_once( 'kernel/classes/ezviewcounter.php' );
04108         eZViewCounter::removeCounter( $nodeID );
04109 
04110         $db->commit();
04111     }
04112 
04113     /*!
04114      \static
04115      Returns information on what will happen if all subtrees in \a $deleteIDArray
04116      is removed. The returned structure is:
04117      - move_to_trash     - \c true if removed objects can be moved to trash,
04118                            some objects are not allowed to be in trash (e.g user).
04119      - total_child_count - The total number of children for all delete items
04120      - can_remove_all    - Will be set to \c true if all selected items can be removed, \c false otherwise
04121      - delete_list - A list of all subtrees that should be removed, structure:
04122      -- node               - The content node
04123      -- object             - The content object
04124      -- class              - The content class
04125      -- node_name          - The name of the node
04126      -- child_count        - Total number of child items below the node
04127      -- can_remove         - Boolean which tells if the user has permission to remove the node
04128      -- can_remove_subtree - Boolean which tells if the user has permission to remove items in the subtree
04129      -- new_main_node_id   - The new main node ID for the node if it needs to be moved, or \c false if not
04130      -- object_node_count  - The number of nodes the object has (before removal)
04131      -- sole_node_count    - The number of nodes in the subtree (excluding current) that does
04132                              not have multiple locations.
04133 
04134      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
04135      the calls within a db transaction; thus within db->begin and db->commit.
04136     */
04137     static function subtreeRemovalInformation( $deleteIDArray )
04138     {
04139         return eZContentObjectTreeNode::removeSubtrees( $deleteIDArray, true, true );
04140     }
04141 
04142     /*!
04143      \static
04144      Will remove the nodes in the subtrees defined in \a $deleteIDArray,
04145      it will only remove the nodes unless there are no more nodes for
04146      an object in which case the object is removed too.
04147 
04148      \param $moveToTrash If \c true it will move the object to trash, if \c false
04149                          the object will be purged from the system.
04150      \param $infoOnly If set to \c true then it will not remove the subtree
04151                       but instead return information on what will happen
04152                       if it is removed. See subtreeRemovalInformation() for the
04153                       returned structure.
04154 
04155      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
04156      the calls within a db transaction; thus within db->begin and db->commit.
04157     */
04158     static function removeSubtrees( $deleteIDArray, $moveToTrash = true, $infoOnly = false )
04159     {
04160         $moveToTrashAllowed = true;
04161         $deleteResult = array();
04162         $totalChildCount = 0;
04163         $totalLoneNodeCount = 0;
04164         $canRemoveAll = true;
04165 
04166         $db = eZDB::instance();
04167         $db->begin();
04168 
04169         $userClassIDArray = eZUser::contentClassIDs();
04170         $usersWereRemoved = false;
04171 
04172         foreach ( $deleteIDArray as $deleteID )
04173         {
04174             $node = eZContentObjectTreeNode::fetch( $deleteID );
04175             if ( $node === null )
04176                 continue;
04177 
04178             $object = $node->attribute( 'object' );
04179             if ( $object === null )
04180                 continue;
04181 
04182             $class = $object->attribute( 'content_class' );
04183             $canRemove = $object->attribute( 'can_remove' );
04184             $canRemoveSubtree = true;
04185 
04186             $nodeID = $node->attribute( 'node_id' );
04187             $nodeName = $object->attribute( 'name' );
04188 
04189             $childCount = 0;
04190             $newMainNodeID = false;
04191             $objectNodeCount = 0;
04192             $readableChildCount = 0;
04193 
04194             if ( $canRemove )
04195             {
04196                 $isUserClass = in_array( $class->attribute( 'id' ), $userClassIDArray );
04197 
04198                 if ( $moveToTrashAllowed and $isUserClass )
04199                 {
04200                     $moveToTrashAllowed = false;
04201                 }
04202                 $readableChildCount = $node->subTreeCount( array( 'Limitation' => array() ) );
04203                 $childCount = $node->subTreeCount();
04204                 $totalChildCount += $childCount;
04205 
04206                 $allAssignedNodes = $object->attribute( 'assigned_nodes' );
04207                 $objectNodeCount = count( $allAssignedNodes );
04208                 // We need to find a new main node ID if we are trying
04209                 // to remove the current main node.
04210                 if ( $node->attribute( 'main_node_id' ) == $nodeID )
04211                 {
04212                     if ( count( $allAssignedNodes ) > 1 )
04213                     {
04214                         foreach( $allAssignedNodes as $assignedNode )
04215                         {
04216                             $assignedNodeID = $assignedNode->attribute( 'node_id' );
04217                             if ( $assignedNodeID == $nodeID )
04218                                 continue;
04219                             $newMainNodeID = $assignedNodeID;
04220                             break;
04221                         }
04222                     }
04223                 }
04224 
04225                 if ( $infoOnly )
04226                 {
04227                     // Find the number of items in the subtree we are allowed to remove
04228                     // if this differs from the total count it means we have items we cannot remove
04229                     // We do this by fetching the limitation list for content/remove
04230                     // and passing it to the subtree count function.
04231                     //include_once( "kernel/classes/datatypes/ezuser/ezuser.php" );
04232                     $currentUser = eZUser::currentUser();
04233                     $accessResult = $currentUser->hasAccessTo( 'content', 'remove' );
04234                     if ( $accessResult['accessWord'] == 'limited' )
04235                     {
04236                         $limitationList = $accessResult['policies'];
04237                         $removeableChildCount = $node->subTreeCount( array( 'Limitation' => $limitationList ) );
04238                         $canRemoveSubtree = ( $removeableChildCount == $childCount );
04239                         $canRemove = $canRemoveSubtree;
04240                     }
04241                 }
04242 
04243                 // We will only remove the subtree if are allowed
04244                 // and are told to do so.
04245                 if ( $canRemove and !$infoOnly )
04246                 {
04247                     $moveToTrashTemp = $moveToTrash;
04248                     if ( !$moveToTrashAllowed )
04249                         $moveToTrashTemp = false;
04250 
04251                     eZContentCacheManager::clearContentCacheIfNeeded( $node->attribute( 'contentobject_id' ) );
04252 
04253                     // Remove children, fetching them by 100 to avoid memory overflow.
04254                     while ( 1 )
04255                     {
04256                         // We should remove the latest subitems first,
04257                         // so we should fetch subitems sorted by 'path_string' DESC
04258                         $children = $node->subTree( array( 'Limitation' => array(),
04259                                                            'SortBy' => array( 'path' , false ),
04260                                                            'Limit' => 100 ) );
04261                         if ( !$children )
04262                             break;
04263 
04264                         foreach ( $children as $child )
04265                         {
04266                             $childObject = $child->attribute( 'object' );
04267                             $child->removeNodeFromTree( $moveToTrashTemp );
04268                             if ( in_array( $childObject->attribute( 'contentclass_id' ), $userClassIDArray ) )
04269                             {
04270                                 eZUser::removeSessionData( $childObject->attribute( 'id' ) );
04271                                 $usersWereRemoved = true;
04272                             }
04273                             eZContentObject::clearCache();
04274                         }
04275                     }
04276 
04277                     $node->removeNodeFromTree( $moveToTrashTemp );
04278 
04279                     if ( $isUserClass )
04280                     {
04281                         eZUser::removeSessionData( $object->attribute( 'id' ) );
04282                         $usersWereRemoved = true;
04283                     }
04284                 }
04285             }
04286             if ( !$canRemove )
04287                 $canRemoveAll = false;
04288 
04289             // Do not create info list if we are removing subtrees
04290             if ( !$infoOnly )
04291                 continue;
04292 
04293             $soleNodeCount = $node->subtreeSoleNodeCount();
04294             $totalLoneNodeCount += $soleNodeCount;
04295             if ( $objectNodeCount <= 1 )
04296                 ++$totalLoneNodeCount;
04297 
04298             $item = array( "nodeName" => $nodeName, // Backwards compatability
04299                            "childCount" => $childCount, // Backwards compatability
04300                            "additionalWarning" => '', // Backwards compatability, this will always be empty
04301                            'node' => $node,
04302                            'object' => $object,
04303                            'class' => $class,
04304                            'node_name' => $nodeName,
04305                            'child_count' => $childCount,
04306                            'object_node_count' => $objectNodeCount,
04307                            'sole_node_count' => $soleNodeCount,
04308                            'can_remove' => $canRemove,
04309                            'can_remove_subtree' => $canRemoveSubtree,
04310                            'real_child_count' => $readableChildCount,
04311                            'new_main_node_id' => $newMainNodeID );
04312             $deleteResult[] = $item;
04313         }
04314 
04315         if ( $usersWereRemoved )
04316         {
04317             // clean up the user-policy cache
04318             eZUser::cleanupCache();
04319         }
04320 
04321         $db->commit();
04322 
04323 
04324         if ( !$infoOnly )
04325             return true;
04326 
04327         if ( $moveToTrashAllowed and $totalLoneNodeCount == 0 )
04328             $moveToTrashAllowed = false;
04329 
04330         return array( 'move_to_trash' => $moveToTrashAllowed,
04331                       'total_child_count' => $totalChildCount,
04332                       'can_remove_all' => $canRemoveAll,
04333                       'delete_list' => $deleteResult,
04334                       'reverse_related_count' => eZContentObjectTreeNode::reverseRelatedCount( $deleteIDArray ) );
04335     }
04336 
04337     /*!
04338      \private
04339      \static
04340      Return reverse related count for specified node
04341 
04342      \param $nodeIDArray, array of node id's
04343 
04344      \return reverse related count.
04345     */
04346     static function reverseRelatedCount( $nodeIDArray )
04347     {
04348         // Select count of all elements having reverse relations. And ignore those items that don't relate to objects other than being removed.
04349         if ( $nodeIDArray === array() )
04350         {
04351             return 0;
04352         }
04353 
04354         foreach( $nodeIDArray as $nodeID )
04355         {
04356             $contentObjectTreeNode = eZContentObjectTreeNode::fetch( $nodeID, false, false );
04357             $tempPathString = $contentObjectTreeNode['path_string'];
04358 
04359             // Create WHERE section
04360             $pathStringArray[] = "tree.path_string like '$tempPathString%'";
04361             $path2StringArray[] = "tree2.path_string like '$tempPathString%'";
04362         }
04363         $path_strings = '( ' . implode( ' OR ', $pathStringArray ) . ' ) ';
04364         $path_strings_where = '( ' . implode( ' OR ', $path2StringArray ) . ' ) ';
04365 
04366         // Total count of sub items
04367         $db = eZDB::instance();
04368         $countOfItems = $db->arrayQuery( "SELECT COUNT( DISTINCT( tree.node_id ) ) as count
04369                                                   FROM  ezcontentobject_tree tree,  ezcontentobject obj,
04370                                                         ezcontentobject_link link LEFT JOIN ezcontentobject_tree tree2
04371                                                         ON link.from_contentobject_id = tree2.contentobject_id
04372                                                   WHERE $path_strings
04373                                                         and link.to_contentobject_id = tree.contentobject_id
04374                                                         and obj.id = link.from_contentobject_id
04375                                                         and obj.current_version = link.from_contentobject_version
04376                                                         and not $path_strings_where" );
04377 
04378         if ( $countOfItems )
04379         {
04380             return $countOfItems[0]['count'];
04381         }
04382     }
04383 
04384     /*!
04385      Will check if you are  removing the main node in which case it relocates
04386      the main node before removing it. It will also remove the object if there
04387      no more node assignments for it.
04388      \param $moveToTrash If \c true it will move the object to trash, if \c false
04389                          the object will be purged from the system.
04390 
04391      \note This uses remove() to do the actual node removal but has some extra logic
04392      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
04393      the calls within a db transaction; thus within db->begin and db->commit.
04394     */
04395     function removeNodeFromTree( $moveToTrash = true )
04396     {
04397         //include_once( 'kernel/classes/ezcontentcachemanager.php' );
04398         $nodeID = $this->attribute( 'node_id' );
04399         if ( $nodeID == $this->attribute( 'main_node_id' ) )
04400         {
04401             $object = $this->object();
04402             $assignedNodes = $object->attribute( 'assigned_nodes' );
04403             if ( count( $assignedNodes ) > 1 )
04404             {
04405                 $newMainNode = false;
04406                 foreach ( $assignedNodes as $assignedNode )
04407                 {
04408                     $assignedNodeID = $assignedNode->attribute( 'node_id' );
04409                     if ( $assignedNodeID == $nodeID )
04410                         continue;
04411                     $newMainNode = $assignedNode;
04412                     break;
04413                 }
04414 
04415                 // We need to change the main node ID before we remove the current node
04416                 $db = eZDB::instance();
04417                 $db->begin();
04418                 eZContentObjectTreeNode::updateMainNodeID( $newMainNode->attribute( 'node_id' ),
04419                                                            $object->attribute( 'id' ),
04420                                                            $object->attribute( 'current_version' ),
04421                                                            $newMainNode->attribute( 'parent_node_id' ) );
04422 
04423                 eZContentCacheManager::clearContentCacheIfNeeded( $this->attribute( 'contentobject_id' ) );
04424                 $this->removeThis();
04425                 $db->commit();
04426             }
04427             else
04428             {
04429                 // This is the last assignment so we remove the object too
04430                 eZContentCacheManager::clearContentCacheIfNeeded( $this->attribute( 'contentobject_id' ) );
04431 
04432                 $db = eZDB::instance();
04433                 $db->begin();
04434                 $this->removeThis();
04435 
04436                 if ( $moveToTrash )
04437                 {
04438                     // saving information about this node in ..trash_node table
04439                     //include_once( 'kernel/classes/ezcontentobjecttrashnode.php' );
04440                     $trashNode = eZContentObjectTrashNode::createFromNode( $this );
04441                     $db = eZDB::instance();
04442                     $db->begin();
04443                     $trashNode->storeToTrash();
04444                     $db->commit();
04445                     $object->removeThis();
04446                 }
04447                 else
04448                 {
04449                     $object->purge();
04450                 }
04451                 $db->commit();
04452             }
04453         }
04454         else
04455         {
04456             eZContentCacheManager::clearContentCacheIfNeeded( $this->attribute( 'contentobject_id' ) );
04457             $this->removeThis();
04458         }
04459     }
04460 
04461     /*!
04462      \return The number of nodes in the current subtree that have no other placements.
04463     */
04464     function subtreeSoleNodeCount( $params = array() )
04465     {
04466         $nodeID = $this->attribute( 'node_id' );
04467         $node = $this;
04468 
04469         $depth = false;
04470         if ( isset( $params['Depth'] ) && is_numeric( $params['Depth'] ) )
04471         {
04472             $depth = $params['Depth'];
04473 
04474         }
04475 
04476         $fromNode = $nodeID;
04477 
04478         $nodePath = null;
04479         $nodeDepth = 0;
04480         if ( count( $node ) != 0 )
04481         {
04482             $nodePath = $node->attribute( 'path_string' );
04483             $nodeDepth = $node->attribute( 'depth' );
04484         }
04485 
04486         $childPath = $nodePath;
04487 
04488         $db = eZDB::instance();
04489         $pathString = " ezcot.path_string like '$childPath%' and ";
04490 
04491         $notEqParentString = "ezcot.node_id != $fromNode";
04492         $depthCond = '';
04493         if ( $depth )
04494         {
04495 
04496             $nodeDepth += $depth;
04497             if ( isset( $params[ 'DepthOperator' ] ) && $params[ 'DepthOperator' ] == 'eq' )
04498             {
04499                 $depthCond = ' ezcot.depth = ' . $nodeDepth . '';
04500                 $notEqParentString = '';
04501             }
04502             else
04503                 $depthCond = ' ezcot.depth <= ' . $nodeDepth . ' and ';
04504         }
04505 
04506         $tmpTableName = $db->generateUniqueTempTableName( 'eznode_count_%' );
04507         $db->createTempTable( "CREATE TEMPORARY TABLE $tmpTableName ( count int )" );
04508         $query = "INSERT INTO $tmpTableName
04509                   SELECT
04510                           count( ezcot.main_node_id ) AS count
04511                     FROM
04512                           ezcontentobject_tree ezcot,
04513                           ezcontentobject_tree ezcot_all
04514                     WHERE
04515                            $pathString
04516                            $depthCond
04517                            $notEqParentString
04518                            and ezcot.contentobject_id = ezcot_all.contentobject_id
04519                     GROUP BY ezcot_all.main_node_id
04520                     HAVING count( ezcot.main_node_id ) <= 1";
04521 
04522         $db->query( $query, eZDBInterface::SERVER_SLAVE );
04523         $query = "SELECT count( * ) AS count
04524                   FROM $tmpTableName";
04525 
04526         $rows = $db->arrayQuery( $query, array(), eZDBInterface::SERVER_SLAVE );
04527         $db->dropTempTable( "DROP TABLE $tmpTableName" );
04528         return $rows[0]['count'];
04529     }
04530 
04531     /*!
04532       Moves the node to the given node.
04533       \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
04534      the calls within a db transaction; thus within db->begin and db->commit.
04535     */
04536     function move( $newParentNodeID, $nodeID = 0 )
04537     {
04538         //include_once( "kernel/classes/ezpolicylimitation.php" );
04539         if ( $nodeID == 0 )
04540         {
04541             $node = $this;
04542             $nodeID = $node->attribute( 'node_id' );
04543         }
04544         else
04545         {
04546             $node = eZContentObjectTreeNode::fetch( $nodeID );
04547         }
04548 
04549         $oldPath = $node->attribute( 'path_string' );
04550         $oldParentNodeID = $node->attribute( 'parent_node_id' );
04551         $newParentNodeID =(int) $newParentNodeID;
04552         if ( $oldParentNodeID != $newParentNodeID )
04553         {
04554             $node->updateAndStoreModified();
04555             // Who moves which content should be logged.
04556             //include_once( "kernel/classes/ezaudit.php" );
04557             $object = $node->object();
04558             eZAudit::writeAudit( 'content-move', array( 'Node ID' => $node->attribute( 'node_id' ),
04559                                                         'Old parent node ID' => $oldParentNodeID, 'New parent node ID' => $newParentNodeID,
04560                                                         'Object ID' => $object->attribute( 'id' ), 'Content Name' => $object->attribute( 'name' ),
04561                                                         'Comment' => 'Moved the node to the given node: eZContentObjectTreeNode::move()' ) );
04562 
04563             $newParentNode = eZContentObjectTreeNode::fetch( $newParentNodeID );
04564             $newParentPath = $newParentNode->attribute( 'path_string' );
04565             $newParentDepth = $newParentNode->attribute( 'depth' );
04566             $newPath = $newParentPath . $nodeID;
04567             $oldDepth = $node->attribute( 'depth' );
04568 
04569             $oldPathLength = strlen( $oldPath );
04570             $moveQuery = "UPDATE
04571                                  ezcontentobject_tree
04572                           SET
04573                                  parent_node_id = $newParentNodeID
04574                           WHERE
04575                                  node_id = $nodeID";
04576             $db = eZDB::instance();
04577             $subStringString = $db->subString( 'path_string', $oldPathLength );
04578             $newPathString   = $db->concatString( array( "'$newPath'", $subStringString ) );
04579             $moveQuery1 = "UPDATE
04580                                  ezcontentobject_tree
04581                            SET
04582                                  path_string = $newPathString,
04583                                  depth = depth + $newParentDepth - $oldDepth + 1
04584                            WHERE
04585                                  path_string LIKE '$oldPath%'";
04586             $db->begin();
04587             $db->query( $moveQuery );
04588             $db->query( $moveQuery1 );
04589 
04590             /// role system clean up
04591             // Clean up policies and limitations
04592 
04593             $expireRoleCache = false;
04594 
04595             $limitationsToFix = eZPolicyLimitation::findByType( 'SubTree', $node->attribute( 'path_string' ), false );
04596             if ( count( $limitationsToFix ) > 0 )
04597             {
04598                 //include_once( "kernel/classes/ezrole.php" );
04599                 $limitationIDString = $db->generateSQLInStatement( $limitationsToFix, 'limitation_id' );
04600                 $subStringString =  $db->subString( 'value', $oldPathLength );
04601                 $newValue = $db->concatString( array( "'$newPath'", $subStringString ) );
04602 
04603                 $query = "UPDATE
04604                                 ezpolicy_limitation_value
04605                           SET
04606                                 value = $newValue
04607                           WHERE
04608                                 value LIKE '$oldPath%' AND $limitationIDString";
04609 
04610                 $db->query( $query );
04611 
04612                 $expireRoleCache = true;
04613             }
04614 
04615             // clean up limitations on role assignment level
04616             $countRows = $db->arrayQuery( "SELECT COUNT(*) AS row_count FROM ezuser_role WHERE limit_identifier='Subtree' AND limit_value LIKE '$oldPath%'" );
04617             $assignmentsToFixCount = $countRows[0]['row_count'];
04618 
04619             if ( $assignmentsToFixCount > 0 )
04620             {
04621                 $subStringString =  $db->subString( 'limit_value', $oldPathLength );
04622                 $newValue = $db->concatString( array( "'$newPath'", $subStringString ) );
04623 
04624                 $db->query( "UPDATE
04625                                 ezuser_role
04626                              SET
04627                                 limit_value = $newValue
04628                              WHERE
04629                                 limit_identifier='Subtree' AND limit_value LIKE '$oldPath%'"
04630                           );
04631 
04632                $expireRoleCache = true;
04633            }
04634 
04635             if ( $expireRoleCache )
04636             {
04637                 eZRole::expireCache();
04638             }
04639 
04640             // Update "is_invisible" node attribute.
04641             $newNode = eZContentObjectTreeNode::fetch( $nodeID );
04642             eZContentObjectTreeNode::updateNodeVisibility( $newNode, $newParentNode );
04643             $db->commit();
04644         }
04645     }
04646 
04647     function checkAccess( $functionName, $originalClassID = false, $parentClassID = false, $returnAccessList = false, $language = false )
04648     {
04649         $classID = $originalClassID;
04650         $user = eZUser::currentUser();
04651         $userID = $user->attribute( 'contentobject_id' );
04652 
04653         //include_once( 'kernel/classes/ezcontentlanguage.php' );
04654         // Fetch the ID of the language if we get a string with a language code
04655         // e.g. 'eng-GB'
04656         $originalLanguage = $language;
04657         if ( is_string( $language ) && strlen( $language ) > 0 )
04658         {
04659             $language = eZContentLanguage::idByLocale( $language );
04660         }
04661         else
04662         {
04663             $language = false;
04664         }
04665 
04666         // This will be filled in with the available languages of the object
04667         // if a Language check is performed.
04668         $languageList = false;
04669 
04670         // This will be filled if parent object is needed.
04671         $parentObject = false;
04672 
04673         $origFunctionName = $functionName;
04674         // The 'move' function simply reuses 'edit' for generic access
04675         // but adds another top-level check below
04676         // The original function is still available in $origFunctionName
04677         if ( $functionName == 'move' )
04678             $functionName = 'edit';
04679 
04680         // Manage locations depends if it's removal or not.
04681         if ( $functionName == 'can_add_location' ||
04682              $functionName == 'can_remove_location' )
04683         {
04684             $functionName = 'manage_locations';
04685         }
04686 
04687         $accessResult = $user->hasAccessTo( 'content' , $functionName );
04688         $accessWord = $accessResult['accessWord'];
04689         if ( $origFunctionName == 'can_remove_location' )
04690         {
04691             if ( $this->ParentNodeID <= 1 )
04692             {
04693                 return 0;
04694             }
04695             $currentNode = eZContentObjectTreeNode::fetch( $this->ParentNodeID );
04696             $contentObject = $currentNode->attribute( 'object' );
04697         }
04698         else
04699         {
04700             $currentNode = $this;
04701             $contentObject = $this->attribute( 'object' );
04702         }
04703 
04704         /*
04705         // Uncomment this part if 'create' permissions should become implied 'edit'.
04706         // Merges in 'create' policies with 'edit'
04707         if ( $functionName == 'edit' &&
04708              !in_array( $accessWord, array( 'yes', 'no' ) ) )
04709         {
04710             // Add in create policies.
04711             $accessExtraResult = $user->hasAccessTo( 'content', 'create' );
04712             if ( $accessExtraResult['accessWord'] != 'no' )
04713             {
04714                 $accessWord = $accessExtraResult['accessWord'];
04715                 if ( isset( $accessExtraResult['policies'] ) )
04716                 {
04717                     $accessResult['policies'] = array_merge( $accessResult['policies'],
04718                                                              $accessExtraResult['policies'] );
04719                 }
04720                 if ( isset( $accessExtraResult['accessList'] ) )
04721                 {
04722                     $accessResult['accessList'] = array_merge( $accessResult['accessList'],
04723                                                                $accessExtraResult['accessList'] );
04724                 }
04725             }
04726         }
04727         */
04728 
04729         if ( $origFunctionName == 'remove' or
04730              $origFunctionName == 'move' or
04731              $origFunctionName == 'can_remove_location' )
04732         {
04733             // We do not allow these actions on top-level nodes
04734             // - remove
04735             // - move
04736             if ( $this->ParentNodeID <= 1 )
04737             {
04738                 return 0;
04739             }
04740         }
04741 
04742         if ( $classID === false )
04743         {
04744             $classID = $contentObject->attribute( 'contentclass_id' );
04745         }
04746         if ( $accessWord == 'yes' )
04747         {
04748             return 1;
04749         }
04750         else if ( $accessWord == 'no' )
04751         {
04752             if ( $functionName == 'edit' )
04753             {
04754                 // Check if we have 'create' access under the main parent
04755                 $object = $currentNode->object();
04756                 if ( $object && $object->attribute( 'current_version' ) == 1 && !$object->attribute( 'status' ) )
04757                 {
04758                     $mainNode = eZNodeAssignment::fetchForObject( $object->attribute( 'id' ), $object->attribute( 'current_version' ) );
04759                     $parentObj = $mainNode[0]->attribute( 'parent_contentobject' );
04760                     $result = $parentObj->checkAccess( 'create', $object->attribute( 'contentclass_id' ),
04761                                                        $parentObj->attribute( 'contentclass_id' ), false, $originalLanguage );
04762                     return $result;
04763                 }
04764                 else
04765                 {
04766                     return 0;
04767                 }
04768             }
04769 
04770             return 0;
04771         }
04772         else
04773         {
04774             $policies = $accessResult['policies'];
04775             $access = 'denied';
04776 
04777             foreach ( $policies as $pkey => $limitationArray )
04778             {
04779                 if ( $access == 'allowed' )
04780                 {
04781                     break;
04782                 }
04783 
04784                 $limitationList = array();
04785                 if ( isset( $limitationArray['Subtree' ] ) )
04786                 {
04787                     $checkedSubtree = false;
04788                 }
04789                 else
04790                 {
04791                     $checkedSubtree = true;
04792                     $accessSubtree = false;
04793                 }
04794                 if ( isset( $limitationArray['Node'] ) )
04795                 {
04796                     $checkedNode = false;
04797                 }
04798                 else
04799                 {
04800                     $checkedNode = true;
04801                     $accessNode = false;
04802                 }
04803                 foreach ( $limitationArray as $key => $valueList  )
04804                 {
04805                     $access = 'denied';
04806                     switch( $key )
04807                     {
04808                         case 'Class':
04809                         {
04810                             if ( $functionName == 'create' and
04811                                  !$originalClassID )
04812                             {
04813                                 $access = 'allowed';
04814                             }
04815                             else if ( $functionName == 'create' and
04816                                       in_array( $classID, $valueList ) )
04817                             {
04818                                 $access = 'allowed';
04819                             }
04820                             else if ( $functionName != 'create' and
04821                                       in_array( $contentObject->attribute( 'contentclass_id' ), $valueList ) )
04822                             {
04823                                 $access = 'allowed';
04824                             }
04825                             else
04826                             {
04827                                 $access = 'denied';
04828                                 $limitationList = array( 'Limitation' => $key,
04829                                                          'Required' => $valueList );
04830                             }
04831                         } break;
04832 
04833                         case 'ParentClass':
04834                         {
04835                             if (  in_array( $contentObject->attribute( 'contentclass_id' ), $valueList ) )
04836                             {
04837                                 $access = 'allowed';
04838                             }
04839                             else
04840                             {
04841                                 $access = 'denied';
04842                                 $limitationList = array( 'Limitation' => $key,
04843                                                          'Required' => $valueList );
04844                             }
04845                         } break;
04846 
04847                         case 'Section':
04848                         case 'User_Section':
04849                         {
04850                             if ( in_array( $contentObject->attribute( 'section_id' ), $valueList ) )
04851                             {
04852                                 $access = 'allowed';
04853                             }
04854                             else
04855                             {
04856                                 $access = 'denied';
04857                                 $limitationList = array( 'Limitation' => $key,
04858                                                          'Required' => $valueList );
04859                             }
04860                         } break;
04861 
04862                         case 'Language':
04863                         {
04864                             $languageMask = 0;
04865                             // If we don't have a language list yet we need to fetch it
04866                             // and optionally filter out based on $language.
04867                             if ( $functionName == 'create' )
04868                             {
04869                                 // If the function is 'create' we do not use the language_mask for matching.
04870                                 if ( $language !== false )
04871                                 {
04872                                     $languageMask = $language;
04873                                 }
04874                                 else
04875                                 {
04876                                     // If the create is used and no language specified then
04877                                     // we need to match against all possible languages (which
04878                                     // is all bits set, ie. -1).
04879                                     $languageMask = -1;
04880                                 }
04881                             }
04882                             else
04883                             {
04884                                 if ( $language !== false )
04885                                 {
04886                                     if ( $languageList === false )
04887                                     {
04888                                         $languageMask = $contentObject->attribute( 'language_mask' );
04889                                         // We are restricting language check to just one language
04890                                         $languageMask &= $language;
04891                                         // If the resulting mask is 0 it means that the user is trying to
04892                                         // edit a language which does not exist, ie. translating.
04893                                         // The mask will then become the language trying to edit.
04894                                         if ( $languageMask == 0 )
04895                                         {
04896                                             $languageMask = $language;
04897                                         }
04898                                     }
04899                                 }
04900                                 else
04901                                 {
04902                                     $languageMask = -1;
04903                                 }
04904                             }
04905                             // Fetch limit mask for limitation list
04906                             $limitMask = eZContentLanguage::maskByLocale( $valueList );
04907                             if ( ( $languageMask & $limitMask ) != 0 )
04908                             {
04909                                 $access = 'allowed';
04910                             }
04911                             else
04912                             {
04913                                 $access = 'denied';
04914                                 $limitationList = array( 'Limitation' => $key,
04915                                                          'Required' => $valueList );
04916                             }
04917                         } break;
04918 
04919                         case 'Owner':
04920                         {
04921                             // if limitation value == 2, anonymous limited to current session.
04922                             if ( in_array( 2, $valueList ) &&
04923                                  $user->isAnonymous() )
04924                             {
04925                                 //include_once( 'kernel/classes/ezpreferences.php' );
04926                                 $createdObjectIDList = eZPreferences::value( 'ObjectCreationIDList' );
04927                                 if ( $createdObjectIDList &&
04928                                      in_array( $contentObject->attribute( 'id' ), unserialize( $createdObjectIDList ) ) )
04929                                 {
04930                                     $access = 'allowed';
04931                                 }
04932                             }
04933                             else if ( $contentObject->attribute( 'owner_id' ) == $userID || $contentObject->attribute( 'id' ) == $userID )
04934                             {
04935                                 $access = 'allowed';
04936                             }
04937                             if ( $access != 'allowed' )
04938                             {
04939                                 $access = 'denied';
04940                                 $limitationList = array ( 'Limitation' => $key );
04941                             }
04942                         } break;
04943 
04944                         case 'Group':
04945                         {
04946                             $access = $contentObject->checkGroupLimitationAccess( $valueList, $userID );
04947 
04948                             if ( $access != 'allowed' )
04949                             {
04950                                 $access = 'denied';
04951                                 $limitationList = array ( 'Limitation' => $key,
04952                                                           'Required' => $valueList );
04953                             }
04954                         } break;
04955 
04956                         case 'ParentDepth':
04957                         {
04958                             if ( in_array( $currentNode->attribute( 'depth' ), $valueList ) )
04959                             {
04960                                 $access = 'allowed';
04961                             }
04962                             else
04963                             {
04964                                 $access = 'denied';
04965                                 $limitationList = array( 'Limitation' => $key,
04966                                                          'Required' => $valueList );
04967                             }
04968                         } break;
04969 
04970                         case 'Node':
04971                         {
04972                             $accessNode = false;
04973                             $mainNodeID = $currentNode->attribute( 'main_node_id' );
04974                             foreach ( $valueList as $nodeID )
04975                             {
04976                                 $node = eZContentObjectTreeNode::fetch( $nodeID, false, false );
04977                                 $limitationNodeID = $node['main_node_id'];
04978                                 if ( $mainNodeID == $limitationNodeID )
04979                                 {
04980                                     $access = 'allowed';
04981                                     $accessNode = true;
04982                                     break;
04983                                 }
04984                             }
04985                             if ( $access != 'allowed' && $checkedSubtree && !$accessSubtree )
04986                             {
04987                                 $access = 'denied';
04988                                 // ??? TODO: if there is a limitation on Subtree, return two limitations?
04989                                 $limitationList = array( 'Limitation' => $key,
04990                                                          'Required' => $valueList );
04991                             }
04992                             else
04993                             {
04994                                 $access = 'allowed';
04995                             }
04996                             $checkedNode = true;
04997                         } break;
04998 
04999                         case 'Subtree':
05000                         {
05001                             $accessSubtree = false;
05002                             $path = $currentNode->attribute( 'path_string' );
05003                             $subtreeArray = $valueList;
05004                             foreach ( $subtreeArray as $subtreeString )
05005                             {
05006                                 if ( strstr( $path, $subtreeString ) )
05007                                 {
05008                                     $access = 'allowed';
05009                                     $accessSubtree = true;
05010                                     break;
05011                                 }
05012                             }
05013                             if ( $access != 'allowed' && $checkedNode && !$accessNode )
05014                             {
05015                                 $access = 'denied';
05016                                 // ??? TODO: if there is a limitation on Node, return two limitations?
05017                                 $limitationList = array( 'Limitation' => $key,
05018                                                          'Required' => $valueList );
05019                             }
05020                             else
05021                             {
05022                                 $access = 'allowed';
05023                             }
05024                             $checkedSubtree = true;
05025                         } break;
05026 
05027                         case 'User_Subtree':
05028                         {
05029                             $path = $currentNode->attribute( 'path_string' );
05030                             $subtreeArray = $valueList;
05031                             foreach ( $subtreeArray as $subtreeString )
05032                             {
05033                                 if ( strstr( $path, $subtreeString ) )
05034                                 {
05035                                     $access = 'allowed';
05036                                 }
05037                             }
05038                             if ( $access != 'allowed' )
05039                             {
05040                                 $access = 'denied';
05041                                 $limitationList = array( 'Limitation' => $key,
05042                                                          'Required' => $valueList );
05043                             }
05044                         } break;
05045                     }
05046 
05047                     if ( $access == 'denied' )
05048                     {
05049                         break;
05050                     }
05051                 }
05052 
05053                 $policyList[] = array( 'PolicyID' => $pkey,
05054                                        'LimitationList' => $limitationList );
05055             }
05056             if ( $access == 'denied' )
05057             {
05058                 $accessList = array( 'FunctionRequired' => array ( 'Module' => 'content',
05059                                                                    'Function' => $origFunctionName,
05060                                                                    'ClassID' => $classID,
05061                                                                    'MainNodeID' => $currentNode->attribute( 'main_node_id' ) ),
05062                                      'PolicyList' => $policyList );
05063                 return 0;
05064             }
05065             else
05066             {
05067                 return 1;
05068             }
05069         }
05070     }
05071 
05072     // code-template::create-block: class-list-from-policy, is-node
05073     // code-template::auto-generated:START class-list-from-policy
05074     // This code is automatically generated from templates/classlistfrompolicy.ctpl
05075     // DO NOT EDIT THIS CODE DIRECTLY, CHANGE THE TEMPLATE FILE INSTEAD
05076 
05077     function classListFromPolicy( $policy, $allowedLanguageCodes = false )
05078     {
05079         $canCreateClassIDListPart = array();
05080         $hasClassIDLimitation = false;
05081         $object = false;
05082         if ( isset( $policy['Class'] ) )
05083         {
05084             $canCreateClassIDListPart = $policy['Class'];
05085             $hasClassIDLimitation = true;
05086         }
05087 
05088         if ( isset( $policy['User_Section'] ) )
05089         {
05090             if ( $object === false )
05091                 $object = $this->attribute( 'object' );
05092             if ( !in_array( $object->attribute( 'section_id' ), $policy['User_Section']  ) )
05093             {
05094                 return array();
05095             }
05096         }
05097 
05098         if ( isset( $policy['User_Subtree'] ) )
05099         {
05100             $allowed = false;
05101             if ( $object === false )
05102                 $object = $this->attribute( 'object' );
05103             $assignedNodes = $object->attribute( 'assigned_nodes' );
05104             foreach ( $assignedNodes as $assignedNode )
05105             {
05106                 $path = $assignedNode->attribute( 'path_string' );
05107                 foreach ( $policy['User_Subtree'] as $subtreeString )
05108                 {
05109                     if ( strstr( $path, $subtreeString ) )
05110                     {
05111                         $allowed = true;
05112                         break;
05113                     }
05114                 }
05115             }
05116             if( !$allowed )
05117             {
05118                 return array();
05119             }
05120         }
05121 
05122         if ( isset( $policy['Section'] ) )
05123         {
05124             if ( $object === false )
05125                 $object = $this->attribute( 'object' );
05126             if ( !in_array( $object->attribute( 'section_id' ), $policy['Section']  ) )
05127             {
05128                 return array();
05129             }
05130         }
05131 
05132         if ( isset( $policy['ParentClass'] ) )
05133         {
05134             if ( $object === false )
05135                 $object = $this->attribute( 'object' );
05136             if ( !in_array( $object->attribute( 'contentclass_id' ), $policy['ParentClass']  ) )
05137             {
05138                 return array();
05139             }
05140         }
05141 
05142         if ( isset( $policy['ParentDepth'] ) && is_array( $policy['ParentDepth'] ) )
05143         {
05144             $NodeDepth = $this->attribute( 'depth' );
05145             if ( !in_array( '*', $policy['ParentDepth'] ) && !in_array( $NodeDepth, $policy['ParentDepth'] ) )
05146             {
05147                 return array();
05148             }
05149         }
05150 
05151         if ( isset( $policy['Assigned'] ) )
05152         {
05153             if ( $object === false )
05154                 $object = $this->attribute( 'object' );
05155             if ( $object->attribute( 'owner_id' ) != $user->attribute( 'contentobject_id' )  )
05156             {
05157                 return array();
05158             }
05159         }
05160 
05161         $allowedNode = false;
05162         if ( isset( $policy['Node'] ) )
05163         {
05164             $allowed = false;
05165             foreach( $policy['Node'] as $nodeID )
05166             {
05167                 $mainNodeID = $this->attribute( 'main_node_id' );
05168                 $node = eZContentObjectTreeNode::fetch( $nodeID, false, false );
05169                 if ( $mainNodeID == $node['main_node_id'] )
05170                 {
05171                     $allowed = true;
05172                     $allowedNode = true;
05173                     break;
05174                 }
05175             }
05176             if ( !$allowed && !isset( $policy['Subtree'] ) )
05177             {
05178                 return array();
05179             }
05180         }
05181 
05182         if ( isset( $policy['Subtree'] ) )
05183         {
05184             $allowed = false;
05185             if ( $object === false )
05186                 $object = $this->attribute( 'object' );
05187             $assignedNodes = $object->attribute( 'assigned_nodes' );
05188             foreach ( $assignedNodes as $assignedNode )
05189             {
05190                 $path = $assignedNode->attribute( 'path_string' );
05191                 foreach ( $policy['Subtree'] as $subtreeString )
05192                 {
05193                     if ( strstr( $path, $subtreeString ) )
05194                     {
05195                         $allowed = true;
05196                         break;
05197                     }
05198                 }
05199             }
05200             if ( !$allowed && !$allowedNode )
05201             {
05202                 return array();
05203             }
05204         }
05205 
05206         if ( isset( $policy['Language'] ) )
05207         {
05208             if ( $allowedLanguageCodes )
05209             {
05210                 $allowedLanguageCodes = array_intersect( $allowedLanguageCodes, $policy['Language'] );
05211             }
05212             else
05213             {
05214                 $allowedLanguageCodes = $policy['Language'];
05215             }
05216         }
05217 
05218         if ( $hasClassIDLimitation )
05219         {
05220             return array( 'classes' => $canCreateClassIDListPart, 'language_codes' => $allowedLanguageCodes );
05221         }
05222         return array( 'classes' => '*', 'language_codes' => $allowedLanguageCodes );
05223     }
05224 
05225     // This code is automatically generated from templates/classlistfrompolicy.ctpl
05226     // code-template::auto-generated:END class-list-from-policy
05227 
05228     // code-template::create-block: can-instantiate-class-list, group-filter, object-policy-list, name-create, object-creation, object-sql-creation
05229     // code-template::auto-generated:START can-instantiate-class-list
05230     // This code is automatically generated from templates/classcreatelist.ctpl
05231     // DO NOT EDIT THIS CODE DIRECTLY, CHANGE THE TEMPLATE FILE INSTEAD
05232 
05233     /*!
05234      Finds all classes that the current user can create objects from and returns.
05235      It is also possible to filter the list event more with \a $includeFilter and \a $groupList.
05236 
05237      \param $asObject If \c true then it return eZContentClass objects, if not it will
05238                       be an associative array with \c name and \c id keys.
05239      \param $includeFilter If \c true then it will include only from class groups defined in
05240                            \a $groupList, if not it will exclude those groups.
05241      \param $groupList An array with class group IDs that should be used in filtering, use
05242                        \c false if you do not wish to filter at all.
05243      \param $id A unique name for the current fetch, this must be supplied when filtering is
05244                 used if you want caching to work.
05245     */
05246     function canCreateClassList( $asObject = false, $includeFilter = true, $groupList = false, $fetchID = false )
05247     {
05248         $ini = eZINI::instance();
05249         $groupArray = array();
05250         $languageCodeList = eZContentLanguage::fetchLocaleList();
05251         $allowedLanguages = array( '*' => array() );
05252 
05253         $user = eZUser::currentUser();
05254         $accessResult = $user->hasAccessTo( 'content' , 'create' );
05255         $accessWord = $accessResult['accessWord'];
05256 
05257         $classIDArray = array();
05258         $classList = array();
05259         $fetchAll = false;
05260         if ( $accessWord == 'yes' )
05261         {
05262             $fetchAll = true;
05263             $allowedLanguages['*'] = $languageCodeList;
05264         }
05265         else if ( $accessWord == 'no' )
05266         {
05267             // Cannnot create any objects, return empty list.
05268             return $classList;
05269         }
05270         else
05271         {
05272             $policies = $accessResult['policies'];
05273             foreach ( $policies as $policyKey => $policy )
05274             {
05275                 $policyArray = $this->classListFromPolicy( $policy, $languageCodeList );
05276                 if ( count( $policyArray ) == 0 )
05277                 {
05278                     continue;
05279                 }
05280                 $classIDArrayPart = $policyArray['classes'];
05281                 $languageCodeArrayPart = $policyArray['language_codes'];
05282                 if ( $classIDArrayPart == '*' )
05283                 {
05284                     $fetchAll = true;
05285                     $allowedLanguages['*'] = array_unique( array_merge( $allowedLanguages['*'], $languageCodeArrayPart ) );
05286                 }
05287                 else
05288                 {
05289                     foreach( $classIDArrayPart as $class )
05290                     {
05291                         if ( isset( $allowedLanguages[$class] ) )
05292                         {
05293                             $allowedLanguages[$class] = array_unique( array_merge( $allowedLanguages[$class], $languageCodeArrayPart ) );
05294                         }
05295                         else
05296                         {
05297                             $allowedLanguages[$class] = $languageCodeArrayPart;
05298                         }
05299                     }
05300                     $classIDArray = array_merge( $classIDArray, array_diff( $classIDArrayPart, $classIDArray ) );
05301                 }
05302             }
05303         }
05304 
05305         $db = eZDB::instance();
05306 
05307         $filterTableSQL = '';
05308         $filterSQL = '';
05309         // Create extra SQL statements for the class group filters.
05310         if ( is_array( $groupList ) )
05311         {
05312             if ( count( $groupList ) == 0 )
05313             {
05314                 return $classList;
05315             }
05316 
05317             $filterTableSQL = ', ezcontentclass_classgroup ccg';
05318             $filterSQL = ( " AND\n" .
05319                            "      cc.id = ccg.contentclass_id AND\n" .
05320                            "      " );
05321             $filterSQL .= $db->generateSQLINStatement( $groupList, 'ccg.group_id', !$includeFilter, true, 'int' );
05322         }
05323 
05324         $classNameFilter = eZContentClassName::sqlFilter( 'cc' );
05325 
05326         if ( $fetchAll )
05327         {
05328             // If $asObject is true we fetch all fields in class
05329             $fields = $asObject ? "cc.*, $classNameFilter[nameField]" : "cc.id, $classNameFilter[nameField]";
05330             $rows = $db->arrayQuery( "SELECT DISTINCT $fields\n" .
05331                                      "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from]\n" .
05332                                      "WHERE cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . " $filterSQL AND $classNameFilter[where]\n" .
05333                                      "ORDER BY $classNameFilter[nameField] ASC" );
05334             $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject );
05335         }
05336         else
05337         {
05338             // If the constrained class list is empty we are not allowed to create any class
05339             if ( count( $classIDArray ) == 0 )
05340             {
05341                 return $classList;
05342             }
05343 
05344             $classIDCondition = $db->generateSQLInStatement( $classIDArray, 'cc.id' );
05345             // If $asObject is true we fetch all fields in class
05346             $fields = $asObject ? "cc.*, $classNameFilter[nameField]" : "cc.id, $classNameFilter[nameField]";
05347             $rows = $db->arrayQuery( "SELECT DISTINCT $fields\n" .
05348                                      "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from]\n" .
05349                                      "WHERE $classIDCondition AND\n" .
05350                                      "      cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . " $filterSQL AND $classNameFilter[where]\n" .
05351                                      "ORDER BY $classNameFilter[nameField] ASC" );
05352             $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject );
05353         }
05354 
05355         if ( $asObject )
05356         {
05357             foreach ( $classList as $key => $class )
05358             {
05359                 $id = $class->attribute( 'id' );
05360                 if ( isset( $allowedLanguages[$id] ) )
05361                 {
05362                     $languageCodes = array_unique( array_merge( $allowedLanguages['*'], $allowedLanguages[$id] ) );
05363                 }
05364                 else
05365                 {
05366                     $languageCodes = $allowedLanguages['*'];
05367                 }
05368                 $classList[$key]->setCanInstantiateLanguages( $languageCodes );
05369             }
05370         }
05371 
05372         eZDebugSetting::writeDebug( 'kernel-content-class', $classList, "class list fetched from db" );
05373         return $classList;
05374     }
05375 
05376     // This code is automatically generated from templates/classcreatelist.ctpl
05377     // code-template::auto-generated:END can-instantiate-class-list
05378 
05379     static function makeObjectsArray( $array , $with_contentobject = true )
05380     {
05381         $retNodes = array();
05382         if ( !is_array( $array ) )
05383             return $retNodes;
05384 
05385         $ini = eZINI::instance();
05386 
05387         foreach ( $array as $node )
05388         {
05389             unset( $object );
05390 
05391             if( $node['node_id'] == 1 )
05392             {
05393                 if( !array_key_exists( 'name', $node ) || !$node['name'] )
05394                     $node['name'] = ezi18n( 'kernel/content', 'Top Level Nodes' );
05395             }
05396 
05397             $object = new eZContentObjectTreeNode( $node );
05398             // If the name is not set it will be fetched later on when
05399             // getName()/attribute( 'name' ) is accessed.
05400             if ( isset( $node['name'] ) )
05401             {
05402                 $object->setName( $node['name'] );
05403             }
05404 
05405             if ( isset( $node['class_serialized_name_list'] ) )
05406             {
05407                 $node['class_name'] = eZContentClass::nameFromSerializedString( $node['class_serialized_name_list'] );
05408                 $object->ClassName = $node['class_name'];
05409             }
05410             if ( isset( $node['class_identifier'] ) )
05411                 $object->ClassIdentifier = $node['class_identifier'];
05412             if ( $with_contentobject )
05413             {
05414                 if ( array_key_exists( 'class_name', $node ) )
05415                 {
05416                     unset( $node['remote_id'] );
05417                     $contentObject = new eZContentObject( $node );
05418 
05419                     $permissions = array();
05420                     $contentObject->setPermissions( $permissions );
05421                     $contentObject->setClassName( $node['class_name'] );
05422                     if ( isset( $node['class_identifier'] ) )
05423                         $contentObject->ClassIdentifier = $node['class_identifier'];
05424 
05425                 }
05426                 else
05427                 {
05428                     $contentObject = new eZContentObject( array());
05429                     if ( isset( $node['name'] ) )
05430                          $contentObject->setCachedName( $node['name'] );
05431                 }
05432                 if ( isset( $node['real_translation'] ) && $node['real_translation'] != '' )
05433                 {
05434                     $object->CurrentLanguage = $node['real_translation'];
05435                     $contentObject->CurrentLanguage = $node['real_translation'];
05436                 }
05437                 if ( $node['node_id'] == 1 )
05438                 {
05439                     $contentObject->ClassName = 'Folder';
05440                     $contentObject->ClassIdentifier = 'folder';
05441                     $contentObject->ClassID = 1;
05442                     $contentObject->SectionID = 1;
05443                 }
05444 
05445                 $object->setContentObject( $contentObject );
05446             }
05447             $retNodes[] = $object;
05448         }
05449         return $retNodes;
05450     }
05451 
05452     static function getParentNodeId( $nodeID )
05453     {
05454         if ( !isset( $nodeID ) )
05455             return null;
05456         $db = eZDB::instance();
05457         $nodeID =(int) $nodeID;
05458         $parentArr = $db->arrayQuery( "SELECT
05459                                               parent_node_id
05460                                        FROM
05461                                               ezcontentobject_tree
05462                                        WHERE
05463                                               node_id = $nodeID");
05464         return $parentArr[0]['parent_node_id'];
05465     }
05466 
05467     /*!
05468      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
05469      the calls within a db transaction; thus within db->begin and db->commit.
05470      */
05471     static function deleteNodeWhereParent( $node, $id )
05472     {
05473         eZContentObjectTreeNode::removeNode( eZContentObjectTreeNode::findNode( $node, $id ) );
05474 
05475     }
05476 
05477     static function findNode( $parentNode, $id, $asObject = false, $remoteID = false )
05478     {
05479         if ( !isset( $parentNode) || $parentNode == NULL  )
05480         {
05481             $parentNode = 2;
05482         }
05483         $parentNode =(int) $parentNode;
05484         $db = eZDB::instance();
05485         if( $asObject )
05486         {
05487             if ( $remoteID )
05488             {
05489                 $objectIDFilter = 'ezcontentobject.remote_id = ' . (string) $id;
05490             }
05491             else
05492             {
05493                 $objectIDFilter = 'contentobject_id = ' . (int) $id;
05494             }
05495 
05496             $query="SELECT ezcontentobject.*,
05497                        ezcontentobject_tree.*,
05498                        ezcontentclass.serialized_name_list as class_serialized_name_list,
05499                        ezcontentclass.identifier as class_identifier,
05500                        ezcontentclass.is_container as is_container
05501                 FROM ezcontentobject_tree,
05502                      ezcontentobject,
05503                      ezcontentclass
05504                 WHERE parent_node_id = $parentNode AND
05505                       $objectIDFilter AND
05506                       ezcontentobject_tree.contentobject_id=ezcontentobject.id AND
05507                       ezcontentclass.version=0  AND
05508                       ezcontentclass.id = ezcontentobject.contentclass_id ";
05509 
05510             $nodeListArray = $db->arrayQuery( $query );
05511             $retNodeArray = eZContentObjectTreeNode::makeObjectsArray( $nodeListArray );
05512 
05513             if ( count( $retNodeArray ) > 0 )
05514             {
05515                 return $retNodeArray[0];
05516             }
05517             else
05518             {
05519                 return null;
05520             }
05521         }
05522         else
05523         {
05524             $id = (int) $id;
05525             $getNodeQuery = "SELECT node_id
05526                            FROM ezcontentobject_tree
05527                            WHERE
05528                                 parent_node_id=$parentNode AND
05529                                 contentobject_id = $id ";
05530             $nodeArr = $db->arrayQuery( $getNodeQuery );
05531             if ( isset( $nodeArr[0] ) )
05532             {
05533                 return $nodeArr[0]['node_id'];
05534             }
05535             else
05536             {
05537                 return false;
05538             }
05539         }
05540     }
05541 
05542     function getName( $language = false )
05543     {
05544         // If the name is not set yet we fetch it from the object table
05545         if ( $this->Name === null || $language !== false )
05546         {
05547             if ( $this->CurrentLanguage || $language !== false )
05548             {
05549                 $sql = "SELECT name FROM ezcontentobject_name WHERE contentobject_id=" . (int) $this->ContentObjectID . " AND content_version=" . (int)$this->attribute( 'contentobject_version' ) . " AND real_translation='" . ( $language !== false ? $language : $this->CurrentLanguage ) . "'";
05550             }
05551             else
05552             {
05553                 $sql = "SELECT name FROM ezcontentobject WHERE id=" . (int) $this->ContentObjectID;
05554             }
05555             $db = eZDB::instance();
05556             $rows = $db->arrayQuery( $sql );
05557             if ( count( $rows ) > 0 )
05558             {
05559                 if ( $language !== false )
05560                 {
05561                     return $rows[0]['name'];
05562                 }
05563                 $this->Name = $rows[0]['name'];
05564             }
05565             else
05566             {
05567                 if ( $language !== false )
05568                 {
05569                     return false;
05570                 }
05571                 $this->Name = false;
05572             }
05573         }
05574         return $this->Name;
05575     }
05576 
05577     function setName( $name )
05578     {
05579         $this->Name = $name;
05580     }
05581 
05582     /*!
05583      \static
05584      Creates propper nodeassigment from contentNodeDOMNode specification
05585 
05586      \param contentobjecttreenode DOMNode
05587      \param contentobject.
05588      \param version
05589      \param isMain
05590      \param options
05591 
05592      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
05593      the calls within a db transaction; thus within db->begin and db->commit.
05594     */
05595     static function unserialize( $contentNodeDOMNode, $contentObject, $version, $isMain, &$nodeList, &$options, $handlerType = 'ezcontentobject' )
05596     {
05597         $parentNodeID = -1;
05598 
05599         $remoteID = $contentNodeDOMNode->getAttribute( 'remote-id' );
05600         $parentNodeRemoteID = $contentNodeDOMNode->getAttribute( 'parent-node-remote-id' );
05601         $node = eZContentObjectTreeNode::fetchByRemoteID( $remoteID );
05602         if ( is_object( $node ) )
05603         {
05604             $description = "Node with remote ID $remoteID already exists.";
05605 
05606             // include_once( 'kernel/classes/ezpackagehandler.php' );
05607             $choosenAction = eZPackageHandler::errorChoosenAction( eZContentObject::PACKAGE_ERROR_EXISTS,
05608                                                                    $options, $description, $handlerType, false );
05609 
05610             switch( $choosenAction )
05611             {
05612                 // In case user have choosen "Keep existing object and create new"
05613                 case eZContentObject::PACKAGE_NEW:
05614                 {
05615                     $newRemoteID = md5( (string)mt_rand() . (string)time() );
05616                     $node->setAttribute( 'remote_id', $newRemoteID );
05617                     $node->store();
05618                     $nodeInfo = array( 'contentobject_id' =>  $node->attribute( 'contentobject_id' ),
05619                                        'contentobject_version' => $node->attribute( 'contentobject_version' ),
05620                                        'parent_remote_id' => $remoteID );
05621                     $nodeAssignment = eZPersistentObject::fetchObject( eZNodeAssignment::definition(),
05622                                                                        null,
05623                                                                        $nodeInfo );
05624                     if ( is_object( $nodeAssignment ) )
05625                     {
05626                         $nodeAssignment->setAttribute( 'parent_remote_id', $newRemoteID );
05627                         $nodeAssignment->store();
05628                     }
05629                 } break;
05630 
05631                 // When running non-interactively with ezpm.php
05632                 case eZPackage::NON_INTERACTIVE:
05633                 {
05634                     // Update existing node settigns.
05635                     if ( !$parentNodeRemoteID )
05636                     {
05637                         // when top node of subtree export, only update node sort field and sort order
05638                         $node->setAttribute( 'sort_field', eZContentObjectTreeNode::sortFieldID( $contentNodeDOMNode->getAttribute( 'sort-field' ) ) );
05639                         $node->setAttribute( 'sort_order', $contentNodeDOMNode->getAttribute( 'sort-order' ) );
05640                         $node->store();
05641                         return true;
05642                     }
05643                 } break;
05644 
05645                 default:
05646                 {
05647                     // This error may occur only if data integrity is broken
05648                     $options['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_NODE_EXISTS,
05649                                                'element_id' => $remoteID,
05650                                                'description' => $description );
05651                     return false;
05652                 } break;
05653             }
05654         }
05655 
05656         if ( $parentNodeRemoteID )
05657         {
05658             $parentNode = eZContentObjectTreeNode::fetchByRemoteID( $parentNodeRemoteID );
05659             if ( $parentNode !== null )
05660             {
05661                 $parentNodeID = $parentNode->attribute( 'node_id' );
05662             }
05663         }
05664         else
05665         {
05666             if ( isset( $options['top_nodes_map'][$contentNodeDOMNode->getAttribute( 'node-id' )]['new_node_id'] ) )
05667             {
05668                 $parentNodeID = $options['top_nodes_map'][$contentNodeDOMNode->getAttribute( 'node-id' )]['new_node_id'];
05669             }
05670             else if ( isset( $options['top_nodes_map']['*'] ) )
05671             {
05672                 $parentNodeID = $options['top_nodes_map']['*'];
05673             }
05674             else
05675             {
05676                 eZDebug::writeError( 'New parent node not set ' . $contentNodeDOMNode->getAttribute( 'name' ),
05677                                      'eZContentObjectTreeNode::unserialize()' );
05678             }
05679         }
05680 
05681         $isMain = ( $isMain && $contentNodeDOMNode->getAttribute( 'is-main-node' ) );
05682 
05683         $nodeInfo = array( 'contentobject_id' => $contentObject->attribute( 'id' ),
05684                            'contentobject_version' => $version,
05685                            'is_main' => $isMain,
05686                            'parent_node' => $parentNodeID,
05687                            'parent_remote_id' => $remoteID,     // meaning processed node remoteID (not parent)
05688                            'sort_field' => eZContentObjectTreeNode::sortFieldID( $contentNodeDOMNode->getAttribute( 'sort-field' ) ),
05689                            'sort_order' => $contentNodeDOMNode->getAttribute( 'sort-order' ) );
05690 
05691         if ( $parentNodeID == -1 && $parentNodeRemoteID )
05692         {
05693             if ( !isset( $options['suspended-nodes'] ) )
05694             {
05695                 $options['suspended-nodes'] = array();
05696             }
05697 
05698             $options['suspended-nodes'][$parentNodeRemoteID] = array( 'nodeinfo' => $nodeInfo,
05699                                                                       'priority' => $contentNodeDOMNode->getAttribute( 'priority' ) );
05700             return true;
05701         }
05702 
05703         $existNodeAssignment = eZPersistentObject::fetchObject( eZNodeAssignment::definition(),
05704                                                    null,
05705                                                    $nodeInfo );
05706         $nodeInfo['priority'] = $contentNodeDOMNode->getAttribute( 'priority' );
05707         if( !is_object( $existNodeAssignment ) )
05708         {
05709             $nodeAssignment = eZNodeAssignment::create( $nodeInfo );
05710             $nodeList[] = $nodeInfo;
05711             $nodeAssignment->store();
05712         }
05713 
05714         return true;
05715     }
05716 
05717     /*!
05718      Serialize ContentObjectTreeNode
05719 
05720      \params $options
05721      \params contentNodeIDArray
05722      \params topNodeIDArray
05723     */
05724     function serialize( $options, $contentNodeIDArray, $topNodeIDArray )
05725     {
05726         if ( $options['node_assignment'] == 'main' &&
05727              $this->attribute( 'main_node_id' ) != $this->attribute( 'node_id' ) )
05728         {
05729             return false;
05730         }
05731         if ( ! in_array( $this->attribute( 'node_id' ), array_keys( $contentNodeIDArray ) ) )
05732         {
05733             return false;
05734         }
05735 
05736         $dom = new DOMDocument( '1.0', 'utf-8' );
05737 
05738         $nodeAssignmentNode = $dom->createElement( 'node-assignment' );
05739         if ( $this->attribute( 'main_node_id' ) == $this->attribute( 'node_id' ) )
05740         {
05741             $nodeAssignmentNode->setAttribute( 'is-main-node', 1 );
05742         }
05743         if( !in_array( $this->attribute( 'node_id'), $topNodeIDArray ) )
05744         {
05745             $parentNode = $this->attribute( 'parent' );
05746             $nodeAssignmentNode->setAttribute( 'parent-node-remote-id', $parentNode->attribute( 'remote_id' ) );
05747         }
05748         $nodeAssignmentNode->setAttribute( 'name', $this->attribute( 'name' ) );
05749         $nodeAssignmentNode->setAttribute( 'node-id', $this->attribute( 'node_id' ) );
05750         $nodeAssignmentNode->setAttribute( 'remote-id', $this->attribute( 'remote_id' ) );
05751         $nodeAssignmentNode->setAttribute( 'sort-field', eZContentObjectTreeNode::sortFieldName( $this->attribute( 'sort_field' ) ) );
05752         $nodeAssignmentNode->setAttribute( 'sort-order', $this->attribute( 'sort_order' ) );
05753         $nodeAssignmentNode->setAttribute( 'priority', $this->attribute( 'priority' ) );
05754         return $nodeAssignmentNode;
05755     }
05756 
05757     /*!
05758      Update and store modified_subnode value for this node and all super nodes.
05759      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
05760      the calls within a db transaction; thus within db->begin and db->commit.
05761     */
05762     function updateAndStoreModified()
05763     {
05764         $pathArray = explode( '/', $this->attribute( 'path_string' ) );
05765         $sql = '';
05766 
05767         for( $pathCount = 1; $pathCount < count( $pathArray ) - 1; ++$pathCount )
05768         {
05769             $sql .= ( $pathCount != 1 ? 'OR ' : '' ) . 'node_id=\'' . $pathArray[$pathCount] . '\' ';
05770         }
05771 
05772         if ( $sql != '' )
05773         {
05774             $sql = 'UPDATE ezcontentobject_tree SET modified_subnode=' . time() .
05775                  ' WHERE ' . $sql;
05776             $db = eZDB::instance();
05777             $db->query( $sql );
05778         }
05779     }
05780 
05781     /*!
05782      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
05783      the calls within a db transaction; thus within db->begin and db->commit.
05784      */
05785     function store( $fieldFilters = null )
05786     {
05787         $db = eZDB::instance();
05788 
05789         $db->begin();
05790         eZPersistentObject::store( $fieldFilters );
05791         $this->updateAndStoreModified();
05792         $db->commit();
05793     }
05794 
05795     function object()
05796     {
05797         if ( $this->hasContentObject() )
05798         {
05799             return $this->ContentObject;
05800         }
05801         $contentobject_id = $this->attribute( 'contentobject_id' );
05802         $obj = eZContentObject::fetch( $contentobject_id );
05803         $obj->setCurrentLanguage( $this->CurrentLanguage );
05804         $this->ContentObject = $obj;
05805         return $obj;
05806     }
05807 
05808     function hasContentObject()
05809     {
05810         if ( isset( $this->ContentObject ) && $this->ContentObject instanceof eZContentObject )
05811             return true;
05812         else
05813             return false;
05814     }
05815 
05816     /*!
05817      Sets the current content object for this node.
05818     */
05819     function setContentObject( $object )
05820     {
05821         $this->ContentObject = $object;
05822     }
05823 
05824     /*!
05825      \return the creator of the version published in the node.
05826      \note The reference for the return value is required to workaround
05827            a bug with PHP references.
05828     */
05829     function creator()
05830     {
05831         $db = eZDB::instance();
05832         $query = "SELECT creator_id
05833                   FROM ezcontentobject_version
05834                   WHERE
05835                         contentobject_id = '$this->ContentObjectID' AND
05836                         version = '$this->ContentObjectVersion' ";
05837 
05838         $creatorArray = $db->arrayQuery( $query );
05839         return eZContentObject::fetch( $creatorArray[0]['creator_id'] );
05840     }
05841 
05842     function contentObjectVersionObject( $asObject = true )
05843     {
05844         $version = eZContentObjectVersion::fetchVersion( $this->ContentObjectVersion, $this->ContentObjectID, $asObject );
05845         if ( $this->CurrentLanguage != false )
05846         {
05847             $version->CurrentLanguage = $this->CurrentLanguage;
05848         }
05849         return $version;
05850     }
05851 
05852     function urlAlias()
05853     {
05854         $useURLAlias =& $GLOBALS['eZContentObjectTreeNodeUseURLAlias'];
05855         $ini = eZINI::instance();
05856         $cleanURL = '';
05857         if ( !isset( $useURLAlias ) )
05858         {
05859             $useURLAlias = $ini->variable( 'URLTranslator', 'Translation' ) == 'enabled';
05860         }
05861         if ( $useURLAlias )
05862         {
05863             $path = $this->pathWithNames();
05864             if ( $ini->hasVariable( 'SiteAccessSettings', 'PathPrefix' ) &&
05865                  $ini->variable( 'SiteAccessSettings', 'PathPrefix' ) != '' )
05866             {
05867                 $prepend = $ini->variable( 'SiteAccessSettings', 'PathPrefix' );
05868                 $pathIdenStr = substr( $prepend, strlen( $prepend ) -1 ) == '/'
05869                                 ? $path . '/'
05870                                 : $path;
05871                 if ( strncasecmp( $pathIdenStr, $prepend, strlen( $prepend ) ) == 0 )
05872                     $cleanURL = eZURLAliasML::cleanURL( substr( $path, strlen( $prepend ) ) );
05873                 else
05874                     $cleanURL = eZURLAliasML::cleanURL( $path );
05875             }
05876             else
05877             {
05878                 $cleanURL = eZURLAliasML::cleanURL( $path );
05879             }
05880         }
05881         else
05882         {
05883             $cleanURL = eZURLAliasML::cleanURL( 'content/view/full/' . $this->NodeID );
05884         }
05885 
05886         return $cleanURL;
05887     }
05888 
05889     function url()
05890     {
05891         $ini = eZINI::instance();
05892         if ( $ini->variable( 'URLTranslator', 'Translation' ) == 'enabled' )
05893         {
05894             return $this->urlAlias();
05895         }
05896         return 'content/view/full/' . $this->NodeID;
05897     }
05898 
05899 
05900     /*!
05901      \return the cached value of the class identifier if it exists, it not it's fetched dynamically
05902     */
05903     function classIdentifier()
05904     {
05905         $identifier = '';
05906         if ( $this->ClassIdentifier !== null )
05907         {
05908             $identifier = $this->ClassIdentifier;
05909         }
05910         else
05911         {
05912             $object = $this->object();
05913             $class = $object->contentClass();
05914             $identifier = $class->attribute( 'identifier' );
05915         }
05916 
05917         return $identifier;
05918     }
05919 
05920     /*!
05921      \return the cached value of the class name if it exists, it not it's fetched dynamically
05922     */
05923     function className()
05924     {
05925         if ( $this->ClassName !== null )
05926         {
05927             return $this->ClassName;
05928         }
05929 
05930         $object = $this->object();
05931         $class = $object->contentClass();
05932         return $class->attribute( 'name' );
05933     }
05934 
05935     /*!
05936     \return combined string representation of both "is_hidden" and "is_invisible" attributes
05937     Used in the node view templates.
05938     FIXME: this method probably should be removed in the future.
05939     */
05940     function hiddenInvisibleString()
05941     {
05942         return ( $this->IsHidden ? 'H' : '-' ) . '/' . ( $this->IsInvisible ? 'X' : '-' );
05943     }
05944 
05945     /*!
05946     \return combined string representation of both "is_hidden" and "is_invisible" attributes
05947     Used in the limitation handling templates.
05948     */
05949     function hiddenStatusString()
05950     {
05951         if( $this->IsHidden )
05952         {
05953             return ezi18n( 'kernel/content', 'Hidden' );
05954         }
05955         else if( $this->IsInvisible )
05956         {
05957             return ezi18n( 'kernel/content', 'Hidden by superior' );
05958         }
05959         return ezi18n( 'kernel/content', 'Visible' );
05960     }
05961 
05962     /*!
05963      \a static
05964 
05965      \param $node            Root node of the subtree
05966      \param $modifyRootNode  Whether to modify the root node (true/false)
05967 
05968      Hide algorithm:
05969      if ( root node of the subtree is visible )
05970      {
05971         1) Mark root node as hidden and invisible
05972         2) Recursively mark child nodes as invisible except for ones which have been previously marked as invisible
05973      }
05974      else
05975      {
05976         Mark root node as hidden
05977      }
05978 
05979      In some cases we don't want to touch the root node when (un)hiding a subtree, for example
05980      after content/move or content/copy.
05981      That's why $modifyRootNode argument is used.
05982 
05983      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
05984      the calls within a db transaction; thus within db->begin and db->commit.
05985     */
05986     static function hideSubTree( &$node, $modifyRootNode = true )
05987     {
05988         $nodeID = $node->attribute( 'node_id' );
05989         $time = time();
05990         $db = eZDB::instance();
05991 
05992         $db->begin();
05993 
05994         if ( !$node->attribute( 'is_invisible' ) ) // if root node is visible
05995         {
05996             // 1) Mark root node as hidden and invisible.
05997             if ( $modifyRootNode )
05998                 $db->query( "UPDATE ezcontentobject_tree SET is_hidden=1, is_invisible=1, modified_subnode=$time WHERE node_id=$nodeID" );
05999 
06000             // 2) Recursively mark child nodes as invisible, except for ones which have been previously marked as invisible.
06001             $nodePath = $node->attribute( 'path_string' );
06002             $db->query( "UPDATE ezcontentobject_tree SET is_invisible=1, modified_subnode=$time WHERE is_invisible=0 AND path_string LIKE '$nodePath%'" );
06003         }
06004         else
06005         {
06006             // Mark root node as hidden
06007             if ( $modifyRootNode )
06008                 $db->query( "UPDATE ezcontentobject_tree SET is_hidden=1, modified_subnode=$time WHERE node_id=$nodeID" );
06009         }
06010 
06011         $node->updateAndStoreModified();
06012 
06013         $db->commit();
06014 
06015         eZContentObjectTreeNode::clearViewCacheForSubtree( $node, $modifyRootNode );
06016     }
06017 
06018     /*!
06019      \a static
06020 
06021      \param $node            Root node of the subtree
06022      \param $modifyRootNode  Whether to modify the root node (true/false)
06023 
06024      Unhide algorithm:
06025      if ( parent node is visible )
06026      {
06027         1) Mark root node as not hidden and visible.
06028         2) Recursively mark child nodes as visible (except for nodes previosly marked as hidden, and all their children).
06029      }
06030      else
06031      {
06032         Mark root node as not hidden.
06033      }
06034 
06035      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
06036      the calls within a db transaction; thus within db->begin and db->commit.
06037     */
06038     static function unhideSubTree( &$node, $modifyRootNode = true )
06039     {
06040         $nodeID = $node->attribute( 'node_id' );
06041         $nodePath = $node->attribute( 'path_string' );
06042         $nodeInvisible = $node->attribute( 'is_invisible' );
06043         $parentNode = $node->attribute( 'parent' );
06044         $time = time();
06045         $db = eZDB::instance();
06046 
06047         $db->begin();
06048 
06049         if ( ! $parentNode->attribute( 'is_invisible' ) ) // if parent node is visible
06050         {
06051             // 1) Mark root node as not hidden and visible.
06052             if ( $modifyRootNode )
06053                 $db->query( "UPDATE ezcontentobject_tree SET is_invisible=0, is_hidden=0, modified_subnode=$time WHERE node_id=$nodeID" );
06054 
06055             // 2) Recursively mark child nodes as visible (except for nodes previosly marked as hidden, and all their children).
06056 
06057             // 2.1) $hiddenChildren = Fetch all hidden children for the root node
06058             $hiddenChildren = $db->arrayQuery( "SELECT path_string FROM ezcontentobject_tree " .
06059                                                 "WHERE node_id <> $nodeID AND is_hidden=1 AND path_string LIKE '$nodePath%'" );
06060             $skipSubtreesString = '';
06061             foreach ( $hiddenChildren as $i )
06062                 $skipSubtreesString .= " AND path_string NOT LIKE '" . $i['path_string'] . "%'";
06063 
06064             // 2.2) Mark those children as visible which are not under nodes in $hiddenChildren
06065             $db->query( "UPDATE ezcontentobject_tree SET is_invisible=0, modified_subnode=$time WHERE path_string LIKE '$nodePath%' $skipSubtreesString" );
06066         }
06067         else
06068         {
06069             // Mark root node as not hidden.
06070             if ( $modifyRootNode )
06071                 $db->query( "UPDATE ezcontentobject_tree SET is_hidden=0, modified_subnode=$time WHERE node_id=$nodeID" );
06072         }
06073 
06074         $node->updateAndStoreModified();
06075 
06076         $db->commit();
06077 
06078         eZContentObjectTreeNode::clearViewCacheForSubtree( $node, $modifyRootNode );
06079     }
06080 
06081     /*!
06082      \a static
06083      Depending on the new parent node visibility, recompute "is_invisible" attribute for the given node and its children.
06084      (used after content/move or content/copy)
06085     */
06086     static function updateNodeVisibility( $node, $parentNode, $recursive = true )
06087     {
06088         if ( !$node )
06089         {
06090             eZDebug::writeWarning( 'No such node to update visibility for.' );
06091             return;
06092         }
06093 
06094         if ( !$parentNode )
06095         {
06096             eZDebug::writeWarning( 'No parent node found when updating node visibility' );
06097             return;
06098         }
06099 
06100         if ( $node->attribute( 'is_hidden' ) == 0 &&
06101              $parentNode->attribute( 'is_invisible' ) != $node->attribute( 'is_invisible' ) )
06102         {
06103             $parentNodeIsVisible = $parentNode->attribute( 'is_invisible' );
06104             $nodeID                 = $node->attribute( 'node_id' );
06105             $db                     = eZDB::instance();
06106             $db->begin();
06107             $db->query( "UPDATE ezcontentobject_tree SET is_invisible=$parentNodeIsVisible WHERE node_id=$nodeID" );
06108 
06109             if ( $recursive )
06110             {
06111                 // update visibility for children of the node
06112                 if( $parentNodeIsVisible )
06113                     eZContentObjectTreeNode::hideSubTree( $node, $modifyRootNode = false );
06114                 else
06115                     eZContentObjectTreeNode::unhideSubTree( $node, $modifyRootNode = false );
06116             }
06117             $db->commit();
06118         }
06119     }
06120 
06121     /*!
06122      \a static
06123      \return true on success, false otherwise
06124     */
06125     static function clearViewCacheForSubtree( &$node, $clearForRootNode = true )
06126     {
06127         //include_once( 'kernel/classes/ezcontentcachemanager.php' );
06128 
06129         // Max nodes to fetch at a time
06130         static $limit = 50;
06131 
06132         if ( !$node )
06133         {
06134             eZDebug::writeWarning( "No such subtree to clear view cache for" );
06135             return false;
06136         }
06137 
06138         if ( $clearForRootNode )
06139         {
06140             $objectID = $node->attribute( 'contentobject_id' );
06141             eZContentCacheManager::clearContentCacheIfNeeded( $objectID );
06142         }
06143 
06144         $offset = 0;
06145         $params = array( 'AsObject' => false,
06146                          'Depth' => false,
06147                          'Limitation' => array() ); // Empty array means no permission checking
06148         $subtreeCount = $node->subTreeCount( $params );
06149         while ( $offset < $subtreeCount )
06150         {
06151             $params['Offset'] = $offset;
06152             $params['Limit'] = $limit;
06153 
06154             $subtreeChunk = $node->subTree( $params );
06155             $nNodesInChunk = count( $subtreeChunk );
06156             $offset += $nNodesInChunk;
06157             if ( $nNodesInChunk == 0 )
06158                 break;
06159 
06160             $objectIDList = array();
06161             foreach ( $subtreeChunk as $curNode )
06162                 $objectIDList[] = $curNode['contentobject_id'];
06163             $objectIDList = array_unique( $objectIDList );
06164             unset( $subtreeChunk );
06165 
06166             foreach ( $objectIDList as $objectID )
06167                 eZContentCacheManager::clearContentCacheIfNeeded( $objectID );
06168         }
06169 
06170         return true;
06171     }
06172 
06173     static function setVersionByObjectID( $objectID, $newVersion )
06174     {
06175         $db = eZDB::instance();
06176         $db->query( "UPDATE ezcontentobject_tree SET contentobject_version='$newVersion' WHERE contentobject_id='$objectID'" );
06177     }
06178 
06179     function currentLanguage()
06180     {
06181         return $this->CurrentLanguage;
06182     }
06183 
06184     function setCurrentLanguage( $languageCode )
06185     {
06186         $this->CurrentLanguage = $languageCode;
06187         if ( $this->hasContentObject() )
06188         {
06189             $this->ContentObject->setCurrentLanguage( $languageCode );
06190         }
06191         $this->Name = null;
06192     }
06193 
06194     /*!
06195      \static
06196     */
06197     static function parentDepthLimitationList()
06198     {
06199         $maxLevel = 0;
06200         $ini = eZINI::instance();
06201         if ( $ini->hasVariable( 'RoleSettings', 'MaxParentDepthLimitation' ) )
06202             $maxLevel = $ini->variable( 'RoleSettings', 'MaxParentDepthLimitation' );
06203 
06204         $depthArray = array();
06205         for ( $i = 1; $i <= $maxLevel; $i++ )
06206         {
06207             $depthArray[] = array( 'name' => $i, 'id' => $i );
06208         }
06209 
06210         return $depthArray;
06211     }
06212 
06213     /*
06214       Returns available classes as Js array.
06215       Checks if the node is container, if yes emptyStr will be returned.
06216     */
06217     static function availableClassesJsArray()
06218     {
06219         return eZContentObjectTreeNode::availableClassListJsArray( array( 'node' => &$this ) );
06220     }
06221 
06222     /*
06223       Returns available classes as Js array.
06224       Checks for ini settings.
06225     */
06226     static function availableClassListJsArray( $parameters = false )
06227     {
06228         $iniMenu = eZINI::instance( 'contentstructuremenu.ini' );
06229         $falseValue = "''";
06230 
06231         if ( $iniMenu->hasVariable( 'TreeMenu', 'CreateHereMenu' ) )
06232         {
06233             $createHereMenu = $iniMenu->variable( 'TreeMenu', 'CreateHereMenu' );
06234         }
06235         else
06236         {
06237             $createHereMenu = 'simplified';
06238         }
06239         if ( $createHereMenu != 'simplified' and $createHereMenu != 'full' )
06240             return $falseValue;
06241 
06242         $ini = eZINI::instance( 'content.ini' );
06243         list( $usersClassGroupID, $setupClassGroupID ) = $ini->variableMulti( 'ClassGroupIDs', array( 'Users', 'Setup' ) );
06244         $userRootNode = $ini->variable( 'NodeSettings', 'UserRootNode' );
06245         $groupIDs = false;
06246         $filterType = 'include';
06247 
06248         if ( !is_array( $parameters ) )
06249             return $falseValue;
06250 
06251         $node = isset( $parameters['node'] ) ? $parameters['node'] : false;
06252         if ( is_object( $node ) )
06253         {
06254             if ( $createHereMenu == 'full' and !$node->canCreate() )
06255                 return $falseValue;
06256 
06257             $obj = $node->object();
06258             $contentClass = $obj->attribute( 'content_class' );
06259             if ( !$contentClass->attribute( 'is_container' ) )
06260             {
06261                 return $falseValue;
06262             }
06263 
06264             $pathArray = $node->pathArray();
06265         }
06266         else
06267         {
06268             // If current object is not container we should not return class list, should not display "create here" menu.
06269             if ( isset( $parameters['is_container'] ) and !$parameters['is_container'] )
06270                 return $falseValue;
06271 
06272             // Check if current user can create under this node
06273             if ( $createHereMenu == 'full' and isset( $parameters['node_id'] ) )
06274             {
06275                 $node = eZContentObjectTreeNode::fetch( $parameters['node_id'] );
06276                 if ( is_object( $node ) and !$node->canCreate() )
06277                     return $falseValue;
06278             }
06279             $pathString = isset( $parameters['path_string'] ) ? $parameters['path_string'] : false;
06280             if ( !$pathString )
06281                 return $falseValue;
06282 
06283             $pathItems = explode( '/', $pathString );
06284             $pathArray = array();
06285             foreach ( $pathItems as $pathItem )
06286             {
06287                 if ( $pathItem != '' )
06288                     $pathArray[] = (int) $pathItem;
06289             }
06290         }
06291 
06292         if ( in_array( $userRootNode, $pathArray ) )
06293         {
06294             $groupIDs = array( $usersClassGroupID );
06295         }
06296         else
06297         {
06298             $groupIDs = array( $usersClassGroupID, $setupClassGroupID );
06299             $filterType = 'exclude';
06300         }
06301 
06302         if ( $createHereMenu == 'simplified' )
06303         {
06304             //include_once( "kernel/classes/ezcontentclass.php" );
06305             $classes = eZContentClass::fetchAllClasses( false, $filterType == 'include', $groupIDs );
06306             return eZContentObjectTreeNode::getClassesJsArray( false, $filterType == 'include', $groupIDs, false, $classes );
06307         }
06308 
06309         return eZContentObjectTreeNode::getClassesJsArray( $node, $filterType == 'include', $groupIDs );
06310     }
06311 
06312     /*
06313       Returns available classes as Js array.
06314       \note building js array.
06315     */
06316     static function getClassesJsArray( $node = false, $includeFilter = true, $groupList = false, $fetchID = false, $classes = false )
06317     {
06318         //include_once( 'kernel/classes/ezcontentclass.php' );
06319         $falseValue = "''";
06320         // If $classes is false we should check $node and fetch class list
06321         if ( $classes === false )
06322         {
06323             // If $node is object we should fetch available classes from node, from ezcontentclass otherwise
06324             $classes = ( is_object( $node ) and strtolower( get_class( $node ) ) == 'ezcontentobjecttreenode' )
06325                         ? $node->canCreateClassList( false, $includeFilter, $groupList, $fetchID )
06326                         : eZContentClass::canInstantiateClassList( false, $includeFilter, $groupList, $fetchID );
06327         }
06328         if ( !is_array( $classes ) )
06329             return $falseValue;
06330 
06331         // Create javascript array
06332         $jsArray = array();
06333         $db = eZDB::instance();
06334         foreach ( $classes as $class )
06335         {
06336             if ( is_object( $class ) )
06337             {
06338                 $classID = $class->attribute( 'id' );
06339                 $className = $class->attribute( 'name' );
06340             }
06341             elseif ( is_array( $class ) )
06342             {
06343                 $classID = $class['id'];
06344                 $className = $class['name'];
06345             }
06346             $jsArray[] = "{ classID: '" . $db->escapeString( $classID ) .
06347                           "', name: '" . $db->escapeString( $className ) . "' }";
06348         }
06349 
06350         if ( $jsArray )
06351             return '[ '.implode( ', ', $jsArray ).' ]';
06352 
06353         return $falseValue;
06354     }
06355 
06356 
06357     /// The current language for the node
06358     public $CurrentLanguage = false;
06359 
06360     /// Name of the node
06361     public $Name;
06362 
06363     /// Contains the cached value of the class identifier
06364     public $ClassIdentifier = null;
06365     public $ClassName = null;
06366 }
06367 
06368 ?>