Skip to content
This repository has been archived by the owner on Sep 16, 2021. It is now read-only.

Enable the ContentObject provider to work with translated referrers #63

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions AutoRoute/PathProvider/ContentObjectProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
use Doctrine\ODM\PHPCR\DocumentManager;
use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Util\ClassUtils;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRoute;

/**
* Provides path elements by determining them from
Expand Down Expand Up @@ -65,15 +67,28 @@ public function providePath(RouteStack $routeStack)

$object = $contentObject->$method();

$routeFilter = function ($referrer) use ($object) {
if ($referrer instanceof Route && $referrer->getContent() === $object) {
return true;
if (!$object) {
throw new \RuntimeException(sprintf(
'The %s:%s method has returned an empty value "%s"',
Copy link
Member

Choose a reason for hiding this comment

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

missing full stop

get_class($contentObject),
$method,
var_export($object, true)
));
}

$routeFilter = function ($referrer) use ($object, $context) {
if ($referrer instanceof AutoRoute && $referrer->getContent() === $object) {
Copy link
Member Author

Choose a reason for hiding this comment

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

We now require an instance of AutoRoute as I believe that to do what we want here we need the Route object to store a locale attribute. Note that the AutoRoute object itself is not translatable, we just need to know what locale the route is in.

Copy link
Member

Choose a reason for hiding this comment

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

you could try to rely on the LocaleListener for having locales in auto routes, no?

Copy link
Member Author

Choose a reason for hiding this comment

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

If we did that would it mean that the URl

/category-1/fr/this-is-an-article

would not work? Not a common use case, but I don't see any reason for saying its not a valid one (?)

Copy link
Member Author

Choose a reason for hiding this comment

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

Also, the /{_locale}/ does not have to be in the generated URL

Copy link
Member

Choose a reason for hiding this comment

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

hm, yes, the locale would have to be the first part. i guess it makes sense to not rely on the listener then. and users are not expected to edit AutoRoute by hand, so its different (on normal routes, without the listener you could move your route in the tree and it would be at /de but the stored locale be "fr"...)

about the pattern: there are two multilang scenarios, one where you have just one route per content and have the pattern, the other with multiple translated routes that are each for only one locale. but i guess with autoroute, supporting the pattern approach with a single route makes no sense at all (its mostly useful for pages that are routes at the same time, like simple cms, and there you need no auto routes)


// filter the referrering routes by locale
if ($referrer->getLocale() == $context->getLocale()) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Note that this does not support fallback yet, it should do before this PR is done.

return true;
}
}

return false;
};

$referringRoutes = new ArrayCollection;
$referringRoutes = new ArrayCollection();

if ($this->documentIsPersisted($object)) {
// check to see existing routes
Expand All @@ -91,7 +106,7 @@ public function providePath(RouteStack $routeStack)

if (count($routes) > 1) {
throw new \RuntimeException(
'Multiple referring routes (i.e. translations) not supported yet.'
'Found more than one referring auto route, this should not happen.'
Copy link
Member

Choose a reason for hiding this comment

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

should this not go into a logfile, at a high level? an exception could break a running website, which is probably too much.

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 think it depends on if this would ever happen, and under what circumstances it would happen. It shouldn't happen I think, so I would prefer to bail rather than risk the website acting in unexpected ways.

Copy link
Member

Choose a reason for hiding this comment

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

okay

);
}

Expand Down
20 changes: 1 addition & 19 deletions AutoRoute/RouteMaker/AutoRouteMaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public function make(RouteStack $routeStack)
}

$autoRoute->setName($routeStack->getPath());
$autoRoute->setLocale($context->getLocale());
$autoRoute->setParent($context->getTopRoute());

$routeStack->addRoute($autoRoute);
Expand Down Expand Up @@ -75,25 +76,6 @@ protected function getAutoRouteForDocument($document)

$metadata = $dm->getClassMetadata(get_class($document));

$locale = null; // $uow->getLocale($document, $locale);

// If the document is translated, filter locales
if (null !== $locale) {
throw new \Exception(
'Translations not yet supported for Auto Routes - '.
'Should be easy.'
);

// array_filter($referrers, function ($referrer) use ($dm, $uow, $locale) {
// $metadata = $dm->getClassMetadata($refferer);
// if ($locale == $uow->getLocaleFor($referrer, $referrer)) {
// return true;
// }

// return false;
// });
}

if ($referrers->count() > 1) {
throw new \RuntimeException(sprintf(
'More than one auto route for document "%s"',
Expand Down
12 changes: 12 additions & 0 deletions Model/AutoRoute.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,16 @@
*/
class AutoRoute extends Route
{
protected $locale;

public function getLocale()
{
return $this->locale;
}

public function setLocale($locale)
{
$this->locale = $locale;
}
Copy link
Member

Choose a reason for hiding this comment

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

note taht normal routes store the locale in a route _default, and there is the LocaleListener that adjusts that according to the path. i am in the process of finding a way to make routes locale capable even if there is just one, porting simplcms things to RoutingBundle - see symfony-cmf/routing-bundle#210

i am a bit afraid that these things collide with the other model, or we end up in too many different ways to do the same thing.

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 LocaleListener is redundant in this case isn't it?

Copy link
Member

Choose a reason for hiding this comment

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

that listener is meant to ensure that routes always have the right locale according to their repository path. as said above, i follow your reasoning.

there is one point left: why not store _locale in the defaults, rather than have this separate field? that way, symfony would see the locale 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.

Yeah I guess that would make sense. Is there ever an edge risk that the LocaleListener will overwrite that value if for some reason somebody had a german route which for some reason started with an fr prefix : /fr/dies-ist-ein-deutcsh-url?

Copy link
Member

Choose a reason for hiding this comment

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

if the route is at a tree root that the listener looks at, and starts
with something that looks like one of the supported locale prefixes but
its in a different language then yes, that could happen. i think its
really an edge case.

do you think people should mix their own routes with an autoroute tree?
if not, we just need to make sure that you can have the locale listener
use a different list of roots than the dynamic router.

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 think the users shouldn't, but there is no way to stop them doing this, unless we have a system to segrate routes into zones (e.g. all children of /pages are managed by RoutingAuto). But this would be an unnecessary restriction imo.

Maybe the LocaleListener should ultimately look for a specific interface and normal and AutoRoutes extend a common class (which ommits this interface)?

Copy link
Member

Choose a reason for hiding this comment

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

or we could make the listener only change a locale on a move event, and in all other cases leave the route untouched if it already has a locale (even if its not the expected one). wdyt? if you agree, can you open an issue on the RoutingBundle?

can we remove the whole explict locale thing from here and use the defaults for the locale?


}
5 changes: 4 additions & 1 deletion Resources/config/doctrine-model/AutoRoute.phpcr.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/phpcr/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<document name="Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRoute"/>
<document name="Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRoute">
<field name="locale" type="string" nullable="true"/>
</document>


