Severin
Severin

Reputation: 46

Update laravel 5 models with slug

I created a row in my ‘beers’ table called ‘slug’ where i want to store the slug of the name of my beers.the problem is i already have over 1000 beers and I don’t want to manually enter the slug to each one of them so i am trying to make a script to automatically update all the slugs. But i failed to do that:

This is my code to give for every new beer a slug

/**
   * Set the title attribute and automatically the slug
   *
   * @param string $value
   */
  public function setNameAttribute($value)
  {
      $this->attributes['name'] = $value;

      if (! $this->exists) {
          $this->setUniqueSlug($value, '');
      }
  }

/**
   * Recursive routine to set a unique slug
   *
   * @param string $title
   * @param mixed $extra
   */
  protected function setUniqueSlug($name, $extra)
  {
      $slug = str_slug($name.'-'.$extra);

      if (static::whereSlug($slug)->exists()) {
          $this->setUniqueSlug($name, $extra + 1);
          return;
      }

      $this->attributes['slug'] = $slug;
  }

The code works fine, but how can I change all the existing beers in the database with a unique slug. Thanks for your help.

Upvotes: 0

Views: 1822

Answers (2)

redcenter
redcenter

Reputation: 846

BTW you probably mean you created a COLUMN named 'slug' in the beer table, instead of a ROW.

I would:

Change database definition

If you are using migrations on your app.. maybe an idea:

make the slug column unique tru a migration. So your database will start making comments in the future when you try to add a slug which isn't unique. So your are future-proof on this.

Changing current data

And for changing the current data. If it's a one time only operation, why not use Tinker?

$php artisan tinker;

In tinker, you select all models (or a subset) & run that method on every one. Something like:

$beers = Beer::all();
foreach ($beers as $beer) {
   //do your thingy
   $beer->save()
}

BUT: make sure the code you type is tested on your local and don't use all() on production (but do it in smaller portions)... :-)

Upvotes: 2

Andrea Alhena
Andrea Alhena

Reputation: 1046

In this case the best practice is, in my opinion, to work with a command line interface task that handles the generation of each name in a proper slug. Making Commands in Laravel is a piece of cake: check the docs here (creating commands)

In the handle method, get a collection of all the records (possibly in chunks of 100/200 as described here (chunking results). Setting the name to the current value ($model->name = $model->name) should do the trick as should trigger the setter method in your model that's designated to generate the slug accordingly to the given name. Obviously, before setting the value just check if the slug field is empty or not.

Upvotes: 1

Related Questions