PHP code example of janwebdev / translatable-entity-bundle
1. Go to this page and download the library: Download janwebdev/translatable-entity-bundle library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
janwebdev / translatable-entity-bundle example snippets
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Janwebdev\TranslatableEntityBundle\Model\TranslatableWrapper;
#[ORM\Entity]
#[ORM\Table(name: 'article')]
class Article extends TranslatableWrapper
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
/**
* @var Collection<int, ArticleTranslation>
*/
#[ORM\OneToMany(
targetEntity: ArticleTranslation::class,
mappedBy: 'translatable',
cascade: ['persist', 'remove'],
orphanRemoval: true
)]
private Collection $translations;
public function __construct()
{
$this->translations = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* @return Collection<int, ArticleTranslation>
*/
public function getTranslations(): Collection
{
return $this->translations;
}
public function addTranslation(ArticleTranslation $translation): self
{
if (!$this->translations->contains($translation)) {
$this->translations->add($translation);
$translation->setTranslatable($this);
}
return $this;
}
public function removeTranslation(ArticleTranslation $translation): self
{
if ($this->translations->removeElement($translation)) {
if ($translation->getTranslatable() === $this) {
$translation->setTranslatable(null);
}
}
return $this;
}
}
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Janwebdev\TranslatableEntityBundle\Model\TranslatingInterface;
#[ORM\Entity]
#[ORM\Table(name: 'article_translation')]
#[ORM\UniqueConstraint(name: 'article_locale_unique', columns: ['article_id', 'locale'])]
class ArticleTranslation implements TranslatingInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 10)]
private string $locale;
#[ORM\ManyToOne(targetEntity: Article::class, inversedBy: 'translations')]
#[ORM\JoinColumn(name: 'article_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
private ?Article $translatable = null;
#[ORM\Column(type: 'string', length: 255)]
private string $title;
#[ORM\Column(type: 'text', nullable: true)]
private ?string $content = null;
public function getId(): ?int
{
return $this->id;
}
public function setLocale(string $locale): void
{
$this->locale = $locale;
}
public function getLocale(): string
{
return $this->locale;
}
public function setTranslatable(Article $translatable): void
{
$this->translatable = $translatable;
}
public function getTranslatable(): ?Article
{
return $this->translatable;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(?string $content): self
{
$this->content = $content;
return $this;
}
}
namespace App\Controller;
use App\Entity\Article;
use App\Repository\ArticleRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class ArticleController extends AbstractController
{
#[Route('/article/{id}', name: 'article_show')]
public function show(Article $article): Response
{
// The bundle automatically sets the locale from the request
// Access translated properties through magic methods
$title = $article->title; // or $article->getTitle()
$content = $article->content; // or $article->getContent()
return $this->render('article/show.html.twig', [
'article' => $article,
'title' => $title,
'content' => $content,
]);
}
}
namespace App\Repository;
use App\Entity\Article;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
class ArticleRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Article::class);
}
/**
* Get all articles with translations joined
*/
public function findAllWithTranslations(): array
{
return $this->createQueryBuilderWithTranslations()
->getQuery()
->getResult();
}
/**
* Find one article by ID with translations
*/
public function findOneWithTranslations(int $id): ?Article
{
return $this->createQueryBuilderWithTranslations()
->andWhere('a.id = :id')
->setParameter('id', $id)
->getQuery()
->getOneOrNullResult();
}
/**
* Create query builder with translations joined
*/
private function createQueryBuilderWithTranslations(): QueryBuilder
{
return $this->createQueryBuilder('a')
->leftJoin('a.translations', 'at')
->addSelect('at');
}
}
namespace App\Form;
use App\Entity\ArticleTranslation;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ArticleTranslationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('locale', HiddenType::class)
->add('title', TextType::class, [
'label' => 'Title',
'
namespace App\Form;
use App\Entity\Article;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ArticleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('translations', CollectionType::class, [
'entry_type' => ArticleTranslationType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => 'Translations',
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Article::class,
]);
}
}
namespace App\Entity;
use Janwebdev\TranslatableEntityBundle\Model\TranslatableWrapper;
class Article extends TranslatableWrapper
{
// ... your code ...
/**
* Return true to use the first available translation as fallback
* when translation for current locale is not found
*/
protected function acceptFirstTranslationAsDefault(): bool
{
return true; // Default: false
}
/**
* Return false to NOT use default locale translation as fallback
*/
protected function acceptDefaultLocaleTranslationAsDefault(): bool
{
return true; // Default: true
}
/**
* Handle the case when no translation is found
* Override to provide custom behavior (e.g., return empty translation)
*/
protected function handleTranslationNotFound(): never
{
// Create an empty translation instead of throwing exception
$class = ArticleTranslation::class;
$this->translation = new $class();
$this->translation->setLocale($this->locale->getLocale());
return $this->translation;
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.