Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Observer_Slug, creating unique slugs with a befor_insert() observer
  • Hello, For one of my projects I've developed this Observer_Slug. I wish someone find it useful! tilman explained fantastically what does this observer.
    A slug is a term usually describing a uri-friendly version of a property of a data object.
    In this case, the name field. What this observer does is, it takes whatever you have in your name field and creates a unique slug, to be used in uris and saves it in the slug field. e.g.:
    Name: "Your mum's a slug"
    Slug: "your-mums-a-slug"
    If "your-mums-a-slug" exists, it will be "your-mums-a-slug-1"

    APP/classes/observer/slug.php
    <?php
    /**
     * Slug observer gives you the hability of auto add
     * unique slugs based on the passed properties.
     * 
     * @author      Isern Palaus ipalaus@ipalaus.es
     * @license     MIT License
     * @copyright   2011 Isern Palaus
     * @link        [url=http://ipalaus.es]http://ipalaus.es[/url]
     */
     
    class Observer_Slug extends \Orm\Observer
    {
        public static $property = 'slug';
        public static $from     = 'name';
    
        public function before_insert($obj)
        {
            $obj->{static::$property} = self::unique_slug($obj->{static::$from}, $obj::table());
        }
        
        public static function unique_slug($name, $table)
        {
            $slug = \Inflector::friendly_title($name);
            
            $titles = array();
            
            $query = \DB::query("SELECT slug FROM $table WHERE slug RLIKE '(".$slug.")(-[0-9]+)?$'")->execute();
            
            if(count($query) > 0)
            {
                foreach($query->as_array() as $item)
                {
                    $titles[] = $item["slug"];
                }
            }
            
            $total  = count($titles);
            $last   = end($titles);
            
            /**
            * No equal results, return $slug
            */
            if($total == 0)
                return $slug;
                        
            /**
            * If we have only one result, we look if it has a number at the end
            */
            elseif($total == 1)
            {
                /**
                * Take the only value of the array, because there is only 1
                */
                $exists = $titles[0];
                
                /**
                * Kill the slug and see what happens
                */
                $exists = str_replace($slug, "", $exists);
                
                /**
                * If there is no light about, there was no number at the end.
                * We added it now
                */
                if("" == trim($exists))
                    return $slug."-1";
                
                /**
                * If not..........
                */
                else {
                    /**
                    * Obtain the number because of REGEX it will be there... ;-)
                    */
                    $number = str_replace("-", "", $exists);
                    
                    /**
                    * Number plus one.
                    */
                    $number++;
                    
                    return $slug."-".$number;                
                }
            }
            
            /**
            * If there is more than one result, we need the last one
            */
            else {
                /**
                * Last value
                */
                $exists = $last;
                
                /**
                * Delete the actual slug and see what happens
                */
                $exists = str_replace($slug, "", $exists); 
                
                /**
                * Obtain the number, easy.
                */
                $number = str_replace("-", "", $exists);
                
                /**
                * Increment number +1
                */
                $number++;
                
                return $slug."-".$number;
            }
        }
    }
    

    How to use it: APP/classes/model/test.php
    <?php
    
    class Model_Test extends \Orm\Model {
        protected static $_observers = array(
            'Slug'                      => array('before_insert'),
            '\Orm\Observer_CreatedAt'   => array('before_insert'),
            '\Orm\Observer_UpdatedAt'   => array('before_save'),
        );
    }
    

    King regards!
    Isern
  • Hi Isern, thanks for sharing your observer! Could you put it on github and ask for a pull-request so others can find your superb code more easy? Maybe you should ask dhorrigan or wanwizard where best to put it?
  • Awesome, I've been looking into creating my own but this will do just fine. Many thanks.
  • How about a couple of english sentences to define "slug" and give a use case.
    At a higher level, what does this do ?
    Maybe describe the possible values for "the passsed properties"... Looks like an example of using observers to grow a table of 'tags' or 'related material' ?
    Maybe 'slug' is a new usage of an old term? Or is it wordpress-specific ...? I'm almost certain I know from the code (thanks for sharing) but would appreciate the english.
    Thanks
  • Can't describe better than tilman did. I quote your description on first post. And yes, Inflector does that! :-) Thank you!
  • Always happy to help ;)
  • A slug is a term usually describing a uri-friendly version of a property of a data object.
    In this case, the name field. What this observer does is, it takes whatever you have in your name field and creates a unique slug, to be used in uris and saves it in the slug field. e.g.:
    Name: "Your mum's a slug"
    Slug: "your-mums-a-slug"
    If "your-mums-a-slug" exists, it will be "your-mums-a-slug-1" (Note: Not sure, the Inflector does that exact transformation, but along the lines of)

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion