-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from ezsystems/convert_to_richtext
EZP-25358: ezxmltext:convert-to-richtext command prototype
- Loading branch information
Showing
3 changed files
with
312 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,31 @@ | ||
# XmlText field type for eZ Platform | ||
|
||
This is the XmlText FieldType for eZ Platform. It was extracted from the eZ Publish / Platform 5.x. | ||
|
||
## Migrating from XmlText to RichText | ||
|
||
**Warning: this part is a non-finalized work-in-progress. Always make a backup before using the migration tools.** | ||
|
||
This package provides tools to migration existing XmlText fields to RichText, the enriched text format eZ Platform uses. | ||
The tool comes as a Symfony command, `ezxmltext:convert-to-richtext`. | ||
|
||
It will do two things: | ||
|
||
- convert `ezxmltext` field definitions to `ezrichtext` field definitions | ||
- convert `ezxmltext` fields (content) to `ezrichtext` | ||
|
||
We recommend that you execute it this way: | ||
|
||
``` | ||
php app/console ezxmltext:convert-to-richtext -v | ||
``` | ||
|
||
The `-v` flag will output logs to the console, making it easy to track the conversion work that is being done. | ||
This is an example of a successful conversion log entry for one field: | ||
|
||
``` | ||
[2016-02-03 15:25:52] app.INFO: Converted ezxmltext field #745 to richtext {"original":"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<section xmlns:image=\"http://ez.no/namespaces/ezpublish3/image/\" xmlns:xhtml=\"http://ez.no/namespaces/ezpublish3/xhtml/\" xmlns:custom=\"http://ez.no/namespaces/ezpublish3/custom/\"/>\n","converted":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<section xmlns=\"http://docbook.org/ns/docbook\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:ezxhtml=\"http://ez.no/xmlns/ezpublish/docbook/xhtml\" xmlns:ezcustom=\"http://ez.no/xmlns/ezpublish/docbook/custom\" version=\"5.0-variant ezpublish-1.0\"/>\n"} | ||
``` | ||
|
||
It contains, in a JSON structure, the `original` (ezxmltext) value, and the `converted` (ezrichtext) value that has been | ||
written to the database. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,274 @@ | ||
<?php | ||
/** | ||
* @license For full copyright and license information view LICENSE file distributed with this source code. | ||
*/ | ||
namespace EzSystems\EzPlatformXmlTextFieldTypeBundle\Command; | ||
|
||
use DOMDocument; | ||
use DOMXPath; | ||
use eZ\Publish\Core\FieldType\RichText\Converter; | ||
use eZ\Publish\Core\Persistence\Database\DatabaseHandler; | ||
use PDO; | ||
use Psr\Log\LoggerInterface; | ||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use eZ\Publish\Core\FieldType\RichText\Converter\Aggregate; | ||
use eZ\Publish\Core\FieldType\XmlText\Converter\Expanding; | ||
use eZ\Publish\Core\FieldType\RichText\Converter\Ezxml\ToRichTextPreNormalize; | ||
use eZ\Publish\Core\FieldType\XmlText\Converter\EmbedLinking; | ||
use eZ\Publish\Core\FieldType\RichText\Converter\Xslt; | ||
use eZ\Publish\Core\FieldType\RichText\Validator; | ||
use eZ\Publish\Core\FieldType\XmlText\Value; | ||
|
||
class ConvertXmlTextToRichTextCommand extends ContainerAwareCommand | ||
{ | ||
/** | ||
* @var \eZ\Publish\Core\Persistence\Database\DatabaseHandler | ||
*/ | ||
private $db; | ||
|
||
/** | ||
* @var \eZ\Publish\Core\FieldType\RichText\Converter | ||
*/ | ||
private $converter; | ||
|
||
/** | ||
* @var \eZ\Publish\Core\FieldType\RichText\Validator | ||
*/ | ||
private $validator; | ||
|
||
/** | ||
* @var \Psr\Log\LoggerInterface | ||
*/ | ||
private $logger; | ||
|
||
public function __construct(DatabaseHandler $db, LoggerInterface $logger = null) | ||
{ | ||
parent::__construct(); | ||
|
||
$this->db = $db; | ||
$this->logger = $logger; | ||
|
||
$this->converter = new Aggregate( | ||
array( | ||
new ToRichTextPreNormalize(new Expanding(), new EmbedLinking()), | ||
new Xslt( | ||
'./vendor/ezsystems/ezpublish-kernel/eZ/Publish/Core/FieldType/RichText/Resources/stylesheets/ezxml/docbook/docbook.xsl', | ||
array( | ||
array( | ||
'path' => './vendor/ezsystems/ezpublish-kernel/eZ/Publish/Core/FieldType/RichText/Resources/stylesheets/ezxml/docbook/core.xsl', | ||
'priority' => 99, | ||
), | ||
) | ||
), | ||
) | ||
); | ||
|
||
$this->validator = new Validator( | ||
array( | ||
'./vendor/ezsystems/ezpublish-kernel/eZ/Publish/Core/FieldType/RichText/Resources/schemas/docbook/ezpublish.rng', | ||
'./vendor/ezsystems/ezpublish-kernel/eZ/Publish/Core/FieldType/RichText/Resources/schemas/docbook/docbook.iso.sch.xsl', | ||
) | ||
); | ||
} | ||
|
||
protected function configure() | ||
{ | ||
$this | ||
->setName('ezxmltext:convert-to-richtext') | ||
->setDescription( <<< EOT | ||
Converts XmlText fields from eZ Publish Platform to RichText fields. | ||
== WARNING == | ||
This is a non-finalized work in progress. ALWAYS make sure you have a restorable backup of your database before using it. | ||
EOT | ||
); | ||
} | ||
|
||
protected function execute(InputInterface $input, OutputInterface $output) | ||
{ | ||
$this->convertFieldDefinitions($output); | ||
$this->convertFields($output); | ||
} | ||
|
||
function convertFieldDefinitions(OutputInterface $output) | ||
{ | ||
$query = $this->db->createSelectQuery(); | ||
$query->select($query->expr->count('*')); | ||
$query->from('ezcontentclass_attribute'); | ||
$query->where( | ||
$query->expr->eq( | ||
$this->db->quoteIdentifier('data_type_string'), | ||
$query->bindValue('ezxmltext', null, PDO::PARAM_STR) | ||
) | ||
); | ||
|
||
$statement = $query->prepare(); | ||
$statement->execute(); | ||
$count = $statement->fetchColumn(); | ||
|
||
$output->writeln("Found $count field definiton to convert."); | ||
|
||
$query = $this->db->createSelectQuery(); | ||
$query->select('*'); | ||
$query->from('ezcontentclass_attribute'); | ||
$query->where( | ||
$query->expr->eq( | ||
$this->db->quoteIdentifier('data_type_string'), | ||
$query->bindValue('ezxmltext', null, PDO::PARAM_STR) | ||
) | ||
); | ||
|
||
$statement = $query->prepare(); | ||
$statement->execute(); | ||
|
||
$updateQuery = $this->db->createUpdateQuery(); | ||
$updateQuery->update($this->db->quoteIdentifier('ezcontentclass_attribute')); | ||
$updateQuery->set( | ||
$this->db->quoteIdentifier('data_type_string'), | ||
$updateQuery->bindValue('ezrichtext', null, PDO::PARAM_STR) | ||
); | ||
// was tagPreset in ezxmltext, unused in RichText | ||
$updateQuery->set( | ||
$this->db->quoteIdentifier('data_text2'), | ||
$updateQuery->bindValue(null, null, PDO::PARAM_STR) | ||
); | ||
$updateQuery->where( | ||
$updateQuery->expr->eq( | ||
$this->db->quoteIdentifier('data_type_string'), | ||
$updateQuery->bindValue('ezxmltext', null, PDO::PARAM_STR) | ||
) | ||
); | ||
|
||
$updateQuery->prepare()->execute(); | ||
|
||
$output->writeln("Converted $count ezxmltext field definitions to ezrichtext"); | ||
} | ||
|
||
function convertFields(OutputInterface $output) | ||
{ | ||
$query = $this->db->createSelectQuery(); | ||
$query->select($query->expr->count('*')); | ||
$query->from('ezcontentobject_attribute'); | ||
$query->where( | ||
$query->expr->eq( | ||
$this->db->quoteIdentifier('data_type_string'), | ||
$query->bindValue('ezxmltext', null, PDO::PARAM_STR) | ||
) | ||
); | ||
|
||
$statement = $query->prepare(); | ||
$statement->execute(); | ||
$count = $statement->fetchColumn(); | ||
|
||
$output->writeln("Found $count field rows to convert."); | ||
|
||
$query = $this->db->createSelectQuery(); | ||
$query->select('*'); | ||
$query->from('ezcontentobject_attribute'); | ||
$query->where( | ||
$query->expr->eq( | ||
$this->db->quoteIdentifier('data_type_string'), | ||
$query->bindValue('ezxmltext', null, PDO::PARAM_STR) | ||
) | ||
); | ||
|
||
$statement = $query->prepare(); | ||
$statement->execute(); | ||
|
||
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { | ||
if (empty($row['data_text'])) { | ||
$inputValue = Value::EMPTY_VALUE; | ||
} else { | ||
$inputValue = $row['data_text']; | ||
} | ||
|
||
$converted = $this->convert($inputValue); | ||
|
||
$updateQuery = $this->db->createUpdateQuery(); | ||
$updateQuery->update($this->db->quoteIdentifier('ezcontentobject_attribute')); | ||
$updateQuery->set( | ||
$this->db->quoteIdentifier('data_type_string'), | ||
$updateQuery->bindValue('ezrichtext', null, PDO::PARAM_STR) | ||
); | ||
$updateQuery->set( | ||
$this->db->quoteIdentifier('data_text'), | ||
$updateQuery->bindValue($converted, null, PDO::PARAM_STR) | ||
); | ||
$updateQuery->where( | ||
$updateQuery->expr->lAnd( | ||
$updateQuery->expr->eq( | ||
$this->db->quoteIdentifier('id'), | ||
$updateQuery->bindValue($row['id'], null, PDO::PARAM_INT) | ||
), | ||
$updateQuery->expr->eq( | ||
$this->db->quoteIdentifier('version'), | ||
$updateQuery->bindValue($row['version'], null, PDO::PARAM_INT) | ||
) | ||
) | ||
); | ||
$updateQuery->prepare()->execute(); | ||
|
||
$this->logger->info( | ||
"Converted ezxmltext field #{$row['id']} to richtext", | ||
[ | ||
'original' => $inputValue, | ||
'converted' => $converted | ||
] | ||
); | ||
} | ||
|
||
|
||
$output->writeln("Converted $count ezxmltext fields to richtext"); | ||
} | ||
|
||
function createDocument($xmlString) | ||
{ | ||
$document = new DOMDocument(); | ||
|
||
$document->preserveWhiteSpace = false; | ||
$document->formatOutput = false; | ||
|
||
$document->loadXml($xmlString); | ||
|
||
return $document; | ||
} | ||
|
||
function removeComments(DOMDocument $document) | ||
{ | ||
$xpath = new DOMXpath($document); | ||
$nodes = $xpath->query('//comment()'); | ||
|
||
for ($i = 0; $i < $nodes->length; ++$i) { | ||
$nodes->item($i)->parentNode->removeChild($nodes->item($i)); | ||
} | ||
} | ||
|
||
function convert($xmlString) | ||
{ | ||
$inputDocument = $this->createDocument($xmlString); | ||
|
||
$this->removeComments($inputDocument); | ||
|
||
$convertedDocument = $this->converter->convert($inputDocument); | ||
|
||
// Needed by some disabled output escaping (eg. legacy ezxml paragraph <line/> elements) | ||
$convertedDocumentNormalized = new DOMDocument(); | ||
$convertedDocumentNormalized->loadXML($convertedDocument->saveXML()); | ||
|
||
$errors = $this->validator->validate($convertedDocument); | ||
|
||
$result = $convertedDocumentNormalized->saveXML(); | ||
|
||
if (!empty($errors)) { | ||
$this->logger->error( | ||
"Validation errors when converting xmlstring", | ||
['result' => $result, 'errors' => $errors, 'xmlString' => $xmlString] | ||
); | ||
} | ||
|
||
return $result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters