Как реализовать?Блог (вывод тегов).

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Закрыто
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Как реализовать?Блог (вывод тегов).

Сообщение MOTORIST »

Задача: Подскажите как реализовать вывод тегов в списке постов и при детальном просмотре
Есть таблица tags с полями id, name.
Есть таблица articles c полем id_tag. В котором хранятся id-ки тегов,через запятую(1,2,3,4....).
Контроллер:

Код: Выделить всё

class ArticlesController extends Controller{
        
    public function actionIndex()
    {    
        
        //Статья
        if(!empty($_GET['id'])){
            
            $criteria=new CDbCriteria(array(
                'condition'=>'status=2',
            ));
            $articles = Articles::model()->with('author','tags')->findByPk($_GET['id']);
            
            if(!empty($articles)){
                $this->render('article', array(
                        'article'=>$articles,
                ));
            }
            else throw new CHttpException(404,'Запрашиваемая страница не существует.');
                
        }
        else if(!empty($_GET['cat'])){
            // критерии выборки из таблицы
            $criteria=new CDbCriteria(array(
                'condition'=>'status='.Articles::STATUS_PUBLISHED,
                'condition'=>'id_cat='.$_GET['cat'],
                'order'=>'t.position',
            ));
            
            // создаем пагинатор
            $pagination = new CPagination(Articles::model()->count($criteria));
            $pagination->pageSize = 3;
            
            // добавляем в критерии выборки LIMIT и OFFSET
            $pagination->applyLimit($criteria);
            
            $articles = Articles::model()->with('author','categories')->findAll($criteria);
            
            if(!empty($articles)){
                $this->render('articles', array(
                    'articles'=>$articles,
                    'pagination'=>$pagination,
                ));
            }
            else throw new CHttpException(404,'Запрашиваемая страница не существует.');
        }
        //Статьи
        else{
            // критерии выборки из таблицы
            $criteria=new CDbCriteria(array(
                'condition'=>'status='.Articles::STATUS_PUBLISHED,
                'order'=>'t.position',
            ));
            
            // создаем пагинатор
            $pagination = new CPagination(Articles::model()->count($criteria));
            $pagination->pageSize = 4;
            
            // добавляем в критерии выборки LIMIT и OFFSET
            $pagination->applyLimit($criteria);
            
            $articles = Articles::model()->with('author')->findAll($criteria);
            
            $this->render('articles', array(
                'articles'=>$articles,
                'pagination'=>$pagination,
            ));
            
        }
        
    }
}
 
Заранее спасибо!
Последний раз редактировалось MOTORIST 2010.06.30, 13:14, всего редактировалось 2 раза.
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как реализовать?

Сообщение pirrat »

ну для начала я бы нормализовал бд, вынеся отношения между статьями и тегами в связующею таблицу.
прописал отношение MANY_MANY в модели Articles
и делал бы вывод тегов в нужном месте:

Код: Выделить всё

foreach($article->getTags() as $tag)
{
echo $tag->getName();
} 
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?

Сообщение MOTORIST »

А можно подробнее про связующую таблицу? Знаний по проектированию БД нет. Как должна выглядеть связующая таблица в данном случае?
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как реализовать?

Сообщение pirrat »

как то так:

Код: Выделить всё

CREATE TABLE `articles_tags` (
  `article_id` int(10) unsigned NOT NULL DEFAULT '0',
  `tag_id` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`article_id`,`tag_id`)
) ENGINE=InnoDB
_______________

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

Articles:

Код: Выделить всё

public function getTags()
{
$criteria = new CDbCriteria;
$criteria->condition = "t.id IN('".$this->id_tag."')";
return Tag::model()->findAll($criteria);
}
 
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?

Сообщение MOTORIST »

Пишет:

Код: Выделить всё

Property "ArticlesController.id_tag" is not defined.
 
Сделал так в контроллере:

Код: Выделить всё

//Получаем теги
            if(!empty($articles->id_tag)){
                $tags = Articles::getTags($articles->id_tag);
            }
            
            
            if(!empty($articles)){
                $this->render('article', array(
                        'article'=>$articles,
                        'comments' => $comments,
                        'tags' => $tags,
                ));
            }
            else throw new CHttpException(404,'Запрашиваемая страница не существует.');
 
