1. В Active Record объектный экземпляр привязан к единственной строке в таблице. Как можно тогда объяснить такие методы, которые присутствуют почти в каждой реализации AR, ведь они не соответствуют записи в бд?
Агрегатные функции
Book::find('all', array('select' => 'avg(price) as avg_price, avg(tax) as avg_tax'));
sql => SELECT avg(price) as avg_price, avg(tax) as avg_tax FROM books LIMIT 5,10
Группировка
Book::all(array('group' => 'price')); sql => SELECT * FROM books GROUP BY price
Группировка + having
Book::all(array('group' => 'price', 'having' => 'price > 45.00'));
sql => SELECT * FROM books GROUP BY price HAVING price > 45.00
Или же вообще нативный запрос в контроллере
$book = Book::find_by_sql('select title from books');
2. Как можно реализовать связь многие-ко-многим в самом простом случае? Например хочу получить у статьи все теги.
$article->tags;
Если связь один-ко-многим, то это понятно. Примерно это будет работать так:
$article->author;
Мы вызываем Author::findOne(['author_id' => $author_id]); // Где author_id значение в классе модели Article
А вы заметили, что описанные вами запросы вызываются через статический метод, а не через объект?
Статические методы AR это что-то вроде построителя запросов.
Что касается многие ко многим:
$article->articleAuthor->authors - последовательный неявный вызов getArticleAuthor у модели Article, и getAuthors у модели ArticleAuthor
Фигурирует три модели: Article, ArticleAuthor, Author, где ArticleAuthor - модель промежуточной таблицы и работает всего с двумя основными полями: article_id, author_id.
danildanil, говоря про AR, это нормально. Сам по себе AR не очень нормальный. Это антипаттерн, он слишком много на себя берёт. Поэтому используя AR, вы выбираете удобство разработки, но никак не производительность.
danildanil, если в момент выборки присоединили необходимые таблицы черех JOIN - данные подтянутся автоматически, нет - будет выполнен дополнительный запрос для каждой записи.