eZ Publish  [trunk]
ezkeyword.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZKeyword class.
00004  *
00005  * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved.
00006  * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
00007  * @version //autogentag//
00008  * @package kernel
00009  */
00010 
00011 /*!
00012   \class eZKeyword ezkeyword.php
00013   \ingroup eZDatatype
00014   \brief A content datatype which handles keyword index instances
00015 
00016 */
00017 
00018 class eZKeyword
00019 {
00020     /*!
00021      Construct a new keyword instance
00022     */
00023     function eZKeyword( )
00024     {
00025     }
00026 
00027     function attributes()
00028     {
00029         return array( 'keywords',
00030                       'keyword_string',
00031                       'related_objects',
00032                       'related_nodes' );
00033     }
00034 
00035     function hasAttribute( $name )
00036     {
00037         return in_array( $name, $this->attributes() );
00038     }
00039 
00040     function attribute( $name )
00041     {
00042         switch ( $name )
00043         {
00044             case 'keywords' :
00045             {
00046                 return $this->KeywordArray;
00047             }break;
00048 
00049             case 'keyword_string' :
00050             {
00051                 return $this->keywordString();
00052             }break;
00053 
00054             case 'related_objects' :
00055             case 'related_nodes' :
00056             {
00057                 return $this->relatedObjects();
00058             }break;
00059             default:
00060             {
00061                 eZDebug::writeError( "Attribute '$name' does not exist", __METHOD__ );
00062                 return null;
00063             }break;
00064         }
00065     }
00066 
00067     /*!
00068      Initialze the keyword index
00069     */
00070     function initializeKeyword( $keywordString )
00071     {
00072         if ( !is_array( $keywordString ) )
00073         {
00074             $keywordArray = explode( ',', $keywordString );
00075             $keywordArray = array_unique ( $keywordArray );
00076         }
00077         foreach ( array_keys( $keywordArray ) as $key )
00078         {
00079             if ( trim( $keywordArray[$key] ) != '' )
00080             {
00081                 $this->KeywordArray[$key] = trim( $keywordArray[$key] );
00082             }
00083         }
00084     }
00085 
00086     /*!
00087      Stores the keyword index to database
00088     */
00089     function store( $attribute )
00090     {
00091         $db = eZDB::instance();
00092 
00093         $object = $attribute->attribute( 'object' );
00094         $classID = $object->attribute( 'contentclass_id' );
00095 
00096         // Get already existing keywords
00097         if ( count( $this->KeywordArray ) > 0 )
00098         {
00099             $escapedKeywordArray = array();
00100             foreach( $this->KeywordArray as $keyword )
00101             {
00102                 $keyword = $db->escapeString( $keyword );
00103                 $escapedKeywordArray[] = $keyword;
00104             }
00105             $wordsString = implode( '\',\'', $escapedKeywordArray );
00106             $existingWords = $db->arrayQuery( "SELECT * FROM ezkeyword WHERE keyword IN ( '$wordsString' ) AND class_id='$classID' " );
00107         }
00108         else
00109         {
00110             $existingWords = array();
00111         }
00112 
00113         $newWordArray = array();
00114         $existingWordArray = array();
00115         // Find out which words to store
00116         foreach ( $this->KeywordArray as $keyword )
00117         {
00118             $wordExists = false;
00119             $wordID = false;
00120             foreach ( $existingWords as $existingKeyword )
00121             {
00122                 if ( $keyword == $existingKeyword['keyword'] )
00123                 {
00124                      $wordExists = true;
00125                      $wordID = $existingKeyword['id'];
00126                      break;
00127                 }
00128             }
00129 
00130             if ( $wordExists == false )
00131             {
00132                 $newWordArray[] = $keyword;
00133             }
00134             else
00135             {
00136                 $existingWordArray[] = array( 'keyword' => $keyword, 'id' => $wordID );
00137             }
00138         }
00139 
00140         // Store every new keyword
00141         $addRelationWordArray = array();
00142         foreach ( $newWordArray as $keyword )
00143         {
00144             $keyword = trim( $keyword );
00145             $keyword = $db->escapeString( $keyword );
00146             $db->query( "INSERT INTO ezkeyword ( keyword, class_id ) VALUES ( '$keyword', '$classID' )" );
00147 
00148             $keywordID = $db->lastSerialID( 'ezkeyword', 'id' );
00149             $addRelationWordArray[] = array( 'keyword' => $keywordID, 'id' => $keywordID );
00150         }
00151 
00152         $attributeID = $attribute->attribute( 'id' );
00153         // Find the words which is new for this attribute
00154         if ( $attributeID !== null )
00155         {
00156             $currentWordArray = $db->arrayQuery( "SELECT ezkeyword.id, ezkeyword.keyword FROM ezkeyword, ezkeyword_attribute_link
00157                                                    WHERE ezkeyword.id=ezkeyword_attribute_link.keyword_id
00158                                                    AND ezkeyword_attribute_link.objectattribute_id='$attributeID'" );
00159         }
00160         else
00161             $currentWordArray = array();
00162 
00163         foreach ( $existingWordArray as $existingWord )
00164         {
00165             $newWord = true;
00166             foreach ( $currentWordArray as $currentWord )
00167             {
00168                 if ( $existingWord['keyword']  == $currentWord['keyword'] )
00169                 {
00170                     $newWord = false;
00171                 }
00172             }
00173 
00174             if ( $newWord == true )
00175             {
00176                 $addRelationWordArray[] = $existingWord;
00177             }
00178         }
00179 
00180         // Find the current words no longer used
00181         $removeWordRelationIDArray = array();
00182         foreach ( $currentWordArray as $currentWord )
00183         {
00184             $stillUsed = false;
00185             foreach ( $this->KeywordArray as $keyword )
00186             {
00187                 if ( $keyword == $currentWord['keyword'] )
00188                     $stillUsed = true;
00189             }
00190             if ( !$stillUsed )
00191             {
00192                 $removeWordRelationIDArray[] = $currentWord['id'];
00193             }
00194         }
00195 
00196         if ( count( $removeWordRelationIDArray ) > 0 )
00197         {
00198             $removeIDString = implode( ', ', $removeWordRelationIDArray );
00199             $db->query( "DELETE FROM ezkeyword_attribute_link WHERE keyword_id IN ( $removeIDString ) AND  ezkeyword_attribute_link.objectattribute_id='$attributeID'" );
00200         }
00201 
00202         // Only store relation to new keywords
00203         // Store relations to keyword for this content object
00204         foreach ( $addRelationWordArray as $keywordArray )
00205         {
00206             $db->query( "INSERT INTO ezkeyword_attribute_link ( keyword_id, objectattribute_id ) VALUES ( '" . $keywordArray['id'] ."', '" . $attribute->attribute( 'id' ) . "' )" );
00207         }
00208 
00209         /* Clean up no longer used words:
00210          * 1. Select words having no links.
00211          * 2. Delete them.
00212          * We cannot do this in one cross-table DELETE since older MySQL versions do not support this.
00213          */
00214         if ( $db->databaseName() == 'oracle' )
00215         {
00216             $query =
00217                 'SELECT ezkeyword.id FROM ezkeyword, ezkeyword_attribute_link ' .
00218                 'WHERE ezkeyword.id=ezkeyword_attribute_link.keyword_id(+) AND ' .
00219                 'ezkeyword_attribute_link.keyword_id IS NULL';
00220         }
00221         else
00222         {
00223             $query =
00224                 'SELECT ezkeyword.id FROM ezkeyword LEFT JOIN ezkeyword_attribute_link ' .
00225                 ' ON ezkeyword.id=ezkeyword_attribute_link.keyword_id' .
00226                 ' WHERE ezkeyword_attribute_link.keyword_id IS NULL';
00227         }
00228         $unusedWordsIDs = $db->arrayQuery( $query );
00229         foreach ( $unusedWordsIDs as $wordID )
00230             $db->query( 'DELETE FROM ezkeyword WHERE id=' . $wordID['id'] );
00231     }
00232 
00233     /*!
00234      Fetches the keywords for the given attribute.
00235     */
00236     function fetch( &$attribute )
00237     {
00238         if ( $attribute->attribute( 'id' ) === null )
00239             return;
00240 
00241         $db = eZDB::instance();
00242         $wordArray = $db->arrayQuery( "SELECT ezkeyword.keyword FROM ezkeyword_attribute_link, ezkeyword
00243                                     WHERE ezkeyword_attribute_link.keyword_id=ezkeyword.id AND
00244                                     ezkeyword_attribute_link.objectattribute_id='" . $attribute->attribute( 'id' ) ."' " );
00245 
00246         $this->ObjectAttributeID = $attribute->attribute( 'id' );
00247         foreach ( array_keys( $wordArray ) as $wordKey )
00248         {
00249             $this->KeywordArray[] = $wordArray[$wordKey]['keyword'];
00250         }
00251         $this->KeywordArray = array_unique ( $this->KeywordArray );
00252     }
00253 
00254     /*!
00255      Sets the keyword index
00256     */
00257     function setKeywordArray( $keywords )
00258     {
00259         $this->KeywordArray = $keywords;
00260     }
00261 
00262     /*!
00263      Returns the keyword index
00264     */
00265     function keywordArray( )
00266     {
00267         return $this->KeywordArray;
00268     }
00269 
00270     /*!
00271      Returns the keywords as a string
00272     */
00273     function keywordString()
00274     {
00275         return implode( ', ', $this->KeywordArray );
00276     }
00277 
00278     /*!
00279      Returns the objects which have at least one keyword in common
00280 
00281      \return an array of eZContentObjectTreeNode instances, or null if the attribute is not stored yet
00282     */
00283     function relatedObjects()
00284     {
00285         $return = false;
00286         if ( $this->ObjectAttributeID )
00287         {
00288             $return = array();
00289 
00290             // Fetch words
00291             $db = eZDB::instance();
00292 
00293             $wordArray = $db->arrayQuery( "SELECT * FROM ezkeyword_attribute_link
00294                                            WHERE objectattribute_id='" . $this->ObjectAttributeID ."' " );
00295 
00296             $keywordIDArray = array();
00297             // Fetch the objects which have one of these words
00298             foreach ( $wordArray as $word )
00299             {
00300                 $keywordIDArray[] = $word['keyword_id'];
00301             }
00302 
00303             $keywordCondition = $db->generateSQLINStatement( $keywordIDArray, 'keyword_id' );
00304 
00305             if ( count( $keywordIDArray ) > 0 )
00306             {
00307                 $objectArray = $db->arrayQuery( "SELECT DISTINCT ezcontentobject_attribute.contentobject_id FROM ezkeyword_attribute_link, ezcontentobject_attribute
00308                                                   WHERE $keywordCondition AND
00309                                                         ezcontentobject_attribute.id = ezkeyword_attribute_link.objectattribute_id
00310                                                         AND  objectattribute_id <> '" . $this->ObjectAttributeID ."' " );
00311 
00312                 $objectIDArray = array();
00313                 foreach ( $objectArray as $object )
00314                 {
00315                     $objectIDArray[] = $object['contentobject_id'];
00316                 }
00317 
00318                 if ( count( $objectIDArray ) > 0 )
00319                 {
00320                     $aNodes = eZContentObjectTreeNode::findMainNodeArray( $objectIDArray );
00321 
00322                     foreach ( $aNodes as $key => $node )
00323                     {
00324                         $theObject = $node->object();
00325                         if ( $theObject->canRead() )
00326                         {
00327                             $return[] = $node;
00328                         }
00329                     }
00330                 }
00331             }
00332         }
00333         return $return;
00334     }
00335 
00336     /// Contains the keywords
00337     public $KeywordArray = array();
00338 
00339     /// Contains the ID attribute if fetched
00340     public $ObjectAttributeID = false;
00341 }
00342 
00343 ?>