В модели:

Код: Выделить всё

public function getTags($name)
    {
        $criteria = new CDbCriteria;
        $criteria->condition = "t.id IN(".$name.")";
        return Tags::model()->findAll($criteria);
    }
 
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Как реализовать?Блог (вывод тегов).

Сообщение slavcodev »

Расширение для работ с тегами не подходит?
taggable
Жду Yii 3!
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?Блог (вывод тегов).

Сообщение MOTORIST »

Чужим не интересно пользоваться, хотелось бы самому написать и без связующей таблицы.
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как реализовать?

Сообщение pirrat »

MOTORIST писал(а):Пишет:

Код: Выделить всё

Property "ArticlesController.id_tag" is not defined.
 
А на фига метод в контроллер пихать?
в модель Articles надо было...
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?Блог (вывод тегов).

Сообщение MOTORIST »

Метод в модели. Использую я его в котроллере. Даже если использовать в представлении, все равно та же ошибка.

Articles::getTags();

Поле id_tag есть в таблице.
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как реализовать?Блог (вывод тегов).

Сообщение pirrat »

Articles::getTags();

метод динамический, а вы его используете как статический.

надо так:

Код: Выделить всё

$article = Articles::model()->findByPk(1);
$article->getTags(); 
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?Блог (вывод тегов).

Сообщение MOTORIST »

Контроллер:

Код: Выделить всё

<?php
class ArticlesController extends Controller{
        
    public function actionIndex()
    {    
        
        //Статья
        if(!empty($_GET['id'])){
            
            //Получаем посты с авторами
            $criteria=new CDbCriteria(array(
                'condition'=>'t.status='.Articles::STATUS_PUBLISHED,
                'condition'=>'t.id='.$_GET['id'],
            ));
            $articles = Articles::model()->with('author')->findByPk($_GET['id'],$criteria);

            //Получаем комменты
            $criteria_comments = new CDbCriteria(array(
                'condition'=>'t.status='.Comment::STATUS_APPROVED,
                'condition'=>'t.post_id='.$_GET['id'],
            ));
            $comments = Comment::model()->findAll($criteria_comments);
            
            
            if(!empty($articles)){
                $this->render('article', array(
                        'article'=>$articles,
                        'comments' => $comments,
                ));
            }
            else throw new CHttpException(404,'Запрашиваемая страница не существует.');
                
        }
        else if(!empty($_GET['cat'])){
            // критерии выборки из таблицы
            $criteria=new CDbCriteria(array(
                'condition'=>'status='.Articles::STATUS_PUBLISHED,
                'condition'=>'id_cat='.$_GET['cat'],
                'order'=>'t.position',
            ));
            
            // создаем пагинатор
            $pagination = new CPagination(Articles::model()->count($criteria));
            $pagination->pageSize = 3;
            
            // добавляем в критерии выборки LIMIT и OFFSET
            $pagination->applyLimit($criteria);
            
            $articles = Articles::model()->with('author','categories')->findAll($criteria);
            
            
            if(!empty($articles)){
                $this->render('articles', array(
                    'articles'=>$articles,
                    'pagination'=>$pagination,
                ));
            }
            else throw new CHttpException(404,'Запрашиваемая страница не существует.');
        }
        //Статьи
        else{
            // критерии выборки из таблицы
            $criteria=new CDbCriteria(array(
                'condition'=>'status='.Articles::STATUS_PUBLISHED,
                'order'=>'t.position',
            ));
            
            // создаем пагинатор
            $pagination = new CPagination(Articles::model()->count($criteria));
            $pagination->pageSize = 4;
            
            // добавляем в критерии выборки LIMIT и OFFSET
            $pagination->applyLimit($criteria);
            
            $articles = Articles::model()->with('author')->findAll($criteria);
            
            
            $this->render('articles', array(
                'articles'=>$articles,
                'pagination'=>$pagination,
            ));
            
        }
        
    }
}
?>
Последний раз редактировалось MOTORIST 2010.07.03, 11:36, всего редактировалось 1 раз.
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как реализовать?Блог (вывод тегов).

Сообщение pirrat »

вижу контроллер - страшный и толстый ещё и с ошибками - надо рефакторить.
больше ни чего не вижу, получение тегов или что то подобное там не вижу совсем.
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?Блог (вывод тегов).

Сообщение MOTORIST »

А можно услышать замечания по контроллеру, если не сложно. =) Как его можно упростить? Три страницы, три условия и сответственно разные запросы в БД с критериями.
Пока вижу одно пагинатор не нужно три раза писать и рендеринг.
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как реализовать?Блог (вывод тегов).

Сообщение pirrat »

Код: Выделить всё

't.id='.$_GET['id'] 
а экранировать (приводить к нужным типам) за вас кто переменные будет или хотите на sql injection нарваться?

Код: Выделить всё

$articles = Articles::model()->with('author')->findByPk($_GET['id'],$criteria); 
получаете объект в единственном числе, а переменную обозвали во множественном, верно было бы $article.
как следствие в одной переменной, хотя они и в разных ветках условия, хранятся значения разных типов Articlies и array соответсвенно.

Код: Выделить всё

            //Получаем комменты
            $criteria_comments = new CDbCriteria(array(
                'condition'=>'t.status='.Comment::STATUS_APPROVED,
                'condition'=>'t.post_id='.$_GET['id'],
            ));
            $comments = Comment::model()->findAll($criteria_comments);
 
выносить в метод модели Articlies.

Три страницы, три условия
ну вот и сделайте 3 разных action, а не плодите ветки условий....

ЗЫ: а вообще мы отошли от темы...
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?Блог (вывод тегов).

Сообщение MOTORIST »

Ок. Завтра перепишу и выложу. Спасибо за замечания. Удачного вечера.
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?Блог (вывод тегов).

Сообщение MOTORIST »

Не стал раскидывать по экшинам. Не вижу смысла. Объем кода все равно не изменится. В менюшке нужно будет обращаться к трем экшинам, а так к одному. Да и зачем если действие по сути одно, просто с разными условиями.
Коментарии вынес в модель и работает отлично. СПС.

А вот с тегами не получается. Голову сломал, ничего не могу придумать. Похоже на глюк. В переменной $article->id_tag лежит 1,2. Тут все нормально. Но функция getTags() выводит только одно значение первое. То есть если 1,2 будет выводить значение при 1. Если 2,3 значение при 2. Если жестко прописать значение $article->id_tag = '3,2,1' то функция выведет значение при 3. Если в функции изменить (без кавычек) in(1,2,3), то выведет все значения.Но если использовать функцию при просмотре всех статей выдаст ошибку:
CDbCommand failed to execute the SQL statement: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1
Я в тупике, помогите кто может =)

В модели:

Код: Выделить всё

public function getTags()
    {    
        $criteria = new CDbCriteria;
        $criteria->condition = "t.id IN('".$this->id_tag."')";
        return Tags::model()->findAll($criteria);
    }
 
В контроллере:

Код: Выделить всё

$article = Articles::model()->with('author')->findByPk($_GET['id'],$criteria);
if(!empty($article)){
                $this->render('article', array(
                        'article'=>$article,
                ));
            }
 
В представлении:

Код: Выделить всё

<div><b>Tags:</b>
    <?php $tags = $article->getTags(); ?>
    <?php foreach($tags as $tag) :?>
        <?php echo $tag->name.' | ';?>
    <?php endforeach ?>
</div>
Дамп $tags:

Код: Выделить всё

