views:

756

answers:

2

I have a database design case which I am curios whether Doctrine ORM supports it out-of-box.


Product:
  columns:
    id: {type: integer, primary: true, autoincrement: true }
    type_id: { type: integer, notnull: true }
    brand_id: { type: integer, notnull: true }
  relations:
    ProductType:
      class: ProductType
      local: type_id
      foreign: id
    Brand:
      class: Brand
      local: brand_id
      foreign: id

ProductType:
  actAs:
    I18n:
    fields: { name }
  columns:
    id: {type: integer, primary: true, autoincrement: true }
    name: { type: string(255), notnull: true }

Brand:
  actAs:
    I18n:
      fields: { name }
  columns:
    id: {type: integer, primary: true, autoincrement: true }
    name: { type: string(255), notnull: true }


I want to slugify Products table, ie. products will be reached via their slugs. However, as you see both brand and productype tables has i18n behaviour. And moreover, product doesnt have a name. A product's slug will be: "Brand.name - ProductType.name", and vary with the language served.

For this scenario, is there anyway I can use Sluggable behaviour of Doctrine to sluggify my products automatically. Or do I have to manage it manually?

By the way my environment configuration is:
Doctrine Version: 1.2
Symfony: 1.4.1

Thanks

A: 

My understanding is that you need to have the slug in both Product Type and Brand models. You can leave the Product definition as it is. Anyway, I'm assuming from your question that there is only one product for every brand+type (even if it doesn't have to much sense). So ProductType and Brand will be defined like this:

schema.yml
----------

ProductType:
  actAs:
    I18n:
    fields: { name }
    actAs:
      Sluggable: { fields: [name], uniqueBy: [lang], canUpdate: true }
  columns:
    ...

Then you have to configure your Product route to use the slugs. And after that you will need to configure the action to check what you are getting from the route.

For example, this could be your route for Products:

routing.yml
-----------

product:
  url:   /:sf_culture/product/:brand_slug/:type_slug
  param: { module: product, action: view }
  requirements:
    sf_culture: (?:en|fr)
    sf_method:  get

Then in the action you will call to your own findOneBySlugs($brand_slug, $type_slug) method:

product/actions/actions.class.php
---------------------------------

public function executeView(sfWebRequest $request)
{
  $product = Doctrine::getTable('Product')
    ->findOneBySlugs(
                     $request->getParameter('brand_slug'),
                     $request->getParameter('type_slug')
                    );

  $this->forward404Unless($product);
}
illarra
Thanks illara, it seems to cover my requirement!
Lashae
+1  A: 

the problem with that solution are the queries. With:

$product = Doctrine::getTable('Product')
->findOneBySlugs(
                 $request->getParameter('brand_slug'),
                 $request->getParameter('type_slug')
                );

you are doing a 5-join query if I'm not mistaken. You can improve to do only three (product, brand_translation and producttype_translation)

I'm in a similar situation, and the best option is to create a slug for each product using the brand or product type name in this case. So you would only need:

$product = Doctrine::getTable('Product')
  ->findOneBySlug($request->getParameter('slug'));

I'm thinking between two options:

Product:
  actAs:
    Sluggable:
      unique: true
      fields: [title]
      builder: [Slug, slugify] 

or using the getUniqueSlug() function on the record class. I think the first option is best so you don't have to worry about uniqueness.

fesja