Wallogit.com
2017 © Pedro Peláez
With this bundle you will be able to automatic generate unique slugs inside your entities by simply add a @Slug annotation to a specified field., (*1)
This bundles current release requires Symfony 4. You can use Version 1.2 from this Bundle to use it with Symfony >= 2.7, (*2)
(*) 8 at default conifguration or otherwise as much as the 'fbeen_unique_slug.maximum_digits' parameter (see below at "Full configuration example"), (*3)
$ composer require fbeen/uniqueslugbundle
Suppose that you have a Newsitem entity to display some news on your website and that you want to generate slugs from the $title property., (*4)
$ bin/console make:slug Newsitem title
You might then have an entity like this:, (*5)
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Fbeen\UniqueSlugBundle\Annotation\Slug;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity(repositoryClass="App\Repository\NewsitemRepository")
*/
class Newsitem
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=64)
*/
private $title;
/**
* @ORM\Column(type="text")
*/
private $body;
/**
* @ORM\Column(type="datetime")
*/
private $created;
/**
* @Slug("title")
* @ORM\Column(type="string", length=255, unique=true)
*/
private $slug;
public function __construct()
{
$this->created = new \DateTime();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getBody(): ?string
{
return $this->body;
}
public function setBody(string $body): self
{
$this->body = $body;
return $this;
}
public function getCreated(): ?\DateTimeInterface
{
return $this->created;
}
public function setCreated(\DateTimeInterface $created): self
{
$this->created = $created;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
}
Important notes when you edit your entity manually:, (*6)
use Fbeen\UniqueSlugBundle\Annotation\Slug;
@Slug("title") annotation to the slug property to tell the application it should create a slug from the $title propertyApply the changes to the database:, (*7)
$ bin/console make:migration
$ bin/console doctrine:migrations:migrate
From now on if you persist your entity the slug will be automatically generated. To use the slugs into the routes you could simply use the $slug property into the route e.g., (*8)
@Route("/{slug}", name="newsitem_show")
And then you have to retrieve the right newsitem using the given slug. Fortunately thanks to Symfony's automatic parameter conversion this is as easy as this:, (*9)
/**
* @Route("/{slug}", name="newsitem_show", methods={"GET"})
*/
public function show(Newsitem $newsitem): Response
{
return $this->render('newsitem/show.html.twig', [
'newsitem' => $newsitem,
]);
}
Don't forget to pass the slug property to the router when you generate a route to your show action:, (*10)
<a href="{{ path('newsitem_show', {'slug': newsitem.slug}) }}">show</a>
The slug annotation has some more futures:, (*11)
1) To generate slugs from more than one property just write an array of properties: @Slug({"created", "title"}), (*12)
2) To add your own format for date, time and datetime fields use the format parameter: @Slug({"created", "title"}, format="Y-m-d")., (*13)
3) You could also write your own method that builds the slug and apply the method name to the @Slug annotation., (*14)
/**
* @Slug("generateSlug")
* @ORM\Column(type="string", length=255, unique=true)
*/
private $slug;
public function generateSlug()
{
return $this->created->format('Y-m-d') . ' ' . $this->title;
}
Using the Symfony console commands you are able to generate the slugs for all the records:, (*15)
$ php bin/console make:slug Newsitem --regenerate
Fbeen\UniqueSlugBundle\Slugifier\SlugifierInterface e.g.<?php
// App\Service\MyCustomSlugifier.php
namespace App\Service;
use Fbeen\UniqueSlugBundle\Slugifier\SlugifierInterface;
/**
* My custom slugifier
*/
class MyCustomSlugifier implements SlugifierInterface
{
public function slugify($text) : string
{
// replace non letter or digits by -
$text = preg_replace('~[^\\pL\d]+~u', '-', $text);
// trim
$text = trim($text, '-');
// transliterate latin characters
$text = \transliterator_transliterate('Any-Latin; Latin-ASCII; [\u0100-\u7fff] remove', $text);
// lowercase
$text = strtolower($text);
// remove unwanted characters
$text = preg_replace('~[^-\w]+~', '', $text);
if (empty($text))
{
return 'n-a';
}
return $text;
}
}
services:
# Only necessary if autowiring is off
App\Service\MyCustomSlugifier: ~
# config/packages/fbeen_unique_slug.yaml
fbeen_unique_slug:
slugifier_class: App\Service\MyCustomSlugifier
Ready! From now on the slugs will be generated with your own slugifier class., (*16)
# config/packages/fbeen_unique_slug.yaml
fbeen_unique_slug:
slugifier_class: 'fbeen_unique_slug.slugifier'
maximum_digits: 8
minimum_slug_length: 16