array
(
    [0] => Tags#1
    (
        [CActiveRecord:_md] => CActiveRecordMetaData#2
        (
            [tableSchema] => CMysqlTableSchema#3
            (
                [schemaName] => null
                [name] => '{{tags}}'
                [rawName] => '`{{tags}}`'
                [primaryKey] => 'id'
                [sequenceName] => ''
                [foreignKeys] => array()
                [columns] => array
                (
                    [id] => CMysqlColumnSchema#4
                    (
                        [name] => 'id'
                        [rawName] => '`id`'
                        [allowNull] => false
                        [dbType] => 'int(11)'
                        [type] => 'integer'
                        [defaultValue] => null
                        [size] => 11
                        [precision] => 11
                        [scale] => null
                        [isPrimaryKey] => true
                        [isForeignKey] => false
                        [CComponent:_e] => null
                        [CComponent:_m] => null
                    )
                    [name] => CMysqlColumnSchema#5
                    (
                        [name] => 'name'
                        [rawName] => '`name`'
                        [allowNull] => false
                        [dbType] => 'varchar(128)'
                        [type] => 'string'
                        [defaultValue] => null
                        [size] => 128
                        [precision] => 128
                        [scale] => null
                        [isPrimaryKey] => false
                        [isForeignKey] => false
                        [CComponent:_e] => null
                        [CComponent:_m] => null
                    )
                    [frequency] => CMysqlColumnSchema#6
                    (
                        [name] => 'frequency'
                        [rawName] => '`frequency`'
                        [allowNull] => true
                        [dbType] => 'int(11)'
                        [type] => 'integer'
                        [defaultValue] => 1
                        [size] => 11
                        [precision] => 11
                        [scale] => null
                        [isPrimaryKey] => false
                        [isForeignKey] => false
                        [CComponent:_e] => null
                        [CComponent:_m] => null
                    )
                )
                [CComponent:_e] => null
                [CComponent:_m] => null
            )
            [columns] => array
            (
                [id] => CMysqlColumnSchema#4(...)
                [name] => CMysqlColumnSchema#5(...)
                [frequency] => CMysqlColumnSchema#6(...)
            )
            [relations] => array()
            [attributeDefaults] => array
            (
                [frequency] => 1
            )
            [CActiveRecordMetaData:_model] => Tags#7
            (
                [CActiveRecord:_md] => CActiveRecordMetaData#2(...)
                [CActiveRecord:_new] => false
                [CActiveRecord:_attributes] => array()
                [CActiveRecord:_related] => array()
                [CActiveRecord:_c] => null
                [CActiveRecord:_pk] => null
                [CModel:_errors] => array()
                [CModel:_validators] => null
                [CModel:_scenario] => ''
                [CComponent:_e] => null
                [CComponent:_m] => null
            )
        )
        [CActiveRecord:_new] => false
        [CActiveRecord:_attributes] => array
        (
            [id] => '1'
            [name] => 'yii'
            [frequency] => '1'
        )
        [CActiveRecord:_related] => array()
        [CActiveRecord:_c] => null
        [CActiveRecord:_pk] => '1'
        [CModel:_errors] => array()
        [CModel:_validators] => null
        [CModel:_scenario] => 'update'
        [CComponent:_e] => null
        [CComponent:_m] => null
    )
)
 
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как реализовать?Блог (вывод тегов).

Сообщение pirrat »

ну во первых я ошибся, а вы скопипастили и не поправили.

Код: Выделить всё

$criteria->condition = "t.id IN('".$this->id_tag."')"; 
кавычки лишние, надо:

Код: Выделить всё

$criteria->condition = "t.id IN(".$this->id_tag.")"; 
во вторых ошибку видает, потому что $this->id_tag скорее всего пустой.
т.е. в методе надо сначало проверить

Код: Выделить всё

if(empty($this->id_tag))
return array(); 
ну и так же надо отслеживать чтоб в id_tag были валидные данные...
Аватара пользователя
MOTORIST
Сообщения: 245
Зарегистрирован: 2010.06.24, 10:04

Re: Как реализовать?Блог (вывод тегов).

Сообщение MOTORIST »

Спасибо!
Дописал функцию:

Код: Выделить всё

public function getTags()
    {    
        if(!empty($this->id_tag)){
            $criteria = new CDbCriteria;
            $criteria->condition = "t.id IN(".$this->id_tag.")";
            return Tags::model()->findAll($criteria);
        }
    } 
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
pirrat
Сообщения: 193
Зарегистрирован: 2009.04.03, 09:41

Re: Как реализовать?Блог (вывод тегов).

Сообщение pirrat »

не совсем правильно дописали, правильнее было бы вернуть пустой массив (ну или null), если $this->id_tag пустой.
а то в вашем случае получаетcя, что метод возвращает либо array либо void.
и легко можно допустить ошибку, вызвав метод в цикле, при этом не проверив является ли возвращаемое значение массивом.
Закрыто