Каков наиболее приемлемый подход к генерации кода Javascript / ExtJS из PHP? - PullRequest
4 голосов
/ 27 января 2011

Я создаю среду PHP, которая позволяет разработчику PHP создавать интерфейс ExtJS только с классами PHP, например, создание сетки выглядит следующим образом:

$grid_import = new Backend_Layout_Grid('smart_worksheets');
$grid_import->set_width(1300);
$grid_import->set_rows_selectable(true);
$grid_import->set_title(__('backend.application.import.grid.title'));
$grid_import->set_margin('10px'); //CSS syntax, e.g. also "10px 0 0 0"
$grid_import->add_column(array('id_code'=>'name', 'label'=> __('backend.application.import.worksheetstoimport'), 'width'=>'300'));
$grid_import->add_column(array('id_code'=>'kind', 'label'=> __('backend.application.import.kind'), 'width'=>'50'));
$grid_import->add_column(array('id_code'=>'file_size', 'label'=> __('backend.application.import.sizebyte'), 'datatype' => 'int'));
$grid_import->add_column(array('id_code'=>'when_file_copied', 'label'=> __('backend.application.import.whenfilecopied'), 'datatype' => 'datetime', 'width'=>'150'));
$grid_import->add_column(array('id_code'=>'table_name', 'label'=> __('backend.application.import.mysqltablename'), 'width'=>'300'));
$grid_import->add_column(array('id_code'=>'when_table_created', 'label'=> __('backend.application.import.whentablecreated'), 'width'=>'160'));
$grid_import->add_column(array('id_code'=>'status', 'label'=> __('backend.application.import.status'), 'width'=>'300'));

$grid_import->set_doubleclick_target_uri('backend/application/importmanager/single', 0);

if (count($smart_worksheets) > 0)
{
    $row_index = 0;
    foreach ($smart_worksheets as $smart_worksheet)
    {
        $show_row = array(
            'name' => $smart_worksheet['name'],
            'kind' => $smart_worksheet['kind'],
            'file_size' => $smart_worksheet['file_size'],
            'when_file_copied' => $smart_worksheet['when_file_copied'],
            'table_name' => $smart_worksheet['table_name'],
            'when_table_created' => __($smart_worksheet['when_table_created']),
            'status' => __($smart_worksheet['status'])
        );
        $grid_import->add_row($show_row);
        if(in_array($smart_worksheet['status'], array('backend.application.import.status.needtoimport', 'backend.application.import.status.needtoreimport'))) {
            $grid_import->add_row_format($row_index, Backend_Layout_Grid::ROW_FORMAT_RED);
        }
        if(in_array($smart_worksheet['status'], array('backend.application.import.status.isuptodate'))) {
            $grid_import->add_row_format($row_index, Backend_Layout_Grid::ROW_FORMAT_GREEN);
        }

        if(intval($smart_worksheet['file_size']) > 4000000 AND (in_array($smart_worksheet['kind'], array('XLS','XLSX'))))
        {
            $grid_import->add_row_format($row_index, Backend_Layout_Grid::ROW_FORMAT_GRAY);
        }

        $row_index++;
    }
}

Backend_Layout_Window::instance()->add_item($grid_import);

Пока это работает хорошо, нопоскольку я просто выводил код javascript построчно, чем больше функций я встраиваю в класс, тем сложнее логика if / then при построении необработанного текста Javascript, вот типичный метод , которыйгенерирует код Javascript:

public function render_main_code_block()
{
    $retval = '';

    $retval .= $this->render_data_variable();
    $retval .= $this->render_array_reader_block();
    $retval .= $this->render_grid_panel_block();


    if($this->rows_selectable)
    {
        $retval .= self::render_line("````}),");
        $retval .= self::render_line("````sm: sm,");
    }

    $retval .= self::render_line("````viewConfig: {");


    if ($this->percentage_columns)
    {
        $retval .= self::render_line("``````forceFit: true,"); // true = percentage column width (add up to 100)
    }
    else
    {
        $retval .= self::render_line("``````forceFit: false,");
    }

    $retval .= self::render_line("``````getRowClass: function(record, rowIndex, rp, ds){");
    if (count($this->row_formats) > 0)
    {
        foreach ($this->row_formats as $row_index => $row_format)
        {
            $retval .= self::render_line("````````if(rowIndex == ".$row_index."){");
            $retval .= self::render_line("``````````return '".$row_format."';");
            $retval .= self::render_line("````````}");
        }
    }
    $retval .= self::render_line("````````return '';");
    $retval .= self::render_line("``````}");
    $retval .= self::render_line("````},");

    $retval .= self::render_line("````title: '$this->title',");
    if ( ! is_null($this->width))
    {
        $retval .= self::render_line("````width: $this->width,");
    }
    $retval .= $this->render_double_click_handler();
    $retval .= self::render_line("````autoHeight: true,");
    $retval .= self::render_line("````frame: true");
    $retval .= self::render_line("``});");
    $retval .= self::render_line("");

    $retval .= self::render_line("``replaceComponentContent(targetRegion, ".$this->script_variable_name.");");
    $retval .= self::render_line("``".$this->script_variable_name.".getSelectionModel().selectFirstRow();");


    // for word wrapping in columns
    $retval .= self::render_line("``function columnWrap(val){");
    $retval .= self::render_line("````return '<div style=\"white-space:normal !important;\">'+ val +'</div>';");
    $retval .= self::render_line("``}");

    return $retval;
}

