static function unhideSubTree( eZContentObjectTreeNode $node, $modifyRootNode = true )
    {
        $nodeID = $node->attribute( 'node_id' );
        $nodePath = $node->attribute( 'path_string' );
        $nodeInvisible = $node->attribute( 'is_invisible' );
        $parentNode = $node->attribute( 'parent' );
        if ( !$parentNode instanceof eZContentObjectTreeNode )
        {
            eZDebug::writeError( "Parent of Node #$nodeID doesn't exist or inaccesible.", __METHOD__ );
            return;
        }

        $time = time();

        if ( eZAudit::isAuditEnabled() )
        {
            // Set audit params.
            $objectID = $node->attribute( 'contentobject_id' );
            $objectName = $node->attribute( 'name' );

            eZAudit::writeAudit( 'content-hide', array( 'Node ID' => $nodeID,
                                                        'Object ID' => $objectID,
                                                        'Content Name' => $objectName,
                                                        'Time' => $time,
                                                        'Comment' => 'Node has been unhidden: eZContentObjectTreeNode::unhideSubTree()' ) );
        }

        $db = eZDB::instance();

        $db->begin();

        if ( ! $parentNode->attribute( 'is_invisible' ) ) // if parent node is visible
        {
            // 1) Mark root node as not hidden and visible.
            if ( $modifyRootNode )
                $db->query( "UPDATE ezcontentobject_tree SET is_invisible=0, is_hidden=0, modified_subnode=$time WHERE node_id=$nodeID" );

            // 2) Recursively mark child nodes as visible (except for nodes previosly marked as hidden, and all their children).

            // 2.1) $hiddenChildren = Fetch all hidden children for the root node
            $hiddenChildren = $db->arrayQuery( "SELECT path_string FROM ezcontentobject_tree " .
                                                "WHERE node_id <> $nodeID AND is_hidden=1 AND path_string LIKE '$nodePath%'" );
            $skipSubtreesString = '';
            foreach ( $hiddenChildren as $i )
                $skipSubtreesString .= " AND path_string NOT LIKE '" . $i['path_string'] . "%'";

            // 2.2) Mark those children as visible which are not under nodes in $hiddenChildren
            $db->query( "UPDATE ezcontentobject_tree SET is_invisible=0, modified_subnode=$time WHERE path_string LIKE '$nodePath%' $skipSubtreesString" );
        }
        else
        {
            // Mark root node as not hidden.
            if ( $modifyRootNode )
                $db->query( "UPDATE ezcontentobject_tree SET is_hidden=0, modified_subnode=$time WHERE node_id=$nodeID" );
        }

        $node->updateAndStoreModified();

        $db->commit();

        eZContentObjectTreeNode::clearViewCacheForSubtree( $node, $modifyRootNode );
    }