Разбор кода приложения написанного на 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'
            ]);
        ?>

Из интересного наверное все, я приложил исходник — в нем вы сможете найти более стандартные вещи.Спасибо.

Комментарии (64)


  1. affka
    29.03.2016 09:14
    +2

    inline js, css, куча говнокода… вы удалите этот пост скорей, пока ждуниоры не стали вас в пример брать!


    1. Padaboo
      29.03.2016 11:13
      +1

      Перфикционизм?


  1. SilverFire
    29.03.2016 09:21
    +7

    Yii первой версии (о котором вы пишете) уже очень отстал от современных трендов PHP, потому прием улучшений прекращен, а датой End of life объявлен конец 2018 года. Если вы пишете новый проект — обязательно посмотрите на Yii2, там вы найдете гораздо более гамотные и современные архитектурные решения.


    1. Padaboo
      29.03.2016 09:30
      -2

      Eсть стандартные патерны проектирования, мне не всегда нравится реализация в фреймворках (можно запросто и свой написать) будь то php или другой язык — суть все равно остается прежней. Мне будучи новичком было очень тяжело найти толковые куски кода еще 5-7 лет назад.


      1. Padaboo
        29.03.2016 11:16
        -1

        Да


  1. oxidmod
    29.03.2016 09:24

    В чем смысл выкладывания для ознакомления кода устаревшего фреймворка?
    в чем смысл новичкам учить устаревший фреймворк и потом выбрасывать эти знания за ненадобностью?
    в чем смысл начинать новый проект на yii?


    1. balamyt92
      29.03.2016 09:57
      +4

      в чем смысл начинать новый проект на yii?
      а почему нет? (если берется Yii 2)


    1. SamDark
      29.03.2016 13:10
      +5

      На 1.1 смысла начинать проект нет. На 2.0 — вполне.


  1. pewpew
    29.03.2016 10:03
    +3

    На GitHub есть более-менее грамотно написанные проекты на YII 1.1, например РосЯма:
    https://github.com/RosYama/RosYama.2


    1. Padaboo
      29.03.2016 10:20
      +1

      А спасибо.


    1. scarab
      29.03.2016 11:11
      +2

      А не подскажете то же самое на Yii2?
      Я пока пишу свои поделки на первой версии, но уже становится понятно, что если не хочу превратиться в мамонта — то пора осваивать вторую, и чем быстрее — тем лучше.


      1. Padaboo
        29.03.2016 13:18
        +1

        Думаю лучше обратиться к документации, кстати отличная тема для статьи и хаба. Осваивать новую версию и описывать миграции.


        1. scarab
          29.03.2016 13:25

          Документация — само собой. Но обычно кроме документации, полезно видеть уже готовые, более-менее грамотно написанные проекты, чтобы понимать… даже не coding style, а просто процесс мышления, менталитет фреймворка. На примерах из документации это не всегда видно, они достаточно упрощённые и оторванные от реальной жизни.
          В общем, если кто знает хорошие проекты на Yii2, на которые можно посмотреть в плане изучения кода — буду признателен.



          1. Padaboo
            29.03.2016 14:31

            Есть проект, его делал один человек — его уволили. Пришли 3 новых программиста им код непонравился — начали переписывать — все писали на разных языках в разном стиле и парадигмах (сторонники разных подходов). И таких проектов много. Думаю от примеров из документации отталкиваться правильнее — он следует правилам кодирования язка и стилю фреймворка.
            Я сейчас переезжаю с PHP на Java достаточно большая разница — постараюсь незахватить старых привычек.


          1. oxidmod
            29.03.2016 14:48
            -1

            посмотрите в сторону Laravel, только не увлекайтесь фасадами слишком сильно. Часто новички пихают в них слишком многое
            или же на symfony


    1. vladqa
      29.03.2016 12:25

      Код там на 3 с минусом. Не стал бы рекомендовать новичкам смотреть его и, тем более, брать пример.


      1. pewpew
        29.03.2016 13:06

        Но в таком случае, какой можно порекомендовать?
        Зачастую людям хотелось бы поглядеть на рабочий проект вместо очередного блога или hello world.
        К сожалению не могу показать свой код, он под NDA. Но как и автор, я тоже отошёл от некоторых рекомендаций (например, меня коробит от CHtml).
        YII — это только фреймворк, а демо-проекты — лишь рекомендация.
        Мне, например многие подходы в YII 2 не понравились, и поэтому я пока остался на YII 1.1


        1. SamDark
          29.03.2016 13:11

          Вот, например, большой открытый проект на 2.0: https://www.humhub.org/en


          1. Padaboo
            30.03.2016 02:42

            За опен сорс в разумных пределах)


        1. Padaboo
          29.03.2016 13:14

          Совершенно согласен фреймворки, паттерны и подходы меняются время от времени — некоторые возможности зачастую не используются — по причине неудобства. Суть в рабочем коде, его можно менять как захочется.


        1. Padaboo
          30.03.2016 02:00

          Лицензия? Если вы не будите делиться наработками и техническими подробностями сектор остановится.
          Я к примеру собрался писать игру на java: jmonkeyengine. Там будет достаточно проблем и на клиенте и на сервере. Наработки буду выкладывать в хаб так как люди которые затят научиться программированию или сделать тоже самое просто несмогут этого сделать. Неотчего будет отталкнуться.


      1. Padaboo
        29.03.2016 13:15

        –4 Это не кода на 3 с минусом, а просто html.


    1. xoma
      29.03.2016 12:33

      а что там грамотного?


      1. pewpew
        29.03.2016 14:10

        Местами код сумбурный, но позвольте, вы сразу умным родились и всё умели?
        Лично я, когда начинал разбираться с миграциями, глядел в их код и кое-что почерпнул.
        Вьюхи мне откровенно не нравятся. Но глянуть, как другие люди пишут всегда полезно.


        1. xoma
          29.03.2016 14:16
          +1

          Ну к чему сразу переход на личности? Вы посоветовали новичкам источник, который Вам самим не очень нравится, просто рассказали бы в добавок к ссылке, что там хорошо, а что нет. Иначе будут воспринимать как эталон.


          1. pewpew
            29.03.2016 14:50

            Простите, если задел. Но из того что мне в моём примере не по душе — только лапша в коде и куски с комментариями. Справедливости ради отмечу, что не везде. В остальном, вполне себе боевой проект.
            А вот что неграмотного там заметили Вы?


            1. xoma
              29.03.2016 15:00
              +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. Padaboo
                29.03.2016 22:08
                -1

                Спорный вопрос: оборачивать каждую конструкцию языка в класс? — думаю это нехорошо, некоторые узкие места в PHP переписываются на С для улучшения производительности и экономии памяти. Тоесть с точностью до наоборот.


                1. lnroma
                  30.03.2016 02:37
                  +1

                  https://github.com/RosYama/RosYama.2/blob/master/protected/controllers/HolesController.php#L205 присмотритесь тут у вас sql inj простейшая.


                  1. Padaboo
                    30.03.2016 02:46

                    Там "prepared statement" и в таких местах обычно приводят типы там где это возможно (int)


                    1. lnroma
                      30.03.2016 02:49
                      +2

                      `AND ADR_SUBJECTRF='.$_GET['Holes']['ADR_SUBJECTRF']` тут помойму на прямую пишеться или я ошибаюсь?


        1. Padaboo
          29.03.2016 14:33

          С вьюхами там несколько вариантов: 1)php сам по себе шаблонизатор. 2)стандартные вещи типа Chtml 3)Bootstrap 4) Любой вариант. Фреймворк очень гибкий.


  1. quantum
    29.03.2016 10:12
    +1

    Исходник. В зип архиве. На яндекс диске.


  1. awMinor
    29.03.2016 10:13
    +1

    Достаточно интересная статья, но вот момент с экшенами несколько сбивает с толку, тоесть если я правильно понял, вы предлогаете использовать каждый экшн = класс, а не как изначально в Yii когда экшн = метод контроллера. Таким образом вы призываете уйти от абстракции контроллера к абстракции его экшенов, но зачем? В целом я правильно понимаю, что у нас будет 4 класса с экшенами для CRUD контроллера?


    1. Mendel
      29.03.2016 11:26

      в фреймворке есть возможность указывать в контроллере экшн в виде названия класса а не в виде метода класса.
      Это предназначено как раз для такого решения — когда действие одинаковое во многих контроллерах, и отличаются только детали.
      Собственно ориентируясь именно на встроенное решение автор и писал данный код. Он типовой, но его обычно игнорируют.


  1. Padaboo
    29.03.2016 10:15
    +1

    Суть в том что Экшен может быть один, а контроллеров с одинаковыми действиями 5 — повторное использование кода в данном случае. А вообще — пример использования поведений, экшенов и виджетов.


    1. awMinor
      29.03.2016 10:32

      Просто я не очень понимаю, зачем отрывать экшен от контроллера, тогда ведь нарушается абстракция вся этого контроллера? А дублирование кода, да это плохо. Но в данном случае у меня все равно экшены относятся к контроллерам и не пишется множество не нужных классов, так как вся бизнес логика хранится в модели, ну и экшены у меня все таки просто принимают значения и вызывают метод модели, не более. И тогда никакого дублирования кода, нарушения абстракций и горождения кучи классов ради одного метода. Ведь YII следует парадигме MVC, а значит вся бизнес логика должна быть с моделях.


      1. Padaboo
        29.03.2016 10:44
        +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. Mendel
          29.03.2016 11:32
          +1

          Тут скорее вопрос о том почему наследоваться от CRUDAction а не от CRUDController?


          1. awMinor
            29.03.2016 11:36

            Да, именно это я и пытался сказать. Зачем плодить класс для каждого экшена если можно наследовать контроллер и не разрушать абстракцию контроллер->экшн.


          1. Padaboo
            29.03.2016 12:41

            Именно в этом коде экшены созданы для тех контроллеров который были сгенерированы модулем gii для работы с моделями. 5 моделей и 5 контроллеров с одинаковым содержимым.


            1. awMinor
              29.03.2016 13:11

              Зачем 5 контроллеров с одинковым содержимым, если мы говорим о CRUD, то у нас одна сущность имеет 5 экшенов, тоесть если у нас 5 контроллеров (5 сущностей), то у нас 25 экшенов получается. И почему 5 моделей? Скорее 6, базовая модель плюс её наследеники если нужны. Таким образом у нас нормальный уровень абстракции, каждый экшн принадлежит к сущности контроллера и вызывает бизнес логику на основе входящих данных из модели. Все равно ведь Yii реализует парадигму MVC, тоесть даже в вашем случае вся бизнес логика должна быть в модели и у вас просто получается класс-экшн который просто вызывает бизнес логику из модели. Ваш подход применим только к RESTFull API и только если вы не реализуете бизнес логику в моделях, а реализуете её в экшенах.


        1. awMinor
          29.03.2016 11:34

          Но модель чаще всего будет разная в зависимости от сущности, а вот рендер, не думаю, что ради одной строки стоит создавать класс обертку для экшена. А по поводу вашего примера с грузовиками, так мне кажется, что применение нормальных форм баз данных к ООП не очень приминимо.


          1. Padaboo
            29.03.2016 12:49

            Нормальные формы — это тоже своеобразные правила которые можно и нужно нарушать в пользу скорости кода, просто аналогия. Модель может быть и будет разная, я про типовые вещи findByPk().
            Смотрите как теперь выглядит контроллер — насколько меньше кода:
            Если я захочу поменять что то в 10 контроллерах, мне нужно будет поменять это только в одном экшене который к ним прикрепляется, так выглядит контроллер:
            Yii::import('application.controllers.CrudController');
            class MaterialsController extends CrudController{}


            1. awMinor
              29.03.2016 13:01
              +1

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


              1. Padaboo
                29.03.2016 13:37

                Да, все стандартные методы реализованы в базовой модели, а уникальные в наследнике — но в итоге вызов методов происходит в контроллере. Мы же не переносим всю логику в модель — а только делаем вызов или нет? Это может по разному выглядеть в контроллерах так:

                        $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);

                Но речь идет о повторном использовании кода контроллера.


                1. awMinor
                  29.03.2016 13:46

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

                  1. Почему нельзя реализовать все таки контроллер с этими экшенами и наследоватся от него?
                  2. Что вы будете делать когда один экшн одного контроллера потребует изменения логики? Создавать новый экшн-класс?
                  3. Стоит ли ради "избежания повторного использования кода" разрушать абстракцию данных сущность-экшн? Ведь этого можно избежать используя наследование контроллеров.


                  1. Padaboo
                    29.03.2016 14:21

                    С первым согласен это в общем то одно и тоже создать экшены или наследоваться от общего. На мой взгляд отдельные экшены более гибкая штука. Похоже на хэндлер больше.


                    1. awMinor
                      29.03.2016 14:53

                      Отдельные экшены имеет смысл только когда нужно использовать некий компонент который должен предоставлять экшн, для примера загрузка изображения в таком случае в контроллер просто подгружается компонент и экшн. Но вы же в статье показали пример на CRUD, а в CRUD мне сложно представить ситуацию, когда у двух сущностей будут идентичные экшены. А если создавать отдельный экшн для каждой сущности, то выйдет каша и классов.


                      1. Padaboo
                        29.03.2016 23:48

                        Посмотрите генератор gii он выдает одинаковые контроллеры


                        1. awMinor
                          30.03.2016 08:27
                          +1

                          потому что он генерирует по шаблону, мне ещё никода не доводилось видеть в лайв проекте использование кода gii без изменений.


                          1. SamDark
                            30.03.2016 12:54
                            +1

                            Он и предназначен для того, чтобы результат генерации меняли под себя.


  1. lnroma
    29.03.2016 10:32
    +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);

    тот кто скопирует это, долго будет искать почему картинка не сохранилась, ведь ошибок нет.


    1. Padaboo
      29.03.2016 10:46

      В этой части кода мы конвертируем телефоны из базы данных в картинку, что бы их тяжелее было спарсить, поэтому отдается хэдером при запросе.


      1. lnroma
        29.03.2016 10:53
        +2

        Хотя да, статья же не о чистоте кода :) просто отвлекает меня такой код, ну может только меня.


  1. Padaboo
    29.03.2016 11:15

    Чистота кода она конечно важна, но так можно: рефакторить, улучшать, "подкрашивать", переписывать код до бесконечности — потратить кучу времени которое стоит дороже чем красота кода.


    1. lnroma
      29.03.2016 16:28

      Так то да. Но если не тратить время на рефакторинг(можно сказать работу над ошибками). Движет всё таки изучать ЯП, и применять оптимальные решения. Да кто то зарабатывает деньги тратой времени на написание «нечистого кода» большого объёма, а кто то пишет «более чистый код», и зарабатывает на том что, элементарные задачи на подобие «вывести тайтл с префиксом» решает за 5 минут, а кто то разбираеться в своём же коде пишит велосипеды и тратит 30 минут, и того 25 минут разницы. По вашему кому заплатят больше? первому или второму. Конечно первому т.к. это вложение в будущее проэкта, это меньший порог вхождения и стабильность работы, а второй стоит дешевле так как, в будущем это высокий порог вхождения, низкая стабильность, разработка нового решения… А по статье правда отвлекает от чтения. И не обежайтесь это моё сугубо личное мнение.


      1. Padaboo
        29.03.2016 22:05

        Идея насчет тайтла в коде интересная мысль:

        <?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;
            }
        } 


        1. lnroma
          29.03.2016 22:12

          Сорри не понял Вашего заявления… Собственно, title в коде смотря как использовать:
          1. Когда просто сайтик без админки — почему бы нет если это ваш сайт и вам в принципе удобно напрямую работать с файлами(кодом) или базой.
          2. Когда это cms — и вам необходимо хранить их в базе данных 'как они есть' так как, мета title,description,keywords и теги такие как h1,h2,p их содержимое должно редактироваться из админки и отображаться та как было это вписано в поле в админки. Что собственно приводит к гибкости проэкта.


          1. Padaboo
            29.03.2016 23:55

            С одной стороны да, с другой нужно писать "паттерны" та как мета теги почти везде и всегда динамические, например: Отделение ВТБ 24 ${Новосибирск} Филиал № 5411 | concat{Все для бизнеса 2biz.net}


            1. lnroma
              30.03.2016 01:31

              С точки зрения СЕО они не должны быть динамические, вот несколько аргументов почему:

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

              Я мог бы перечислять дальше но думаю, понятен ход моих мыслей. По этому можно добавить ваш «паттерн» способностью гибко редактировать, любое из свойств для странице, допустим title, и приоритет вывода довать title из базы если он существует.


  1. Padaboo
    31.03.2016 09:16

    fetch_assoc :)


  1. Padaboo
    05.04.2016 11:32
    -1

    http://cs623131.vk.me/v623131445/4d2bc/Eo7GB3WAAa4.jpg