Некоторые конкретные проблемы, из-за которых этот код становится слишком сложным для обслуживания:

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

enter image description here

  • и некоторые функции (такие как добавление флажков в сетку или нет) требуют вставки кода в до четырех различных местах в коде javascript , и я могу представить, что есть функции, которые потребуют реструктуризации существующего кода, поэтому, если функция включена, окружающий код должен, например, содержаться в другом разделе объекта

Так что в какой-то момент я хочу рефакторинг так, как я создаюJavascript.

В настоящее время я вижу только один вариант , например, для создания класса CodeFactory, который содержит, например, ExtJsVariable, к которому я добавляю объекты, которые сами содержат объекты рекурсивно, объектыможет иметь тип, например, simpleArray или anonymousFunction и т. д., а затем для создания кода я бы вывел $codeFactory->render(), который дал бы мне код, основанный на всех его внутренних объектах:

enter image description here

Какие еще варианты или структуры генерации кода я мог бы использовать, чтобы сделать генерацию этого кода Javascript / ExtJS из PHP более понятной и понятной?

Ответы [ 3 ]

2 голосов
/ 28 января 2011

Лучший способ - максимально избежать динамической генерации JS и сохранить весь Javascript в статических JS-файлах (в вашем случае, скорее всего, фабрики, сборщики) И кормите их данными JSON, сгенерированными с сервера. Это серьезно улучшит структуру и значительно упростит поддержку вашего приложения. Возможно, вы захотите прочитать о фабричных и строительных шаблонах.

0 голосов
/ 27 января 2011

Я хотел бы сделать несколько предложений, так как я уже сделал кое-что из этого.

Прежде всего, переместите столько, сколько вы можете, в библиотечные классы. Во-вторых, вы можете создать структуру данных PHP и превратить ее вJSON с json_encode

И, наконец, сделайте это просто!

0 голосов
/ 27 января 2011

На самом деле, я проходил похожий способ создания кода ExtJS из PHP или, в частности, из CakePHP.

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

Тогда быстро я понимаю, что это довольно тяжело для сервера и медленно. Каждый запрос, который вы получаете, необходимо восстанавливать коды, что нецелесообразно. Вскоре после того, как я вышел со вторым поколением, со способностью кеширования. Сгенерированные JS-коды кэшируются в статические файлы и при необходимости включаются динамически. Причина кеширования заключается в том, что в большинстве случаев коды JS являются статическими, изменения - это содержимое, хранилище и т. Д.

Так что этот метод работает в течение пары месяцев, пока я, наконец, не пойму, что это не правильный путь, например,

  • TreePanel не может быть сгенерирован таким образом, особенно с динамическим меню.
  • ACL не может мешать кешированному коду
  • Не может иметь динамические столбцы в сетке
  • Мой фреймворк спроектирован плохо, поэтому мне нужно кэшировать коды, прежде чем увидеть результат - медленная разработка.
  • Трудно поддерживать, трудно позвонить. Простые вещи, такие как добавление одного конфига или удаление одного конфига, могут быть утомительными. Точно так же, как утомительно использовать FormHelper для завершения простых вещей.

Итак, я полностью переписываю свою кодовую базу, перепроектирую все, пока не придумаю эту прекрасную платформу ExtJS + CakePHP, которая:

  • Общие компоненты GridPanel / Store / View / Pagination / Editor были созданы, и с помощью простой настройки вы получаете полную REST-сетку, которая подключается к одному из контроллеров Cake. В Cake вы включаете один из специально разработанных компонентов, и всего за несколько строк кода вы создали полнофункциональную REST-сетку.
  • Специально разработанный видовой экран, обеспечивающий аналогичный внешний вид, со специально разработанной TreePanel (Меню), TabPanel (Содержание)
  • И многие другие общие полезные компоненты, упакованные вместе, такие как Wizard, FieldEditor, UserImport ... и т. Д.
  • И поскольку все они являются расширяемыми компонентами ExtJS, вы можете использовать его, расширять его, полностью настраивать его так, как вам хочется.

Извините, если вам это не кажется правильным, но лично я прошел через это, и я действительно недоволен результатом генерации кодов из PHP. Вы в конечном итоге усложняете весь процесс или замедляете процесс.

Кстати, извините за мой плохой английский. И спасибо, что прочитали это.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...