Поток сообщений друзей

Собствено, хочу узнать у народа, как бы вы стали реализовывать схему а-ля твиттер с потоком сообщений людей, которых вы читаете? Сейчас использую вот такую схему:

Таблицы:

users

messages (fk - user_id)

followers (fk - leader_id, follower_id)

Вроде бы проблем тут нет (разве что логично не иметь PK в таблице followers, но AR не позволяет пока этого). Вопрос встал в другом - как получить и вывести сообщения пользователей, на которых я подписан?

Сейчас делаю так:




// get timeline

	public function getFriends($limit=20, $offset=0)

	{

		// new criteria

		$criteria=new CDbCriteria();

		

		// setup

		$criteria->condition='follower_id = :uid';

		$criteria->select='user.messages.*';

		$criteria->params=array(':uid'=>Yii::app()->user->id);

		$criteria->limit=$limit;

		$criteria->offset=$offset;

		$criteria->together=true;

		$criteria->with=array('user.messages');

		$criteria->order='messages.created_at DESC';

		

		$results=array();

		

		// return results

		$models = Followers::model()->findAll($criteria);

		foreach($models as $model) {

			foreach($model->user->messages as $message) {

				$results[$message->id]=$message;

			}

		}

		ksort($results, SORT_NUMERIC);

		return array_reverse($results);

	}



Вроде как работает, но подозреваю не лучшую производительность у такого подхода. Что посоветуете?

Не иметь PK в таблице само по себе не логично, что будет означать возможность наличия одинаковых строк.

Меня только один вопрос заинтересовал пока: почему выбор сообщений происходит через класс Followers, а не Messages?

Дак я поэтому и обращаюсь, потому что чувствую что есть более элегантный способ забрать сообщения, но который день не могу придумать.

А не иметь ПК вполне допустимо вроде для соединяющих таблиц. Хотя не всегда.

Вобщем, подскажите, как лучше запросить сообщения?

Можно добавить в код модели User такой метод:




public function getFriendMessages($limit=20, $offset=0)

{

    $criteria = new CDbCriteria;

    $criteria->join = 'INNER JOIN `followers` ON `t`.`user_id` = `followers`.`leader_id`';

    $criteria->compare('follower_id', $this->user_id);

    $crtieria->order = 'created_at DESC'; // почему-то тут не работает, но можно добавить в defaultScope класса Message

    $criteria->offset = $offset;

    $criteria->limit = $limit;

    return Message::model()->with('user')->findAll($criteria);

}



Затем в контроллере, получив юзера, можно воспользоваться данным методом для получения списка сообщений (вместе с авторами):




$user = User::model()->findByPk(1);

$messages = $user->getFriendMessages();

echo $messages[2]->message;

echo $messages[2]->user->name;



Можно конечно прибегнуть и к грубому методу:




$messages = Message::model()->with('user.followers')->findAll('follower_id = '.$user_id);



где связь followers - много-много для User, но тут соединений будет на одно больше.

В общем, тестировать вам и почаще смотрите на генерируемые SQL запросы :)

Спасибо, попробую!