【问题标题】:What is the most maintainable approach to generating Javascript/ExtJS code from PHP?从 PHP 生成 Javascript/ExtJS 代码的最可维护的方法是什么?
【发布时间】:2011-06-16 12:47:26
【问题描述】:

我正在创建一个 PHP 框架,它允许 PHP 开发人员创建一个仅包含 PHP 类的 ExtJS 前端,例如创建网格如下所示:

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

开始让这段代码过于复杂而难以维护的一些特殊问题是:

  • 一个简单的事实,即在属性列表中,只有最后一项没有逗号。到目前为止,我已经能够将 has required 属性放在列表的末尾,以便始终包含不带逗号的项目。

  • 和一些功能(例如是否向网格中添加复选框)需要在 javascript 代码中最多四个不同的位置插入代码,我可以想象有些功能需要现有的代码要重构,所以如果开启了这个功能,周围的代码需要是eg包含在对象的另一部分中

所以在某些时候我想重构我创建 Javascript 的方式。

我目前只看到 一个选项,例如创建CodeFactory 类,其中包含例如ExtJsVariable 我递归地添加包含对象本身的对象,对象可以是例如类型simpleArrayanonymousFunction 等,然后创建代码,我将输出 $codeFactory-&gt;render(),这将为我提供基于其所有内部对象的代码:

我可以使用哪些其他选项或代码生成框架来使从 PHP 生成此 Javascript/ExtJS 代码更易于维护和直接?

【问题讨论】:

标签: php javascript extjs code-generation


【解决方案1】:

最好的方法是尽可能避免动态生成 JS 并将所有 Javascript 保存在静态 JS 文件中(最有可能是工厂、构建器)。并向他们提供从服务器生成的 JSON 数据。这极大地改进了结构,并使您的应用程序更易于维护。您可能想了解 Factory 和 Builder 模式。

【讨论】:

    【解决方案2】:

    我会提出一些建议,因为我也做过一些。

    首先,尽可能多地移动到库类中 其次,您可以创建一个 PHP 数据结构并将其转换为带有 json_encode 的 JSON

    最后保持简单!

    【讨论】:

      【解决方案3】:

      事实上,我一直在通过类似的方式从 PHP,或者特别是从 CakePHP 创建 ExtJS 代码。

      在我的公司,我负责创建应用程序框架,这将加速应用程序的生产,所以我实际上提出了我们的第一代框架,它类似于您的想法:通过 PHP 生成代码。

      然后很快我意识到这对服务器来说非常沉重,而且速度很慢。您收到的每个请求都需要重新生成代码,这是不切实际的。不久之后,我推出了第二代,具有缓存能力。生成的 JS 代码缓存到静态文件中,并在需要时动态包含。缓存的原因是因为大部分时间 JS 代码是静态的,变化的是内容、存储等。

      所以这个方法工作了几个月,直到我终于意识到这不是正确的方法,例如,

      • TreePanel不能通过这种方式生成,尤其是动态菜单。
      • ACL 无法干扰缓存代码
      • 网格中不能有动态列
      • 我的框架设计得很糟糕,我需要在看到结果之前缓存代码 - 开发缓慢。
      • 难以维护,难以调用。添加一个配置或删除一个配置等简单的事情可能很乏味。就像使用FormHelper 完成简单的事情一样乏味。

      然后我完全重写了我的代码库,重新设计了所有东西,直到我想出了这个当前漂亮的 ExtJS + CakePHP 框架,它:

      • 创建了通用 GridPanel/Store/View/Pagination/Editor 组件,只需进行一些简单的配置,您就可以获得一个完整的 REST 网格,该网格连接到 Cake 的控制器之一。在 Cake 中,您包含一个专门设计的组件,并且只需几行代码,您就创建了一个完整的工作 REST 网格。
      • 特别设计的 Viewport 提供类似的外观和感觉,并带有特别设计的 TreePanel(菜单)、TabPanel(内容)
      • 还有许多其他通用、有用的组件被打包在一起,例如 Wizard、FieldEditor、UserImport... 等。
      • 而且因为它们都是可扩展的 ExtJS 组件,所以您可以使用它、扩展它、完全自定义它以满足您的任何需求。

      很抱歉,如果您觉得这听起来不对,但我个人已经经历过这个,我对从 PHP 生成代码的结果非常不满意。你基本上最终会使整个过程复杂化,或者放慢速度。

      顺便说一句,对不起我的英语不好。感谢您阅读本文。

      我不能分享我的代码,也不能开源它,因为它是公司财产的一部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-19
        • 2011-05-19
        • 2010-09-13
        • 1970-01-01
        • 2010-09-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多