Yii Registro relacional com condição de outra tabela

Tenho um registro relacional similar ao seguinte:

  • Existem usuários (usuários de mesa) com IDs
  • Existem categorias (categorias de tabela) com id, name
  • Existem artigos (artigos de tabela) com id, body, category_id
  • Depois, há uma tabela read_articles com article_id, user_id

Então, um usuário pode ver uma lista de todos os artigos em uma categoria. Eles podem clicar em um artigo e ele irá adicionar uma input (user_id, article_id) à tabela read_articles.

Eu quero poder usar o ActiveRecord de Yii para obter todos os artigos de uma determinada categoria que não foram lidos pelo usuário atual e exibi-los. Eu tenho pensado nisso em termos de SQL um pouco, mas não tenho certeza de como ajustá-lo à minha configuração do ActiveRecord. Minha primeira idéia foi um escopo parametrizado no registro ativo do artigo:

public function unread( $userId ) { $this->getDbCriteria()->mergeWith( array( 'alias' => 'articles', 'condition' => 'not exists (SELECT * ' . 'FROM user_read_articles ' . 'WHERE articles.id=user_read_articles.article_id ' . 'AND read_articles.user_id=' . (int)$userId . ')', ) ); } 

Parece estar funcionando, mas parece-me muito sujo.

Existe uma maneira mais limpa de fazer o que estou falando no ActiveRecord? Ou devo talvez considerar mudar para SQL mais simples e lidar com coisas como esta eu mesmo (mas perder muito recurso agradável de AR)?

Editar Aqui estão as relações para os modelos acima mencionados: (Isenção de responsabilidade, estas são truncadas para apenas partes relevantes)

UserActiveRecord

 public function relations() { return array( 'categories' => array( self::HAS_MANY, 'UserCategoryActiveRecord', 'user_id' ), // I added this early using gii, never really used it... 'readArticles' => array( self::HAS_MANY, 'UserReadArticleActiveRecord', 'user_id' ), ); } 

UserCategoryActiveRecord

 public function relations() { return array( 'user' => array( self::BELONGS_TO, 'UserActiveRecord', 'user_id' ), 'articles' => array( self::HAS_MANY, 'ArticleActiveRecord', 'category_id', 'order' => 'articles.pub_date DESC' ), ); } 

ArticleActiveRecord

 public function relations() { return array( 'category' => array( self::BELONGS_TO, 'CategoryActiveRecord', 'category_id' ), ); } 

Eu também fiz um “UserReadArticleActiveRecord” cedo, enquanto eu estava construindo isso, mas eu nunca usei esse modelo e está praticamente vazio.

Com toda a honestidade, pensei em mudar para Symfony2 e Doctrine de qualquer forma e simplesmente abandonar o registro ativo. Eu sei que não resolve esse problema, mas eu posso simplesmente deixar isso e manter minha solução atual por enquanto.

Para obter os artigos de leitura , você pode definir um relacionamento MANY_MANY no seu modelo de usuário, conforme descrito aqui:

http://www.yiiframework.com/doc/guide/1.1/pt/database.arr

Eu não acho que você precisará do modelo de proxy UserReadArticles, você só precisa definir o relacionamento corretamente.

Para obter artigos não lidos , também estou tendo problemas para pensar sobre a maneira Yii de fazê-lo, mas uma maneira mais eficiente do que usar uma consulta de sub-seleção é fazer uma JOINTA ESQUERDA para user_read_articles e verificar se uma coluna de user_read_articles IS NULL ( não houve uma linha correspondente) algo como isto:

 $this->getDbCriteria()->mergeWith( array( 'alias' => 'articles', 'join' => 'LEFT JOIN user_read_articles ON articles.id=user_read_articles.article_id', 'condition' => 'user_read_articles.article_id IS NULL', ) );