Skip to content

Commit

Permalink
Merge pull request #924 from ezsystems/fix/EZP-21324-copy_old_version…
Browse files Browse the repository at this point in the history
…_images

EZP-22402: Refactored aliases handling
  • Loading branch information
bdunogier committed Apr 5, 2014
2 parents 9193a13 + 61aaa00 commit b072583
Show file tree
Hide file tree
Showing 10 changed files with 245 additions and 164 deletions.
214 changes: 89 additions & 125 deletions kernel/classes/datatypes/ezimage/ezimagealiashandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -644,9 +644,12 @@ function aliasList( $checkValidity = true )
*
* @param eZContentObjectAttribute
* @note If you want to remove the alias information use removeAliases().
*
* @deprecated use removeAliases, it does the same thing
*/
static function removeAllAliases( $contentObjectAttribute )
{
/** @var eZImageAliasHandler $handler */
$handler = $contentObjectAttribute->attribute( 'content' );
if ( !$handler->isImageOwner() )
{
Expand Down Expand Up @@ -676,162 +679,116 @@ static function removeAllAliases( $contentObjectAttribute )
/**
* Removes the images alias while keeping the original image.
* @see eZCache::purgeAllAliases()
*
* @param eZContentObjectAttribute $contentObjectAttribute
*/
public function purgeAllAliases( eZContentObjectAttribute $contentObjectAttribute )
public function purgeAllAliases()
{
$aliasList = $this->aliasList( false );
unset( $aliasList['original'] ); // keeping original

foreach ( $aliasList as $aliasName => $alias )
foreach ( $aliasList as $alias )
{
$filepath = $alias['url'];

eZImageFile::removeFilepath( $this->ContentObjectAttributeData['id'], $filepath );
if ( $alias['is_valid'] )
$this->removeAliasFile( $alias['url'] );

$file = eZClusterFileHandler::instance( $filepath );
if ( $file->exists() )
{
$file->purge();
eZDir::cleanupEmptyDirectories( $alias['dirpath'] );
}
else
// remove entry from DOM model
$doc = $this->ContentObjectAttributeData['DataTypeCustom']['dom_tree'];
$domXPath = new DOMXPath( $doc );
foreach ( $domXPath->query( "//alias[@name='{$alias['name']}']") as $aliasNode )
{
eZDebug::writeError( "Image file $filepath for alias $aliasName does not exist, could not remove from disk", __METHOD__ );
$aliasNode->parentNode->removeChild( $aliasNode );
}
}

$doc = $this->ContentObjectAttributeData['DataTypeCustom']['dom_tree'];
foreach ( $doc->getElementsByTagName( 'alias' ) as $aliasNode )
if ( isset( $doc ) )
$this->storeDOMTree( $doc, true, false );
}

/**
* Removes aliases from the attribute.
*
* Files, as well as their references in ezimagefile, are only removed if this attribute/version was
* the last one referencing it. The attribute's XML is then reset to reference no image.
*/
function removeAliases()
{
foreach ( $this->aliasList() as $alias )
{
$aliasNode->parentNode->removeChild( $aliasNode );
if ( $alias['is_valid'] )
$this->removeAliasFile( $alias['url'] );
}
$this->ContentObjectAttributeData['DataTypeCustom']['dom_tree'] = $doc;
unset( $this->ContentObjectAttributeData['DataTypeCustom']['alias_list'] );

$this->storeDOMTree( $doc, true, $contentObjectAttribute );
$this->generateXMLData();
}

/**
* Removes all the image aliases and their information.
* The stored images will also be removed if the attribute is the owner
* of the images.
* Removes $aliasFile and references to it for the attribute.
*
* After the images are removed the attribute will containe an internal
* structure with empty data
* The eZImageFile entry as well as the file are only removed if this attribute was the last reference.
*
* @param eZContentObjectAttribute $contentObjectAttribute
* Content object attribute to remove aliases for
* @param string $aliasFile
*
* @return void
* @return array bool true if something was actually done, false otherwise
*/
function removeAliases( $contentObjectAttribute )
public function removeAliasFile( $aliasFile )
{
$aliasList = $this->aliasList();
$alternativeText = false;
if ( $aliasFile == '' )
throw new InvalidArgumentException( "Expecting image file path" );

$contentObjectAttributeVersion = $this->ContentObjectAttributeData['version'];
$contentObjectAttributeID = $this->ContentObjectAttributeData['id'];
$filePathIsReferencedByOtherAttributes = false;

$isImageOwner = $this->isImageOwner();

// We loop over each image alias, and look up the file in ezcontentobject_attribute
// Only images referenced by one version will be removed
foreach ( $aliasList as $aliasName => $alias )
// we must check all eZImageFile referencing the alias file
$imageFilesReferencingFilePath = eZImageFile::fetchListByFilepath( $aliasFile );
foreach ( $imageFilesReferencingFilePath as $imageFileData )
{
$dirpath = $alias['dirpath'];
$doNotDelete = false; // Do not delete files from storage

if ( $aliasName == 'original' )
$alternativeText = $alias['alternative_text'];
if ( $alias['is_valid'] )
if ( $imageFileData['contentobject_attribute_id'] != $this->ContentObjectAttributeData['id'] )
{
$filepath = $alias['url'];

/**
* If there are no ezimagefile references to this file with this content object attribute id,
* we are dealing with an attribute that was copied from another content.
* The image doesn't belong to us, and we just don't do anything.
* See http://jira.ez.no/browse/EZP-21324
*/
if ( !eZImageFile::fetchByFilepath( $contentObjectAttributeID, $filepath ) )
continue;
$filePathIsReferencedByOtherAttributes = true;
}

// Fetch ezimage attributes that use $filepath
// Always returns current attribute (array of $contentObjectAttributeID and $contentObjectAttributeVersion)
$dbResult = eZImageFile::fetchImageAttributesByFilepath( $filepath, $contentObjectAttributeID );
$dbResultCount = count( $dbResult );
// Check if there are the attributes.
if ( $dbResultCount > 0 )
{
$doNotDelete = true;
foreach ( $dbResult as $res )
{
// We only look results where the version matches
if ( $res['version'] == $contentObjectAttributeVersion )
{
// If more than one result has been returned, it means
// that another version is using the same image,
// and we should not delete this file
if ( $dbResultCount > 1 )
{
continue;
}
// Only one result means that the current attribute
// & version are the only ones using this image,
// and it can be removed
else
{
$doNotDelete = false;
}
}
$imageFileIsReferencedByOtherAttributes = false;

eZImageFile::appendFilepath( $res['id'], $filepath, true );
}
}
// we skip eZImageFile entries that reference another contentobject attribute or another version/language
foreach ( eZImageFile::fetchImageAttributesByFilepath( $aliasFile, $imageFileData['contentobject_attribute_id'] ) as $attribute )
{
if ( $attribute['id'] != $this->ContentObjectAttributeData['id'] )
continue;

if ( !$doNotDelete )
if (
$attribute['version'] != $this->ContentObjectAttributeData['version'] ||
$attribute['language_code'] != $this->ContentObjectAttributeData['language_code']
)
{
eZImageFile::removeFilepath( $contentObjectAttributeID, $filepath );

$file = eZClusterFileHandler::instance( $filepath );
if ( $file->exists() )
{
$file->delete();
eZDir::cleanupEmptyDirectories( $dirpath );
}
else
{
eZDebug::writeError( "Image file $filepath for alias $aliasName does not exist, could not remove from disk", __METHOD__ );
}
$filePathIsReferencedByOtherAttributes = true;
$imageFileIsReferencedByOtherAttributes = true;
break;
}
}
}

$doc = new DOMDocument( '1.0', 'utf-8' );
$imageNode = $doc->createElement( "ezimage" );
$doc->appendChild( $imageNode );
if ( $imageFileIsReferencedByOtherAttributes )
continue;

$imageNode->setAttribute( 'serial_number', false );
$imageNode->setAttribute( 'is_valid', false );
$imageNode->setAttribute( 'filename', false );
$imageNode->setAttribute( 'suffix', false );
$imageNode->setAttribute( 'basename', false );
$imageNode->setAttribute( 'dirpath', false );
$imageNode->setAttribute( 'url', false );
$imageNode->setAttribute( 'original_filename', false );
$imageNode->setAttribute( 'mime_type', false );
$imageNode->setAttribute( 'width', false );
$imageNode->setAttribute( 'height', false );
$imageNode->setAttribute( 'alternative_text', $alternativeText );
$imageNode->setAttribute( 'alias_key', false );
$imageNode->setAttribute( 'timestamp', false );
// we remove all rows since we can have duplicates
eZImageFile::removeObject(
eZImageFile::definition(),
array(
'contentobject_attribute_id' => $this->ContentObjectAttributeData['id'],
'filepath' => $aliasFile
)
);

$this->ContentObjectAttributeData['DataTypeCustom']['dom_tree'] = $doc;
unset( $this->ContentObjectAttributeData['DataTypeCustom']['alias_list'] );
}

$this->storeDOMTree( $doc, true, $contentObjectAttribute );
// remove file, if applicable
if ( $filePathIsReferencedByOtherAttributes )
return;
$file = eZClusterFileHandler::instance( $aliasFile );
if ( !$file->exists() )
{
eZDebug::writeError( "Image file {$aliasFile} does not exist, could not remove from disk", __METHOD__ );
return;
}
$file->delete();
eZDir::cleanupEmptyDirectories( dirname( $aliasFile ) );
}

/*!
Expand Down Expand Up @@ -876,7 +833,16 @@ function updateAliasPath( $dirpath, $name )
{
$fileHandler = eZClusterFileHandler::instance();
$fileHandler->fileLinkCopy( $oldURL, $alias['url'], false );
eZImageFile::appendFilepath( $this->ContentObjectAttributeData['id'], $alias['url'] );

// we still move the file if no other attribute from the current content uses it
if ( count( eZImageFile::fetchImageAttributesByFilepath( $oldURL, $this->ContentObjectAttributeData['id'] ) ) == 1 )
{
eZImageFile::moveFilepath( $this->ContentObjectAttributeData['id'], $oldURL, $alias['url'] );
}
else
{
eZImageFile::appendFilepath( $this->ContentObjectAttributeData['id'], $alias['url'] );
}
}
$this->setAliasVariation( $aliasName, $alias );
}
Expand Down Expand Up @@ -1133,8 +1099,7 @@ function initializeFromHTTPFile( $httpFile, $imageAltText = false )
$mimeData = eZMimeType::findByURL( $httpFile->attribute( 'original_filename' ) );
}
}
$attr = false;
$this->removeAliases( $attr );
$this->removeAliases();
$this->setOriginalAttributeDataValues( $this->ContentObjectAttributeData['id'],
$this->ContentObjectAttributeData['version'],
$this->ContentObjectAttributeData['language_code'] );
Expand Down Expand Up @@ -1190,8 +1155,7 @@ function initializeFromFile( $filename, $imageAltText = false, $originalFilename
$mimeData = eZMimeType::findByFileContents( $originalFilename );
}

$attr = false;
$this->removeAliases( $attr );
$this->removeAliases();
$this->setOriginalAttributeDataValues( $this->ContentObjectAttributeData['id'],
$this->ContentObjectAttributeData['version'],
$this->ContentObjectAttributeData['language_code'] );
Expand Down
39 changes: 33 additions & 6 deletions kernel/classes/datatypes/ezimage/ezimagefile.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,7 @@ static function fetchForContentObjectAttribute( $contentObjectAttributeID, $asOb
* @param string $filePath file path to look up as URL in the XML string
* @param int $contentObjectAttributeID
*
* @return array An array of content object attribute ids and versions of
* image files where the url is referenced
*
* @todo Rewrite ! A where data_text LIKE '%xxx%' is a resource hog !
* @return array An array with a series of ezcontentobject_attribute's id, version and language_code
*/
static function fetchImageAttributesByFilepath( $filepath, $contentObjectAttributeID )
{
Expand Down Expand Up @@ -117,7 +114,7 @@ static function fetchImageAttributesByFilepath( $filepath, $contentObjectAttribu
);
// Escape _ in like to avoid it to act as a wildcard !
$filepath = addcslashes( $filepath, "_" );
$query = "SELECT id, version
$query = "SELECT id, version, language_code
FROM ezcontentobject_attribute
WHERE contentobject_id = $contentObjectID AND
contentclassattribute_id = $contentClassAttributeID AND
Expand All @@ -130,10 +127,22 @@ static function fetchImageAttributesByFilepath( $filepath, $contentObjectAttribu
return $rows;
}

/**
* Fetches the eZImageFile objects matching $filepath, optionally filtered by content object attribute id
*
* @param int $contentObjectAttributeId Optional content object attribute id to filter on. Set to false to disable.
* @param string $filepath
* @param bool $asObject
*
* @return eZImageFile
*
* @todo This method is actually wrong: the method could return multiple objects (EZP-21324)
*/
static function fetchByFilepath( $contentObjectAttributeID, $filepath, $asObject = true )
{
// Fetch by file path without $contentObjectAttributeID
if ( $contentObjectAttributeID === false )

return eZPersistentObject::fetchObject( eZImageFile::definition(),
null,
array( 'filepath' => $filepath ),
Expand All @@ -146,6 +155,25 @@ static function fetchByFilepath( $contentObjectAttributeID, $filepath, $asObject
$asObject );
}

/**
* Fetches unique eZImageFile data (as an array) for $filePath
*
* @param string $filePath
*
* @return array array of hash. Keys: contentobject_attribute_id, filepath
*/
static function fetchListByFilePath( $filePath )
{
return eZPersistentObject::fetchObjectList(
eZImageFile::definition(),
array( 'contentobject_attribute_id', 'filepath' ),
array( 'filepath' => $filePath ),
null,
null,
false
);
}

static function moveFilepath( $contentObjectAttributeID, $oldFilepath, $newFilepath )
{
$db = eZDB::instance();
Expand Down Expand Up @@ -197,7 +225,6 @@ static function removeForContentObjectAttribute( $contentObjectAttributeID )


/// \privatesection
public $ID;
public $ContentObjectAttributeID;
public $Filepath;
}
Expand Down
Loading

0 comments on commit b072583

Please sign in to comment.