Yii framework разбор кода

    Разбор кода приложения написанного на php c применением Yii Framework (исходник).

    Из статьи можно вынести интересные куски кода на php, а так же тонкости и конструкции Yii Framework, расчитана она на поддержку php программистов и пользователей Yii Framework.

    Поведения Behavior


    Пример поведения для работы с изображениями (как мы знаем поведения прикрепляются к контроллеру и становятся частью его функционала):
    class ImageBehavior extends CBehavior{
        public $modelName = '';
        const MAX_WIDTH   = 450;
        const MAX_HEIGHT  = 450;
    
        public function resize($path){
    
            $mimeType = mime_content_type($path);
    
            $type     = str_replace('image/','',$mimeType);
    
            list($width, $height) = getimagesize($path);
    
            list($newWidth, $newHeight) = $this->getNewSize($width,$height);
    
            $thumb = imagecreatetruecolor($newWidth, $newHeight);
    
            $createFunction = 'imagecreatefrom' . $type;
            $source         = $createFunction($path);
    
            imagecopyresized($thumb, $source, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
    
            $imageFunction = 'image' . $type;
    
            ob_start();
            header('Content-Type: ' . $mimeType);
    
            $imageFunction($thumb,null,100);
    
            $img = ob_get_contents();
    
            @unlink($path);
    
            @file_put_contents($path,$img);
        }
    
        public function getNewSize($width,$height){
            $wK        = $width/$height;
            $hK        = $height/$width;
            $newWidth  = $width;
            $newHeight = $height;
            if($width > self::MAX_WIDTH && ($width > $height)){
                $newWidth  = self::MAX_WIDTH;
                $newHeight = $newWidth/$wK;
            }
            if($height > self::MAX_HEIGHT && ($height > $width)){
                $newHeight = self::MAX_HEIGHT;
                $newWidth  = $newHeight/$hK;
            }
            return array($newWidth,$newHeight);
        }
    
        public function columnExists($column){
            $modelName   = $this->modelName;
            $model       = $modelName::model();
            $table       = Yii::app()->getDb()->getSchema()->getTable($model->tableName());
            $columnNames = $table->getColumnNames();
    
            return in_array($column,$columnNames);
        }
    
        public function deleteImage(){
            if($this->columnExists('image_path')){
                $path     = $this->image_path;
                $fullPath = Yii::getPathOfAlias('webroot') . $path;
                if(file_exists($fullPath))
                    @unlink($fullPath);
            }
        }
    
        public function getModelName(){
            return get_called_class();
        }
    
    

    Давайте разберем поподробнее, в поведение вынесена часть функционала модели Yii + добавлены общие методы для работы с изображениями. Предположим у нас есть 5 контроллеров в которых используются изображения, для того что бы не дублировать код, мы просто выносим функционал в поведение. Так же в поведении можно переопределить часть стандартных функций класса.

    Action действия


    Для удобного повторго использования кода в Yii существуют Actions которые прикрепляются к контроллерам.
    Во время генерации кода при помощи модуля gii, cоздаются множетсво почти одинаковых контроллеров функционал которых можно вынести в отдельный класс Action.
    Создается CRUDAction который наследуется от CAction, определены 2 атрибута: название модели и страница редиректа на которую пользователь попадает после завершения действий CRUD(Create Read Update Delete), так же происходит загрузка модели:
    <?php
    
    class CRUDAction extends  CAction{
        public $modelName;
        public $redirectTo = ['index'];
    
        public function loadModel($id){
            $m = $this->modelName;
            $model = $m::model()->findByPk($id);
            if($model===null)
                throw new CHttpException(404,'The requested page does not exist.');
            return $model;
        }
    }
    

    CreateAction — наследуется от CRUDAction, динамически создается модель и задается название сценария, в методе run описывается стандартные действия:
    <?php
    Yii::import('application.components.actions.CRUDAction');
    class CreateAction extends CRUDAction{
    
        public function run(){
            $model = new $this->modelName;
            $model->scenario = 'create';
    
            if(isset($_POST[$this->modelName])){
                $model->attributes = $_POST[$this->modelName];
                if($model->save())
                    $this->getController()->redirect($this->redirectTo);
            }
    
            $renderPath = strtolower("create");
            $this->getController()->render($renderPath,[
                'model' => $model,
            ]);
        }
    }
    

    Виджет

    Большое количество одинакового функционала — можно упаковать в виджет и вызывать там где понадобится.
    Класс виджета:
    class Citywidget extends CWidget{
        public $cols = 10;
        public $name;
        public $dialogId;
        public $city_id;
        public $defaultName = 'Город';
    
        public function init(){
            parent::init();
        }
    
        public function run(){
    
            $this->render('citywidget',[
                'name'        => $this->name,
                'dialogId'    => $this->dialogId,
                'city_id'     => $this->city_id,
                'cols'        => $this->cols,
                'defaultName' => $this->defaultName,
            ]);
        }
    }
    

    Представление:
    <?php
        $this->beginWidget('zii.widgets.jui.CJuiDialog',array(
            'id' => $dialogId,
            // additional javascript options for the dialog plugin
            'options'=> [
                'title' => 'Города',
                'autoOpen'=>false,
                'width' => '800px'
            ],
            'htmlOptions' => [
                'width' => '800px'
            ]
        ));
    ?>
    
    <?php
        $cities   = Cities::getCities();
        $count    = count($cities);
        $perCol   = round($count/$cols);
    
        if($city_id == 0){
            $city_id = CityChooser::$cityId;
        }
    
        $cityName = Cities::getCityNameByPk($city_id,$defaultName);
    ?>
    
    <style type="text/css">
        #<?=$dialogId?>{
            display:none;
        }
        #<?=$dialogId?> ul {
            float:left;
            clear:right;
            padding:5px;
        }
        #<?=$dialogId?> li {
            float:left;
            clear:left;
        }
    </style>
    <script type="text/javascript">
        function changeCity<?=$dialogId?>(id,cityName,dialogId,inName){
            $("#href-"+dialogId+"").text(cityName);
            $("input[name*='"+inName+"']").val(id);
            $("#"+dialogId).dialog("close");
    
            if(dialogId == 'chooserDialogId'){
                $.get( "/api/setcity/id/"+id, function( data ) {
    
                });
            }
            //$("#"+dialogId).dialog("close");
        }
    </script>
    
            <?='<ul>'?>
            <?php $i=0; ?>
            <?php foreach ($cities as $city):?>
               <?php if($i>=$perCol):?>
                    <?='</ul><ul>'?>
                    <?php $i=0; ?>
               <?php endif;?>
    
                  <li style="margin-top:4px;">
                    <a href="#" style="margin:8px;color: #428bca;" onClick="changeCity<?=$dialogId?>('<?=$city->id?>','<?=$city->name?>','<?=$dialogId?>','<?=$name?>')">
                        <?php if((int)$city->sort !== 0):?>
                            <b><?=$city->name?></b>
                        <?php else:?>
                            <?=$city->name?>
                        <?php endif;?>
                    </a>
                  </li>
    
                <?php if($i>=$perCol):?>
                    <?='</ul>'?>
                <?php endif;?>
    
                <?php $i++; ?>
            <?php endforeach;?>
            <?='</ul>'?>
    
    <?php $this->endWidget('zii.widgets.jui.CJuiDialog');?>
    
    <input type="hidden" name="<?=$name?>" value="<?=$city_id?>">
    
    <a href="#" id="href-<?=$dialogId?>" onclick='$("#<?=$dialogId?>").dialog("open"); return false;'><?= $cityName?></a>
    
    

    Как видите с такой смесью php и html работать неудобно, а вот так выглядит вызов виджета:
            <?php
                $this->widget('Citywidget',[
                    'name'        => 'Biztrade[city_id]',
                    'city_id'     => $model->city_id,
                    'dialogId'    => 'dialogId'
                ]);
            ?>
    

    Из интересного наверное все, я приложил исходник — в нем вы сможете найти более стандартные вещи.Спасибо.
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 64

      +2
      inline js, css, куча говнокода… вы удалите этот пост скорей, пока ждуниоры не стали вас в пример брать!
        +1
        Перфикционизм?
        +7
        Yii первой версии (о котором вы пишете) уже очень отстал от современных трендов PHP, потому прием улучшений прекращен, а датой End of life объявлен конец 2018 года. Если вы пишете новый проект — обязательно посмотрите на Yii2, там вы найдете гораздо более гамотные и современные архитектурные решения.
          –2
          Eсть стандартные патерны проектирования, мне не всегда нравится реализация в фреймворках (можно запросто и свой написать) будь то php или другой язык — суть все равно остается прежней. Мне будучи новичком было очень тяжело найти толковые куски кода еще 5-7 лет назад.
            –1
            Да
          0
          В чем смысл выкладывания для ознакомления кода устаревшего фреймворка?
          в чем смысл новичкам учить устаревший фреймворк и потом выбрасывать эти знания за ненадобностью?
          в чем смысл начинать новый проект на yii?
            +4
            в чем смысл начинать новый проект на yii?
            а почему нет? (если берется Yii 2)
              +5
              На 1.1 смысла начинать проект нет. На 2.0 — вполне.
              +3
              На GitHub есть более-менее грамотно написанные проекты на YII 1.1, например РосЯма:
              https://github.com/RosYama/RosYama.2
                +1
                А спасибо.
                  +2
                  А не подскажете то же самое на Yii2?
                  Я пока пишу свои поделки на первой версии, но уже становится понятно, что если не хочу превратиться в мамонта — то пора осваивать вторую, и чем быстрее — тем лучше.
                    +1
                    Думаю лучше обратиться к документации, кстати отличная тема для статьи и хаба. Осваивать новую версию и описывать миграции.
                      0
                      Документация — само собой. Но обычно кроме документации, полезно видеть уже готовые, более-менее грамотно написанные проекты, чтобы понимать… даже не coding style, а просто процесс мышления, менталитет фреймворка. На примерах из документации это не всегда видно, они достаточно упрощённые и оторванные от реальной жизни.
                      В общем, если кто знает хорошие проекты на Yii2, на которые можно посмотреть в плане изучения кода — буду признателен.
                          0
                          Есть проект, его делал один человек — его уволили. Пришли 3 новых программиста им код непонравился — начали переписывать — все писали на разных языках в разном стиле и парадигмах (сторонники разных подходов). И таких проектов много. Думаю от примеров из документации отталкиваться правильнее — он следует правилам кодирования язка и стилю фреймворка.
                          Я сейчас переезжаю с PHP на Java достаточно большая разница — постараюсь незахватить старых привычек.
                            –1
                            посмотрите в сторону Laravel, только не увлекайтесь фасадами слишком сильно. Часто новички пихают в них слишком многое
                            или же на symfony
                        0
                        Код там на 3 с минусом. Не стал бы рекомендовать новичкам смотреть его и, тем более, брать пример.
                          0
                          Но в таком случае, какой можно порекомендовать?
                          Зачастую людям хотелось бы поглядеть на рабочий проект вместо очередного блога или hello world.
                          К сожалению не могу показать свой код, он под NDA. Но как и автор, я тоже отошёл от некоторых рекомендаций (например, меня коробит от CHtml).
                          YII — это только фреймворк, а демо-проекты — лишь рекомендация.
                          Мне, например многие подходы в YII 2 не понравились, и поэтому я пока остался на YII 1.1
                            0
                            Вот, например, большой открытый проект на 2.0: https://www.humhub.org/en
                              0
                              За опен сорс в разумных пределах)
                              0
                              Совершенно согласен фреймворки, паттерны и подходы меняются время от времени — некоторые возможности зачастую не используются — по причине неудобства. Суть в рабочем коде, его можно менять как захочется.
                                0
                                Лицензия? Если вы не будите делиться наработками и техническими подробностями сектор остановится.
                                Я к примеру собрался писать игру на java: jmonkeyengine. Там будет достаточно проблем и на клиенте и на сервере. Наработки буду выкладывать в хаб так как люди которые затят научиться программированию или сделать тоже самое просто несмогут этого сделать. Неотчего будет отталкнуться.
                                0
                                –4 Это не кода на 3 с минусом, а просто html.
                                0
                                а что там грамотного?
                                  0
                                  Местами код сумбурный, но позвольте, вы сразу умным родились и всё умели?
                                  Лично я, когда начинал разбираться с миграциями, глядел в их код и кое-что почерпнул.
                                  Вьюхи мне откровенно не нравятся. Но глянуть, как другие люди пишут всегда полезно.
                                    +1
                                    Ну к чему сразу переход на личности? Вы посоветовали новичкам источник, который Вам самим не очень нравится, просто рассказали бы в добавок к ссылке, что там хорошо, а что нет. Иначе будут воспринимать как эталон.
                                      0
                                      Простите, если задел. Но из того что мне в моём примере не по душе — только лапша в коде и куски с комментариями. Справедливости ради отмечу, что не везде. В остальном, вполне себе боевой проект.
                                      А вот что неграмотного там заметили Вы?
                                        +1
                                        Ну, например:
                                        — тонны логики в контроллерах https://github.com/RosYama/RosYama.2/blob/master/protected/controllers/HolesController.php#L140
                                        — прямое обращение к $_GET и т.д. https://github.com/RosYama/RosYama.2/blob/master/protected/controllers/HolesController.php#L205
                                        — регистрация статики в контроллере — https://github.com/RosYama/RosYama.2/blob/master/protected/controllers/HolesController.php#L237
                                        — ужасное форматирование кода
                                        — curl-лапша https://github.com/RosYama/RosYama.2/blob/master/protected/controllers/HolesController.php#L720

                                        Это только то, что бросилось в глаза в первом открытом контроллере.
                                          –1
                                          Спорный вопрос: оборачивать каждую конструкцию языка в класс? — думаю это нехорошо, некоторые узкие места в PHP переписываются на С для улучшения производительности и экономии памяти. Тоесть с точностью до наоборот.
                                            +1
                                            https://github.com/RosYama/RosYama.2/blob/master/protected/controllers/HolesController.php#L205 присмотритесь тут у вас sql inj простейшая.
                                              0
                                              Там "prepared statement" и в таких местах обычно приводят типы там где это возможно (int)
                                                +2
                                                `AND ADR_SUBJECTRF='.$_GET['Holes']['ADR_SUBJECTRF']` тут помойму на прямую пишеться или я ошибаюсь?
                                      0
                                      С вьюхами там несколько вариантов: 1)php сам по себе шаблонизатор. 2)стандартные вещи типа Chtml 3)Bootstrap 4) Любой вариант. Фреймворк очень гибкий.
                                  +1
                                  Исходник. В зип архиве. На яндекс диске.
                                    +1
                                    Достаточно интересная статья, но вот момент с экшенами несколько сбивает с толку, тоесть если я правильно понял, вы предлогаете использовать каждый экшн = класс, а не как изначально в Yii когда экшн = метод контроллера. Таким образом вы призываете уйти от абстракции контроллера к абстракции его экшенов, но зачем? В целом я правильно понимаю, что у нас будет 4 класса с экшенами для CRUD контроллера?
                                      0
                                      в фреймворке есть возможность указывать в контроллере экшн в виде названия класса а не в виде метода класса.
                                      Это предназначено как раз для такого решения — когда действие одинаковое во многих контроллерах, и отличаются только детали.
                                      Собственно ориентируясь именно на встроенное решение автор и писал данный код. Он типовой, но его обычно игнорируют.
                                      +1
                                      Суть в том что Экшен может быть один, а контроллеров с одинаковыми действиями 5 — повторное использование кода в данном случае. А вообще — пример использования поведений, экшенов и виджетов.
                                        0
                                        Просто я не очень понимаю, зачем отрывать экшен от контроллера, тогда ведь нарушается абстракция вся этого контроллера? А дублирование кода, да это плохо. Но в данном случае у меня все равно экшены относятся к контроллерам и не пишется множество не нужных классов, так как вся бизнес логика хранится в модели, ну и экшены у меня все таки просто принимают значения и вызывают метод модели, не более. И тогда никакого дублирования кода, нарушения абстракций и горождения кучи классов ради одного метода. Ведь YII следует парадигме MVC, а значит вся бизнес логика должна быть с моделях.
                                          +1
                                          Это в теории, вспомните нормальные формы баз данных, есть много примеров когда для одного поля лучше не создавать отдельную таблицу:
                                          class Trucks extends Advert{
                                          
                                              public $bodyTypes = [
                                                 1  => "Закрытый-Тентованный",
                                                 2  => "Закрытый-Фургон",
                                                 3  => "Закрытый-Контейнер",
                                                 4  => "Закрытый-Цельнометаллич.",
                                                 5  => "Закрытый-Рефрижератор",
                                                 6  => "Закрытый-Изотермический",
                                                 7  => "Открытый-Бортовой",
                                                 8  => "Открытый-Контейнеровоз",
                                                 9  => "Открытый-Низкорамный",
                                                 10 => "Открытый-Самосвал",
                                                 11 => "Открытый-Шаланда",
                                                 12 => "Открытый-Платформа",
                                                 13 => "Открытый-Пирамида",
                                                 14 => "Автовоз",
                                                 15 => "Автотранспортер",
                                                 16 => "Эвакуатор",
                                                 17 => "Трал",
                                                 18 => "Автобус",
                                                 19 => "Микроавтобус",
                                                 20 => "Пикап",
                                                 21 => "Легковая-седан",
                                                 22 => "Легковая-хетчбек",
                                                 23 => "Легковая-универсал",
                                                 24 => "Ж/Д вагон",
                                                 25 => "Цистерна"
                                              ];

                                          И тут таже история всмысле парадигмы, у нас есть кусок кода который повторяется во многих контроллерах, мы его выносим в экшен:
                                              public function actionIndex(){
                                                  $model = new Model();
                                                  $this->render('index',['model' => $model]);
                                              }
                                            +1
                                            Тут скорее вопрос о том почему наследоваться от CRUDAction а не от CRUDController?
                                              0
                                              Да, именно это я и пытался сказать. Зачем плодить класс для каждого экшена если можно наследовать контроллер и не разрушать абстракцию контроллер->экшн.
                                                0
                                                Именно в этом коде экшены созданы для тех контроллеров который были сгенерированы модулем gii для работы с моделями. 5 моделей и 5 контроллеров с одинаковым содержимым.
                                                  0
                                                  Зачем 5 контроллеров с одинковым содержимым, если мы говорим о CRUD, то у нас одна сущность имеет 5 экшенов, тоесть если у нас 5 контроллеров (5 сущностей), то у нас 25 экшенов получается. И почему 5 моделей? Скорее 6, базовая модель плюс её наследеники если нужны. Таким образом у нас нормальный уровень абстракции, каждый экшн принадлежит к сущности контроллера и вызывает бизнес логику на основе входящих данных из модели. Все равно ведь Yii реализует парадигму MVC, тоесть даже в вашем случае вся бизнес логика должна быть в модели и у вас просто получается класс-экшн который просто вызывает бизнес логику из модели. Ваш подход применим только к RESTFull API и только если вы не реализуете бизнес логику в моделях, а реализуете её в экшенах.
                                                0
                                                Но модель чаще всего будет разная в зависимости от сущности, а вот рендер, не думаю, что ради одной строки стоит создавать класс обертку для экшена. А по поводу вашего примера с грузовиками, так мне кажется, что применение нормальных форм баз данных к ООП не очень приминимо.
                                                  0
                                                  Нормальные формы — это тоже своеобразные правила которые можно и нужно нарушать в пользу скорости кода, просто аналогия. Модель может быть и будет разная, я про типовые вещи findByPk().
                                                  Смотрите как теперь выглядит контроллер — насколько меньше кода:
                                                  Если я захочу поменять что то в 10 контроллерах, мне нужно будет поменять это только в одном экшене который к ним прикрепляется, так выглядит контроллер:
                                                  Yii::import('application.controllers.CrudController');
                                                  class MaterialsController extends CrudController{}
                                                    +1
                                                    Но так же вы можете поменять это в одной модели, ведь модель в парадигме MVC и модель в Yii вообще вещи разные, так же никто не запрещает абстракцию модели, тоесть таким образом вы наследуете базовую модель которая реализует базовую бизнес логику для всех моделей, которые в свою очередь реализуют только уникальные методы бизнес логики в зависимости от сущности.
                                                      0
                                                      Да, все стандартные методы реализованы в базовой модели, а уникальные в наследнике — но в итоге вызов методов происходит в контроллере. Мы же не переносим всю логику в модель — а только делаем вызов или нет? Это может по разному выглядеть в контроллерах так:
                                                              $model = Cities::model()->findAll([
                                                                  'condition' => 'name like :term',
                                                                  'params' => [
                                                                      ':term' => "%$term%"
                                                                  ]
                                                              ]);
                                                      
                                                              $arr = [];
                                                      
                                                              foreach($model as $city){
                                                                  $arr[] = ['id' => $city->id, 'value' => $city->name];
                                                              }

                                                      или так
                                                      $model = Cities::model()->findByName($name);
                                                      
                                                              $arr = [];
                                                      
                                                              foreach($model as $city){
                                                                  $arr[] = ['id' => $city->id, 'value' => $city->name];
                                                              }

                                                      Или так:
                                                      $arr = Cities::model()->findByNameArray($name);

                                                      Но речь идет о повторном использовании кода контроллера.
                                                        0
                                                        Все правильно, и вся бизнес логика у вас находится в модели, так зачем тогда вам 25 классов экшенов если достаточно 5 классов контроллеров, ведь обычно контроллер = сущность и согласно вашему примеру в каждом контроллере будет использоваться разная модель? Или одна? Хорошо, даже предположим, что экшены полностью идентичны для разных 5-ти контроллеров. Но учитывая что вся бизнес логика в модели, вы просто создадите класс-экшн для одной, двух строк. Да вы избавитесь от повторного использования кода, но, возникает три вопроса:

                                                        1. Почему нельзя реализовать все таки контроллер с этими экшенами и наследоватся от него?
                                                        2. Что вы будете делать когда один экшн одного контроллера потребует изменения логики? Создавать новый экшн-класс?
                                                        3. Стоит ли ради "избежания повторного использования кода" разрушать абстракцию данных сущность-экшн? Ведь этого можно избежать используя наследование контроллеров.
                                                          0
                                                          С первым согласен это в общем то одно и тоже создать экшены или наследоваться от общего. На мой взгляд отдельные экшены более гибкая штука. Похоже на хэндлер больше.
                                                            0
                                                            Отдельные экшены имеет смысл только когда нужно использовать некий компонент который должен предоставлять экшн, для примера загрузка изображения в таком случае в контроллер просто подгружается компонент и экшн. Но вы же в статье показали пример на CRUD, а в CRUD мне сложно представить ситуацию, когда у двух сущностей будут идентичные экшены. А если создавать отдельный экшн для каждой сущности, то выйдет каша и классов.
                                                              0
                                                              Посмотрите генератор gii он выдает одинаковые контроллеры
                                                                +1
                                                                потому что он генерирует по шаблону, мне ещё никода не доводилось видеть в лайв проекте использование кода gii без изменений.
                                                                  +1
                                                                  Он и предназначен для того, чтобы результат генерации меняли под себя.
                                            +2
                                            ob_start();
                                            header('Content-Type: '. $mimeType);

                                            $imageFunction($thumb,null,100);

                                            $img = ob_get_contents();

                                            @unlink($path);

                                            @file_put_contents($path,$img);

                                            а не проще сразу в фаил писать `$imageFunction($thumb,$path,100);` и ещё один момент.
                                            @unlink($path);
                                            @file_put_contents($path,$img);

                                            тот кто скопирует это, долго будет искать почему картинка не сохранилась, ведь ошибок нет.
                                              0
                                              В этой части кода мы конвертируем телефоны из базы данных в картинку, что бы их тяжелее было спарсить, поэтому отдается хэдером при запросе.
                                                +2
                                                Хотя да, статья же не о чистоте кода :) просто отвлекает меня такой код, ну может только меня.
                                              0
                                              Чистота кода она конечно важна, но так можно: рефакторить, улучшать, "подкрашивать", переписывать код до бесконечности — потратить кучу времени которое стоит дороже чем красота кода.
                                                0
                                                Так то да. Но если не тратить время на рефакторинг(можно сказать работу над ошибками). Движет всё таки изучать ЯП, и применять оптимальные решения. Да кто то зарабатывает деньги тратой времени на написание «нечистого кода» большого объёма, а кто то пишет «более чистый код», и зарабатывает на том что, элементарные задачи на подобие «вывести тайтл с префиксом» решает за 5 минут, а кто то разбираеться в своём же коде пишит велосипеды и тратит 30 минут, и того 25 минут разницы. По вашему кому заплатят больше? первому или второму. Конечно первому т.к. это вложение в будущее проэкта, это меньший порог вхождения и стабильность работы, а второй стоит дешевле так как, в будущем это высокий порог вхождения, низкая стабильность, разработка нового решения… А по статье правда отвлекает от чтения. И не обежайтесь это моё сугубо личное мнение.
                                                  0
                                                  Идея насчет тайтла в коде интересная мысль:
                                                  <?php
                                                  
                                                  class MetaTagMap extends CComponent{
                                                  
                                                      public static $map = [
                                                          'credits/index' => [
                                                              'description' => 'Взять кредит без залогов и поручителей',
                                                              'keywords'    => 'кредит,взять кредит,кредит без поручителей,кредит без залогов,кредит без залогов и поручителей',
                                                              'title'       => "Взять кредит"
                                                          ],
                                                          'trucks/index' => [
                                                              'description' => 'Поиск грузоперевозчиков',
                                                              'keywords'    => 'перевезти груз,грузоперевозки',
                                                              'title'       => "Грузоперевозки"
                                                          ],
                                                          'buildings/index' => [
                                                              'description' => 'Коммерческая недвижимость',
                                                              'keywords'    => 'аренда офиса,аренда склада,купить склад,купить офис,купить здание,арендовать здание',
                                                              'title'       => "Недвижимость"
                                                          ],
                                                          'biztrade/index' => [
                                                              'description' => 'Купить бизнес',
                                                              'keywords'    => 'купить бизнес,купить долю,купить франшизу',
                                                              'title'       => "Купить бизнес"
                                                          ],
                                                          'materials/index' => [
                                                              'description' => 'Товары ',
                                                              'keywords'    => 'купить,',
                                                              'title'       => "Купить "
                                                          ],
                                                      ];
                                                  
                                                      public static function getKeywords($key, $add = ''){
                                                          return self::$map[$key]['keywords'].$add;
                                                      }
                                                  
                                                      public static function getTitle($key, $add = ''){
                                                          return self::$map[$key]['title'] . " ". $add ." | ".Yii::app()->name;
                                                      }
                                                  
                                                      public static function getDescription($key, $add = ''){
                                                          return self::$map[$key]['description']. ' ' . $add;
                                                      }
                                                  } 
                                                    0
                                                    Сорри не понял Вашего заявления… Собственно, title в коде смотря как использовать:
                                                    1. Когда просто сайтик без админки — почему бы нет если это ваш сайт и вам в принципе удобно напрямую работать с файлами(кодом) или базой.
                                                    2. Когда это cms — и вам необходимо хранить их в базе данных 'как они есть' так как, мета title,description,keywords и теги такие как h1,h2,p их содержимое должно редактироваться из админки и отображаться та как было это вписано в поле в админки. Что собственно приводит к гибкости проэкта.
                                                      0
                                                      С одной стороны да, с другой нужно писать "паттерны" та как мета теги почти везде и всегда динамические, например: Отделение ВТБ 24 ${Новосибирск} Филиал № 5411 | concat{Все для бизнеса 2biz.net}
                                                        0
                                                        С точки зрения СЕО они не должны быть динамические, вот несколько аргументов почему:

                                                        1. 'Сухие' тайтлы, с точки зрения пользователя я перейду 'Отделение ВТБ-24 в новосибирске', да и в сео есть приёмы как сокращение слов к примеру городов, 'Отд-ние ВТБ в городе Новосибирске', т.е. Вам придёться писать чуть ли не каждой странице свой уникальный title и description.
                                                        2. Обязательно найдёться город/регион, филиал, другая информация, которая сломает title(вероятность генерации неверных словосочетаний, к примеру из жизни «купить зонта в нашем интернет магазине»).
                                                        3. Meta Description должен быть в своем роде уникален.
                                                        4. Keywords тем более (хотя вроде как их можно опустить)
                                                        5. h1 страницы не должен повторять title и зависить от него, и он должен встречаться только один раз на странице
                                                        6. h2 подобно пункту 5.
                                                        7. p — «сеотексты» (в большинстве случаев он отображаеться в описание при выдачи) должен быть уникальным и в краткой форме раскрывать суть страницы.
                                                        8. etc

                                                        Я мог бы перечислять дальше но думаю, понятен ход моих мыслей. По этому можно добавить ваш «паттерн» способностью гибко редактировать, любое из свойств для странице, допустим title, и приоритет вывода довать title из базы если он существует.
                                                0
                                                fetch_assoc :)
                                                  –1
                                                  http://cs623131.vk.me/v623131445/4d2bc/Eo7GB3WAAa4.jpg

                                                  Only users with full accounts can post comments. Log in, please.