views:

24

answers:

1

Let's consider the following simple schema (in Doctrine, but Propel users are welcome too):

User:
  columns:
    name: string
Article:
  columns:
    user_id: integer
    content: string
  relations:
    User:
      local: user_id
      foreign: id

Now, if you create a route for Article model and generate a module via doctrine:generate-module-for-route frontend @article_route you get a CRUD application that manages all the articles. But in frontend you would normally want to manage objects related to signed-in User, so you have to manually get the id of the User, pass id to the model and write a bunch of methods that would retrieve objects related to this User, for example:

  public function executeIndex(sfWebRequest $request)
  {
    $this->articles = Doctrine::getTable('Articles')
      ->getUserArticles(this->getUser());
  }
  public function executeShow(sfWebRequest $request)
  {
    $this->article = $this->getRoute()->getObject();

    if (!$this->article->belongsToUser($this->getUser()))
    {
      $this->redirect404();  
    }
  }  

and model:

class ArticleTable extends Doctrine_Table
{
    public function getUserArticles(sfUser $user)
    {
      $q = $this->createQuery('a')
        ->where('a.user_id = ?', $user->getId());

      return $q->execute();
    }   
}

class Article extends BaseArticle
{
  public function belongsToUser(sfUser $user)
  {
    return $this->getUserId() == $user->getId();
  }
}

This is trivial stuff and yet you have to manually write this code for each new relation. Am I missing some kind of way to take advantage of Doctrine relations? Anyways, how would you do it? Thank you.

A: 

I believe you should be able to do this with a custom routing class. I have never done this, but there is a tutorial in the More with Symfony book: Advanced Routing. My guess is that it should look something like this:

class objectWithUserRoute extends sfDoctrineRoute
{
  public function matchesUrl($url, $context = array())
  {
    if (false === $parameters = parent::matchesUrl($url, $context))
    {
      return false;
    }

    $parameters['user_id'] = sfContext::getInstance()->getUser()->getId();

    return array_merge(array('user_id' => sfContext::getInstance()->getUser()->getId()), $parameters);
  }

  protected function getRealVariables()
  {
    return array_merge(array('user_id'), parent::getRealVariables());
  }

  protected function doConvertObjectToArray($object)
  {
    $parameters = parent::doConvertObjectToArray($object);

    unset($parameters['user_id']);

    return $parameters;
  }
}

You would then need to set the routing class in routing.yml to use objectWithUserRoute. I haven't tested this, but I think it is the best way to go about solving the problem.

lonesomeday
sfContext::getInstance()->getUser() returns null, probably because user gets instantiated after routing. Should I change the order of factory loading? And how?
Dziamid
Hmm, so it does -- I don't know why my previous test succeeded. Looks like you can't use this technique `:-(`
lonesomeday