Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EZP-28718: Embedded images should be handled as images instead of plain embed object after migrating from XmlText to RichText #39

Merged
merged 2 commits into from Jun 4, 2018

Conversation

vidarl
Copy link
Member

@vidarl vidarl commented Apr 27, 2018

This one fixes
EZP-28718 : Embedded images should be handled as images instead of plain embed object after migrating from XmlText to RichText
EZP-28767 : Create a script to fix embedded images broken after migrating from XmlText to RichText

Running bin/console ezxmltext:convert-to-richtext will ensure embedded images are tagged correctly in the resulting ezrichtext.

Running bin/console ezxmltext:convert-to-richtext --fix-embedded-images-only will only fix the embedded images on an already converted DB.

Optionally, use --image-content-types=image,thumbnail,foobar to specify which classes should considered as image classes.

Related doc pr :
ibexa/documentation-developer#268

protected function loginAsAdmin()
{
$userService = $this->getContainer()->get('ezpublish.api.service.user');
$permissionResolver = $this->getContainer()->get('date_based_publisher.permission_resolver');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

date_based_publisher?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. cut&paste error.. Fixed

'image-content-types',
null,
InputOption::VALUE_OPTIONAL,
'Comma separated list of content types which are considered as images when converting embedded tags. Default value is 27'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be better if we use identifiers, type id's have a tendency to have different values depending on install more often then identifiers.

However the command can translate it to id using dbal, so service can stay on using type id.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. fixed

@vidarl vidarl changed the title EZP-28767: Embedded images should be handled as images instead of plain embed object after migrating from XmlText to RichText EZP-28718: Embedded images should be handled as images instead of plain embed object after migrating from XmlText to RichText Apr 27, 2018
'identifier',
$literalIdentifiers
)
);
Copy link
Contributor

@andrerom andrerom Apr 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aha.. thanx.. Cause my solution was indeed insanely cumbersome


$statement = $query->execute();
$result = array();
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
Copy link
Contributor

@andrerom andrerom Apr 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaik you can use return $statement->fetchAll(PDO::FETCH_COLUMN); to get what you want directly here.

}

$query->select('id')
->from($this->dbal->quoteIdentifier('ezcontentclass'))
Copy link
Contributor

@andrerom andrerom Apr 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding this, I was about to say you don't need to quote constants with DBAL, but seeing it is done in https://github.com/ezsystems/ezpublish-kernel/blob/d1143080d2325cadc6ccc1e3aee55b29aecebae4/eZ/Publish/Core/FieldType/BinaryBase/BinaryBaseStorage/Gateway/DoctrineStorage.php#L269 I'm a bit unsure.

@alongosz Did you check that when writing it? Or was it just left over from style of zeta based older db code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right Andre, those constants does not need to be quoted it seems

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, if identifier is the same as some SQL keyword then it still needs to be quoted, I think. But AFAIR in our system it was more of the case with column names, not tables.

On the other hand... quoting only chosen ones is bad for my Aspergers, so I tried to Quote Them All ;)

But it's up to you, for sure it would be more readable w/o quoting :)

Copy link
Contributor

@andrerom andrerom Apr 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@andrerom andrerom Apr 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So proposal on tables and columns: We can write like this so we never need to be in doubt, and basically never need to quote:

    $query->select('c.id')
    ->from('ezcontentclass', 'c')

Avoids the need to do $this->dbal->quoteIdentifier('id') which is done further down here, also makes it explicit which table we act on all over. Again, optimizing for reading, cause that is what we do most of the time ;)

@vidarl vidarl force-pushed the embed_image branch 2 times, most recently from 66ab403 to 1c22fbd Compare April 30, 2018 09:18
@vidarl
Copy link
Member Author

vidarl commented Apr 30, 2018

Fixed all review comments I believe...

@vidarl
Copy link
Member Author

vidarl commented Apr 30, 2018

