Skip to content

Commit

Permalink
Merge pull request #7 from ezsystems/convert_to_richtext
Browse files Browse the repository at this point in the history
EZP-25358: ezxmltext:convert-to-richtext command prototype
  • Loading branch information
bdunogier committed Feb 4, 2016
2 parents acdf47b + 79033c1 commit 978b9b3
Show file tree
Hide file tree
Showing 3 changed files with 312 additions and 0 deletions.
30 changes: 30 additions & 0 deletions README.md
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.
274 changes: 274 additions & 0 deletions bundle/Command/ConvertXmlTextToRichTextCommand.php
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;
}
}
8 changes: 8 additions & 0 deletions bundle/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@ services:
class: %ezpublish_rest.field_type_processor.ezxmltext.class%
tags:
- { name: ezpublish_rest.field_type_processor, alias: ezxmltext }

ezxmltext.command.convert_to_richtexst:
class: EzSystems\EzPlatformXmlTextFieldTypeBundle\Command\ConvertXmlTextToRichTextCommand
arguments:
- "@ezpublish.api.storage_engine.legacy.dbhandler"
- "@?logger"
tags:
- { name: console.command }

0 comments on commit 978b9b3

Please sign in to comment.