</doctrine-mapping>
113 changes: 113 additions & 0 deletions Tests/Functional/EventListener/AutoRouteListenerMultilangTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

Copy link
Member

Choose a reason for hiding this comment

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

missing license header

namespace Functional\EventListener;
Copy link
Member

Choose a reason for hiding this comment

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

should be Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Functional\EventListener


use Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Article;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Functional\BaseTestCase;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Category;

class AutoRouteListenerMultilangTest extends BaseTestCase
{
public function provideMultilangCategory()
{
return array(
array(
array(
'en' => 'Hello everybody!',
'fr' => 'Bonjour le monde!',
'de' => 'Gutentag',
'es' => 'Hola todo el mundo',
),
array(
'test/auto-route/articles/en/hello-everybody',
'test/auto-route/articles/fr/bonjour-le-monde',
'test/auto-route/articles/de/gutentag',
'test/auto-route/articles/es/hola-todo-el-mundo',
),
),
);
}

/**
* @dataProvider provideMultilangArticle
*/
public function testMultilangCategory($data, $expectedPaths)
{
$category = new Category();
$category->path = '/test/category1';
$this->getDm()->persist($category);

foreach (array(
'de' => 'Meine neue Kategorie',
'fr' => 'Ma nouvelle catégorie',
'en' => 'My new category',
) as $locale => $title) {
$category->title = $title;
$this->getDm()->bindTranslation($category, $locale);
}
}

public function provideMultilangArticle()
{
return array(
array(
array(
'en' => 'Hello everybody!',
'fr' => 'Bonjour le monde!',
'de' => 'Gutentag',
'es' => 'Hola todo el mundo',
),
array(
'test/auto-route/articles/en/category/hello-everybody',
'test/auto-route/articles/fr/category/bonjour-le-monde',
'test/auto-route/articles/de/category/gutentag',
'test/auto-route/articles/es/category/hola-todo-el-mundo',
),
),
);
}

/**
* @dataProvider provideMultilangArticle
*/
public function testMultilangArticle($data, $expectedPaths)
{
$category = new Category();
$category->path = '/test/category1';
$category->title = 'category';
$this->getDm()->persist($category);
foreach (array_keys($data) as $lang) {
$this->getDm()->bindTranslation($category, $lang);
}

$article = new Article;
$article->path = '/test/article-1';
$article->categories[] = $category;

$this->getDm()->persist($article);

foreach ($data as $lang => $title) {
$article->title = $title;
$this->getDm()->bindTranslation($article, $lang);
}

$this->getDm()->flush();
$this->getDm()->clear();

$articleTitles = array_values($data);
foreach ($expectedPaths as $i => $expectedPath) {
$route = $this->getDm()->find(null, $expectedPath);

$this->assertNotNull($route, 'Found route with path ' . $expectedPath);
$this->assertInstanceOf('Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRoute', $route);

$content = $route->getContent();

$this->assertNotNull($content);
$this->assertInstanceOf('Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Article', $content);

// We havn't loaded the translation for the document, so it is always in the default language
$this->assertEquals('Hello everybody!', $content->title);
}
}
}
55 changes: 0 additions & 55 deletions Tests/Functional/EventListener/AutoRouteListenerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Functional\BaseTestCase;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Blog;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Post;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Article;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRoute;
use Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\ConcreteContent;

Expand Down Expand Up @@ -182,60 +181,6 @@ public function testUpdatePost()
);
}

public function provideMultilangArticle()
{
return array(
array(
array(
'en' => 'Hello everybody!',
'fr' => 'Bonjour le monde!',
'de' => 'Gutentag',
'es' => 'Hola todo el mundo',
),
array(
'test/auto-route/articles/en/hello-everybody',
'test/auto-route/articles/fr/bonjour-le-monde',
'test/auto-route/articles/de/gutentag',
'test/auto-route/articles/es/hola-todo-el-mundo',
),
),
);
}

/**
* @dataProvider provideMultilangArticle
*/
public function testMultilangArticle($data, $expectedPaths)
{
$article = new Article;
$article->path = '/test/article-1';
$this->getDm()->persist($article);

foreach ($data as $lang => $title) {
$article->title = $title;
$this->getDm()->bindTranslation($article, $lang);
}

$this->getDm()->flush();
$this->getDm()->clear();

$articleTitles = array_values($data);
foreach ($expectedPaths as $i => $expectedPath) {
$route = $this->getDm()->find(null, $expectedPath);

$this->assertNotNull($route);
$this->assertInstanceOf('Symfony\Cmf\Bundle\RoutingAutoBundle\Model\AutoRoute', $route);

$content = $route->getContent();

$this->assertNotNull($content);
$this->assertInstanceOf('Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Article', $content);

// We havn't loaded the translation for the document, so it is always in the default language
$this->assertEquals('Hello everybody!', $content->title);
}
}

/**
* Ensure that we can map parent classes: #56
*/
Expand Down
15 changes: 15 additions & 0 deletions Tests/Resources/Document/Article.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document;

use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCR;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ODM\PHPCR\PersistentCollection;

/**
* @PHPCR\Document(translator="child", referenceable=true)
Expand All @@ -36,11 +38,24 @@ class Article
*/
public $title;

/**
* @PHPCR\Referrers(
* referringDocument="Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Category",
* referencedBy="articles"
* )
*/
public $categories = array();

/**
* @PHPCR\Locale()
*/
public $locale;

public function getCategory()
{
return current($this->categories);
}

public function getTitle()
{
return $this->title;
Expand Down
54 changes: 54 additions & 0 deletions Tests/Resources/Document/Category.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/*
* This file is part of the Symfony CMF package.
*
* (c) 2011-2013 Symfony CMF
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document;

use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCR;
use Doctrine\Common\Collections\ArrayCollection;

/**
* @PHPCR\Document(translator="child", referenceable=true)
*/
class Category
{
/**
* @PHPCR\Id()
*/
public $path;

/**
* @PHPCR\Referrers(
* referringDocument="Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route",
* referencedBy="content"
* )
*/
public $routes;

/**
* @PHPCR\String(translated=true)
*/
public $title;

/**
* @PHPCR\Locale()
*/
public $locale;

/**
* @PHPCR\ReferenceMany(targetDocument="Symfony\Cmf\Bundle\RoutingAutoBundle\Tests\Resources\Document\Article")
*/
public $articles = array();

public function getTitle()
{
return $this->title;
}
}
Loading