7

I have just installed the doctrine extensions to use Sluggable.

I make this :

composer.json

"stof/doctrine-extensions-bundle": "1.2.*@dev"

AppKernel.php

new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),

app/config/config.yml

stof_doctrine_extensions:
    orm:
        default:
            sluggable: true

Djoo\AppliBundle\Entity\Nomenclature.php

namespace Djoo\AppliBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\DBAL\Types\SmallIntType;
use Gedmo\Mapping\Annotation as Gedmo;

/**
 * Nomenclature
 *
 * 
 * @ORM\Table(name="app_nomenclature")
 * @ORM\Entity
 */
class Nomenclature
{
    .....
    /**
     * @var string
     *
     * @ORM\Column(name="titre", type="string", length=200, nullable=false)
     */
    private $titre;

    /**
     * @var string
     *
     * @ORM\Column(name="finess", type="string", length=10, nullable=true)
     */
    private $finess;

    /**
     * @Gedmo\Slug(fields={"titre","finess"},suffix=".html")
     * @ORM\Column(length=128, unique=true,nullable=true)
     */
    private $slug;

    public function getSlug() {
        return $this->slug;
    }

    public function setSlug($slug){
        $this->slug = $slug;
        return $this;
    }

}

In my controller i make this to generate slug for old values in my datatable :

$filterBuilder = $this->get('doctrine.orm.entity_manager')>getRepository('DjooAppliBundle:Nomenclature')->createQueryBuilder('e')->orderBy('e.titre', 'asc');
$query = $filterBuilder->getQuery();
$nomenclatures = $query->getResult();

foreach($nomenclatures as $nomenclaturee){
    $nomenclature->setSlug(null);
    $this->get('doctrine.orm.entity_manager')->persist($nomenclature);
    $this->get('doctrine.orm.entity_manager')->flush();
 }

I have no error, but my old values are a null slug. I try to create a new element and i have a good slug. Have you and idea ?

Thanks

Johann
  • 127
  • 1
  • 4
  • 7

4 Answers4

7

To change the slug you must change the related property. You can add a space at the end of $titre, save it, change it back and save it again. That will flush the slugs.

lsouza
  • 2,448
  • 4
  • 26
  • 39
  • 1
    Yeaaaa, thank you $entity = $em->getRepository($entityName)->find($id); $titre = $entity->getTitre(); $entity -> setSlug(null); $entity -> setTitre($titre." "); $em -> flush(); – Johann Oct 17 '14 at 14:27
  • It did not work for me. I had to re-generate the slug manually according to http://stackoverflow.com/a/18672588/1179841 – Sithu Feb 02 '17 at 15:46
4
$uow = $em->getUnitOfWork();    
$uow->propertyChanged($entity, 'slug', NULL, NULL);    
$uow->scheduleForUpdate($entity);    
$em->flush();
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • This works for me and I wonder why did it have -1 ????. I just added +1. Also keep in mind that you may want to typehint `ObjectManager` to `EntityManager` so that you can get code completion for `getUnitOfWork()` : `/** @var ObjectManager|EntityManager $em */` – Dimitry K Mar 30 '17 at 16:52
3

Why it didn't work for OP, but worked for others (eg. @gregor):

When creating slug, your first instinct is to create slug property with this column configuration:

 ..    

 @ORM\Column(unique=true, nullable=false)
 private $slug;
 ..

When running app/console doctrine:schema:update and this will result in 2 sql statements:

ALTER TABLE ... ADD slug ... NOT NULL
CREATE UNIQUE INDEX...`. 

By default column slug will be filled with value '' (empty string) which would make 2nd statement to fail with (Duplicate entry '') error. Now you have two choices:

Choice A: Ignore failure of the 2nd statement

If you ignore the error, and later try generating slugs manually using the documented method $entity->setSlug(null) everything would work. It would work because by using $entity->setSlug(null) you would let Doctrine know that propertyslug was changed (from '' to null) and this in turn would trigger internally $uow->propertyChanged() and $uow->scheduleForUpdate() (Thanks to @Sebastian Radu for his example). The Sluggable extension will notice this change as well and will regenerate the slug. Now as all the slugs are unique, next time you run app/console doc:schema:update it will succeed in creating index on slug and your schema will be fully in sync.

Choice B: Modify slug field to be nullable After noticing error your instinct would be to mark slug field as nullable, so that index creation succeeds:

 ..    

 @ORM\Column(unique=true, nullable=true)
 private $slug;
 ..

This would result in slug column having NULL as it's default value. Now as you try using documented $entity->setSlug(null) approach it won't work (just as OP has posted). This happens because when $entity->slug property is already NULL. Thus when you use $entity->setSlug(null) no changes are detected by Doctrine, and thus Sluggable regeneration behaviour is never triggered. In order to trigger the changes there were two answers:

  • hack with adding space to the slug source properties $entity -> setTitre($titre." "); (but this would result in extra space you would have to trim after)

  • approach by @Sebastian Radu, where he shows how to tell Doctrine directly that the field was changed (I personally prefer this one and wonder why it was unfairly downvoted)

Hope this helps you understand a bit better the inner workings of Doctrine and extensions.

Community
  • 1
  • 1
Dimitry K
  • 2,236
  • 1
  • 28
  • 37
2

The sluggable documentation states the following:

In case if you want the slug to regenerate itself based on sluggable fields, set the slug to null.

<?php
$entity = $em->find('Entity\Something', $id);
$entity->setSlug(null);

$em->persist($entity);
$em->flush();

It does work for me.

gregor
  • 558
  • 4
  • 11
  • doesn't work for me. Field annotations are like this `@ORM\Column(name="slug", unique=true, nullable=true)` `@Gedmo\Slug(fields={"name","city"}, updatable=true)` – Dimitry K Mar 30 '17 at 16:54