Skip to content

Commit

Permalink
[doc] translatable doc updates, also some misc changes
Browse files Browse the repository at this point in the history
  • Loading branch information
l3pp4rd committed Apr 16, 2011
1 parent f4eb305 commit 06e3b84
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 25 deletions.
6 changes: 6 additions & 0 deletions README.markdown
Expand Up @@ -25,6 +25,12 @@ use these extensions from separate branch **doctrine2.0.x** or simply checkout t

### Latest updates

**2011-04-16**

- Translation **query walker** is a killer feature for translatable extension. It lets to
translate any query components and filter or order by translated fields. I recommmend you
to use it extensively since it is very performative also.

**2011-04-11**

- **Tree nestedset** was improved, now all in memory nodes are synchronized and do not require `$em->clear()` all the time.
Expand Down
31 changes: 31 additions & 0 deletions bin/clear_temp.php
@@ -0,0 +1,31 @@
<?php

$location = __DIR__ . '/../tests/temp';
define('VENDOR_PATH', realpath(__DIR__ . '/../vendor'));

set_include_path(implode(PATH_SEPARATOR, array(
VENDOR_PATH,
get_include_path(),
)));

$classLoaderFile = VENDOR_PATH . '/doctrine-common/lib/Doctrine/Common/ClassLoader.php';
if (!file_exists($classLoaderFile)) {
die('cannot find vendor, git submodule init && git submodule update');
}

require_once $classLoaderFile;
$classLoader = new Doctrine\Common\ClassLoader('Symfony');
$classLoader->register();

$finder = new Symfony\Component\Finder\Finder;
$finder->files()
->name('*')
->in(__DIR__ . '/../tests/temp');

foreach ($finder as $fileInfo) {
if (!$fileInfo->isWritable()) {
continue;
}
echo 'removing: ' . $fileInfo->getRealPath() . PHP_EOL;
@unlink($fileInfo->getRealPath());
}
48 changes: 48 additions & 0 deletions bin/purify.php
@@ -0,0 +1,48 @@
<?php

define('VENDOR_PATH', realpath(__DIR__ . '/../vendor'));

set_include_path(implode(PATH_SEPARATOR, array(
VENDOR_PATH,
get_include_path(),
)));

$classLoaderFile = VENDOR_PATH . '/doctrine-common/lib/Doctrine/Common/ClassLoader.php';
if (!file_exists($classLoaderFile)) {
die('cannot find vendor, git submodule init && git submodule update');
}

require_once $classLoaderFile;
$classLoader = new Doctrine\Common\ClassLoader('Symfony');
$classLoader->register();

$finder = new Symfony\Component\Finder\Finder;
$finder->files()
->name('*.php')
->in(__DIR__ . '/../lib')
->in(__DIR__ . '/../tests');

foreach ($finder as $fileInfo) {
if (!$fileInfo->isReadable()) {
continue;
}
$count = 0;
$total = 0;
$needsSave = false;
$content = file_get_contents($fileInfo->getRealPath());

$content = str_replace("\t", ' ', $content, $count);
$total += $count;

$content = str_replace("\r\n", "\n", $content, $count);
$total += $count;

$needsSave = $total != 0;

if ($needsSave) {
file_put_contents($fileInfo->getRealPath(), $content);
echo $fileInfo->getRealPath() . PHP_EOL;
}
}

echo 'done';
24 changes: 0 additions & 24 deletions bin/update_vendors.sh

This file was deleted.

61 changes: 60 additions & 1 deletion doc/translatable.md
Expand Up @@ -10,11 +10,19 @@ Features:
- Automatic storage of translations in database
- ORM and ODM support using same listener -Automatic translation of Entity or
Document fields then loaded
- ORM query can use **hint** to translate all records without issuing additional queries
- Can be nested with other behaviors
- Annotation and Yaml mapping support for extensions

[blog_test]: http://gediminasm.org/test "Test extensions on this blog"

Update **2011-04-16**
- Made an ORM query **hint** to hook into any select type query, which will join the translations
and let you **filter, order or search** by translated fields directly. It also will translate
all selected **collections or simple components** without issuing additional queries. It also
supports translation fallbacks
- For performance reasons, translation fallbacks are disabled by default

Update **2011-04-04**
- Made single listener, one instance can be used for any object manager
and any number of them
Expand All @@ -25,7 +33,7 @@ and any number of them
- Public [Translatable repository](http://github.com/l3pp4rd/DoctrineExtensions "Translatable extension on Github") is available on github
- Using other extensions on the same Entity fields may result in unexpected way
- May inpact your application performace since it does an additional query for translation
- Last update date: **2011-04-04**
- Last update date: **2011-04-16**

**Portability:**

Expand All @@ -42,6 +50,7 @@ Content:
- Document [example](#document)
- [Yaml](#yaml) mapping example
- Basic usage [examples](#basic-examples)
- Using ORM query [hint](#orm-query-hint)
- Advanced usage [examples](#advanced-examples)

## Setup and autoloading {#including-extension}
Expand Down Expand Up @@ -328,6 +337,56 @@ Lets try to load it and it should be translated in English
echo $article->getContent();
// prints: "my content in en"

## Using ORM query hint {#orm-query-hint}

By default, behind the scenes, when you load a record - translatable hooks into **postLoad**
event and issues additional query to translate all fields. Imagine that when you load a collection,
when it issues a lot of queries just to translate those fields. Also if you want to hydrate
result as an **array**, it is not possible to hook any **postLoad** event since it is not an
entity being hydrated. These are the main reason why **TranslationWalker** was born.

**TranslationWalker** uses a query **hint** to hook into any **select type query**,
and when you execute the query, no matter which hydration method you use, it automatically
joins the translations for all fields, so you could use ordering filtering or whatever you
want on **translations of the fields** instead of original record fields.

And in result there is only one query for all this happyness.

If you use translation [fallbacks](#advanced-examples) it will be also in the same single
query and during the hydration process it will replace the empty fields in case if they
do not have a translation in currently used locale.

Now enough talking, here is an example:

$dql = "SELECT a, c, u FROM Article a "
. "LEFT JOIN a.comments c "
. "JOIN c.author u "
. "WHERE a.title LIKE '%translated_title%' "
. "ORDER BY a.title";

$query = $em->createQuery($dql);
// set the translation query hint
$query->setHint(
\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
);

$articles = $query->getResult(); // object hydration
$articles = $query->getArrayResult(); // array hydration

Theres no need for any words anymore.. right?
I recommend you to use it extensively since it is a way better performance, even in
cases where you need a single object query.

Notice: Even in **COUNT** select statements translations are joined to leave a
possibility to filter by translated field, if you do not need it, just do not set
the **hint**. Also take into account that it is not possibble to translate components
in **JOIN WITH** statement, example `JOIN a.comments c WITH c.message LIKE '%will_not_be_translated%'`

Notice: any **find** related method calls cannot hook this hint automagically, we
will use a different approach when **persister overriding feature** will be
available in **Doctrine**

## Advanced examples: {#advanced-examples}

### Default locale
Expand Down

0 comments on commit 06e3b84

Please sign in to comment.