Added more bugfixes:

  • added support for <embed node_id=...> (previously, only <embed object_id=...> was supported
  • Gracefully handling if provided node_id or object_id do not exists

*/
private $currentContentFieldId;

public function __construct(LoggerInterface $logger = null, $apiRepository = null, $imageContentTypes = array())
Copy link
Contributor

@andrerom andrerom Apr 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apiRepository should be first as it's not really optional.

imageContentTypes should be either optional setter injection, or required constructor argument. Rather then both at the same time.

nitpick for new/changed code: array() => []

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

try {
$location = $locationService->loadLocation($id);
} catch (NotFoundException $e) {
$this->logger->warning("Unable to find node_id=$id, referred to in embedded tag in contentobject_attribute.id=$this->currentContentFieldId.");

This comment was marked as resolved.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

$nodes = $xpath->query('//doc:ezembed');
foreach ($nodes as $node) {
//href is in format : ezcontent://123 or ezlocation://123
$href=$node->attributes->getNamedItem('href')->nodeValue;
Copy link
Contributor

@andrerom andrerom Apr 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space between ' = '

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

//href is in format : ezcontent://123 or ezlocation://123
$href=$node->attributes->getNamedItem('href')->nodeValue;
$isContentId = strpos($href, 'ezcontent') === 0;
$id = (int) substr($href, strrpos($href, '/')+1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should setup cs checking on travis here, but it won't run on this PR right now as it's against dbal branch :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah.. CS and running unit tests would be good. Who can setup that? I guess it should be adressed in a separate PR though ....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unit tests will be running as soon as you now change target branch to master and rebase for master and push. Its not running here since dbal target branch is not setup as branch to run tests for, maybe we should not restrict branch to run on somehow for pr's on pr's.

See other repos where @alongosz has added cs testing on travis for inspiration on that, like: ezsystems/ezplatform-http-cache@aa1f551

} else {
if (($classAttribute !== null) && ($node->attributes->getNamedItem('class')->nodeValue === 'ez-embed-type-image')) {
$node->removeAttribute('ezxhtml:class');
//$node->setAttribute('ezxhtml:class', 'ez-embed-type-image');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be removed?

As for line above, also the class logic here forget it can be several classes like in html. Or? (OE probably did not allow it, but I1'm thinking maybe the underlying xmltext allowed it if edited raw).
At least assume it can be several when comparing richtext nodes, as it adds ez-embed-type-image to whatever was there from before.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm.. I added this because I thought this would be a nice feature.. but I should probably check if class is indeed ez-embed-type-image, and only remove that one (not everything) if it exists... ok then ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comment line should be removed, indeed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes and yes :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@vidarl vidarl changed the base branch from dbal to master May 3, 2018 08:23
@vidarl
Copy link
Member Author

vidarl commented May 3, 2018

Fixed according to all review comments, and rebased

$xpath = new DOMXPath($richtextDocument);
$ns = $richtextDocument->documentElement->namespaceURI;
$xpath->registerNamespace('doc', $ns);
$nodes = $xpath->query('//doc:ezembed');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to deal with ezembed-inline too....

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

':version'
)
)
->setParameters(array(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

if ($logger === null) {
$this->logger = new NullLogger();
} else {
$this->logger = $logger;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also be:

$this->logger = $logger instanceof LoggerInterface ? $logger : new NullLogger(); 

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

*/
private $converter;

public function __construct(Connection $dbal, RichTextConverter $converter, LoggerInterface $logger = null)
{
parent::__construct();

$this->dbal = $dbal;
$this->logger = $logger;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we need NullLogger here to form the looks of the new code bellow.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll instead remove default value from constructor, forcing a logger to be set in DI config
ok?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is ok, but maybe double check with @adamwojs if there are still cases logger might not be set, as we tend to some places still allow it to be null for some reason. But that might just be baggage from earlier symfony versions, or attempt to have it as optional dependency.

{
$this->currentContentFieldId = $contentFieldId;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could remove this as class property and rather inject it, to avoid global state set by method which is not a setter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, passing on $contentFieldId down the call stack

*/
public function providerForTestTagEmbeddedImages()
{
$map = array();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


$inputDocument = $this->createDocument($inputFilePath);
$richText = new RichText($apiRepositoryStub);
$richText->setImageContentTypes(array(27));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not it seems :)

@vidarl
Copy link
Member Author

vidarl commented May 30, 2018

review ping. PR should now be in compliance with all review comments

@alongosz
Copy link
Member

Hmm, a month ago when I commented on building queries I didn't look at what happens here at all (slammed with work, sorry).
Are you sure this is the right approach? AFAICS update queries are not going to be seen until we clear persistence cache.
It should rather be handled by proper persistence handler. Moreover if something changes in the db we might forget that we have this command in a package. So I'm rather in favor of SPI approach. If there's no corresponding API->SPI methods, it's fine to add them to SPI\Persistence and inject here persistence handler directly.

But maybe I missed something? TL;DR
😅

@andrerom
Copy link
Contributor

andrerom commented May 31, 2018

@alongosz Not sure what you are talking about here, this is migration scenario, it's something people run before booting the system normally, during upgrade. And if they don't, they need to clear all cache anyway.

So while it would be great if we had generic migrations features supported somehow cleanly via SPI (Storage Engine and FieldTypes at least), it's far far beyond the scope here and more for you and engineering team to think about for future versions (this is for existing, real world versions ;)).

@vidarl
Copy link
Member Author

vidarl commented May 31, 2018

In general, there could be benefits with using persistence handler in upgrade scripts. But there are pitfalls too. Often, upgrade scripts fix an invalid DB state ( schema change for instance ). So, having API calls that are able to deal with such things would be nice to have, but not sure it is worth the effort.

my 2 cents...

Copy link
Member

@alongosz alongosz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, if this is intended as a migration script and user knows about clearing Symfony cache after all the operations, I have no further objections.

My point however was also for building queries outside of API or SPI. Then we need to provide BC for database schema (which we do), which leads to showstoppers when it comes to evolving application.
If we had:

  • database migration on upgrade (doctrine schema files WiP)
  • everything encapsulated in at least SPI implementation
    then we wouldn't need to worry about changing database at all.

Right now even if we achieve automatic database update on upgrades, then we still have some commands that operate on raw database.

But that's a little bit out of scope here. For now, with full context, which I didn't have before - +1

Some nitpicks:

<ezvalue key="limit">5</ezvalue>
</ezconfig>
</ezembed>
</section>

This comment was marked as resolved.

<ezvalue key="limit">5</ezvalue>
</ezconfig>
</ezembed>
</section>

This comment was marked as resolved.

<ezvalue key="limit">5</ezvalue>
</ezconfig>
</ezembed>
</section>

This comment was marked as resolved.

<ezvalue key="limit">5</ezvalue>
</ezconfig>
</ezembed>
</section>

This comment was marked as resolved.

<ezvalue key="limit">5</ezvalue>
</ezconfig>
</ezembed>
</section>

This comment was marked as resolved.

This comment was marked as resolved.

Copy link
Contributor

@andrerom andrerom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides small nitpic on array syntax +1

I'll merge as is

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants