Phalcon PHP发布链接与JavaScript确认对话框

时间:2015-01-18 13:56:14

标签: post phalcon confirm

我正在CRUD(版本1.3.4)开发Phalcon PHP系统。

我的目标是创建一个链接(删除行),要求确认点击(JavaScript确认框),然后(请求类型POST)到链接。

因此,假设用户点击"删除行"按钮。

  1. JavaScript确认"您确定要删除此行吗?"
  2. 用户点击"是"
  3. 网页对" / users / delete / 1"
  4. 进行POST

    我知道CakePHP有一个函数(FormHelper::postLink())就是这样做的。

    我想知道Phalcon PHP是否也有这样的功能。

2 个答案:

答案 0 :(得分:5)

我看到了实现你想要的三种可能性。一种是在Volt模板中创建macro,其次是在View中添加一项功能。第三和最接近 - 我理解的是你的愿望 - 是extend Phalcons tag helper,这是我将在这里描述的部分。

Phalcon拥有自己的Tag助手,可以轻松创建一些元素。 postLink不是在那里实现的部分,但您可以轻松实现它。在我的示例中,我的Application命名空间的类Tag\Phalcon\Tag延伸。这是本教程的基础。

// Tag.php

namespace Application;

class Tag extends \Phalcon\Tag
{

    static public function postLink() {
        return '<strong>TEST TAG</strong>';
    }
}

要强制Phalcon DI使用此类,必须通过手动声明它作为新的DI服务来覆盖它的引擎标准声明:

// services.php
$di['tag'] = function() {
    return new \Application\Tag();
};

您可以通过在Volt模板中键入{{ tag.postLink() }}来测试它是否正常工作,如果使用phtml模板,则可以使用$this->tag->postLink()进行测试。

现在,您可以使用您希望它生成的HTML和参数填充Tag::postLink()方法:

namespace Application;

class Tag extends \Phalcon\Tag
{

    static $forms = [];

    static public function postLink($title, $url, $options = array()) {

        // random & unique form ID
        while ($randId = 'f_' . mt_rand(9000, 999999)) {
            if (!isset(self::$forms[$randId])) {
                self::$forms[$randId] = true;
                break;
            }
        }

        // dialog message
        $dialogMessage = isset($options['message']) && $options['message'] ?  $options['message'] : 'Are you sure you want to go on?';


        $html = <<<HTML

            <form action="{$url}" method="post" id="{$randId}">
                <!-- maybe not necessary part -->
                <input type="hidden" name="confirmed" value="1" />
            </form>
            <a href="#" onclick="javascript: confirm('{$dialogMessage}') ? document.forms['{$randId}'].submit() : false;">{$title}</a>

HTML;

        return $html;
    }
}

现在您可以像这样运行它:

{{ tag.postLink('delete', '/users/delete/1') }}

{% set formOptions = ['message' : 'Are you sure you want to delete user Kialia Kuliambro?'] %}
{{ tag.postLink('delete', '/users/delete/1', formOptions) }}

{{ tag.postLink('delete', '/users/delete/1', ['message' : 'Are you sure you want to delete user Kialia Kuliambro?']) }}

享受乐趣:)

答案 1 :(得分:4)

在phalcon中有几种方法可以实现这种行为。在此之前,我们需要了解视图和查看帮助程序如何在phalcon中工作。如果您密切关注,您会注意到,.volt.phtml都可以直接访问DI

例如,在伏特中,您可以访问flash服务,并通过调用以下方式输出其消息:
{{ flash.output() }} 转换为phtml:<?php echo $this->flash->output(); ?>

因此,我的解决方案专注于在DI中定义一个新的服务,伏特可以访问。在CakePHP中,postLink()的语法类似于:echo $this->Form->postLink(),而函数实际上是在名为FormHelper的类中定义的。因此,我的解决方案将执行相同的操作,定义类FormHelper,然后将其注入名称为Form的视图中。

  1. 创建app/helpers/目录。
  2. 更新您的app/config/config.php文件,添加对我们新目录的引用:'helpersDir'=> APP_PATH . '/app/helpers/'
  3. 更新app/config/loader.php文件,将$config->application->helpersDir添加到已注册的目录。
  4. 创建新文件app/helpers/FormHelper.php
  5. following代码复制粘贴到文件中:
  6. <?php
    
    use Phalcon\Tag;
    
    class FormHelper extends Tag
    {
        protected $_lastAction = '';
        public function dottedNameToBracketNotation($name)
        {
           $parts=explode('.',$name);
           $first = array_shift($parts);
           $name=$first . ($parts ? '[' . implode('][', $parts) . ']' : '');
           return $name;
        }
        protected function flatten(array $data, $separator = '.')
        {
            $result = [];
            $stack = [];
            $path = null;
            reset($data);
            while (!empty($data)) {
                $key = key($data);
                $element = $data[$key];
                unset($data[$key]);
                if (is_array($element) && !empty($element)) {
                    if (!empty($data)) {
                        $stack[] = [$data, $path];
                    }
                    $data = $element;
                    reset($data);
                    $path .= $key . $separator;
                } else {
                    $result[$path . $key] = $element;
                }
                if (empty($data) && !empty($stack)) {
                    list($data, $path) = array_pop($stack);
                    reset($data);
                }
            }
            return $result;
        }
        protected function _confirm($message, $okCode, $cancelCode = '', $options = [])
        {
            $message = json_encode($message);
            $confirm = "if (confirm({$message})) { {$okCode} } {$cancelCode}";
            if (isset($options['escape']) && $options['escape'] === false) {
                $confirm = $this->h($confirm);
            }
            return $confirm;
        }
        public function h($text, $double = true, $charset = 'UTF-8')
        {
            return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, $charset, $double);
        }
        protected function _lastAction($url)
        {
            $action = $url;//Router::url($url, true);
            $query = parse_url($action, PHP_URL_QUERY);
            $query = $query ? '?' . $query : '';
            $this->_lastAction = parse_url($action, PHP_URL_PATH) . $query;
        }
        public function postLink($title, $url = null, array $options = [])
        {
    
            $out='';
            $options += ['block' => null, 'confirm' => null];
            $requestMethod = 'POST';
            if (!empty($options['method'])) {
                $requestMethod = strtoupper($options['method']);
                unset($options['method']);
            }
            $confirmMessage = $options['confirm'];
            unset($options['confirm']);
            $formName = str_replace('.', '', uniqid('post_', true));
            $formOptions = [
                'name' => $formName,
                'style' => 'display:none;',
                'method' => 'post',
            ];
            if (isset($options['target'])) {
                $formOptions['target'] = $options['target'];
                unset($options['target']);
            }
            $formOptions[0]=$url;
            $out.=$this->form($formOptions);
            $out .= $this->hiddenField(['_method','value' => $requestMethod]);
            $fields = [];
            if (isset($options['data']) && is_array($options['data'])) {
                foreach ($this->flatten($options['data']) as $key => $value) {
                    $out .= $this->hiddenField([$this->dottedNameToBracketNotation($key),'value' => $value]);
                }
                unset($options['data']);
            }
            $out .= $this->endForm();
            //This is currently unsupported
            if ($options['block']) {
                if ($options['block'] === true) {
                    $options['block'] = __FUNCTION__;
                }
                //$this->_View->append($options['block'], $out);
                $out = '';
            }
            unset($options['block']);
            $url = '#';
            $onClick = 'document.' . $formName . '.submit();';
            if ($confirmMessage) {
                $options['onclick'] = $this->_confirm($confirmMessage, $onClick, '', $options);
            } else {
                $options['onclick'] = $onClick . ' ';
            }
            $options['onclick'] .= 'event.returnValue = false; return false;';
            $options[0]=$url;
            $options[1]=$title;
            $options[2]=false;
            $out .= $this->linkTo($options);
            return $out;
    
        }
    
    }
    1. 修改您的app/config/services.php文件并添加:
    2. $di->set('Form',function () {
      return new FormHelper();
      });

      (你可以制作&#34; Form&#34;小写如果你愿意,两者都可以工作。我把它变得更接近CakePHP的语法。注意Volt在尝试访问服务时是区分大小写但是phtml会小写它。)

      1. 编辑您要测试代码的模板,例如app/views/index/test.volt
      2. 将以下代码复制粘贴到其中:
      3. {{ Form.postLink(' Delete','',['confirm':'Are you sure you want to delete #4?','data':['a':['b','c']]]) }}

        或者对于phtml,请使用:

        <?php echo $this->form->postLink(' Delete', '', array('confirm' => 'Are you sure you want to delete #4?', 'data' => array('a' => array('b', 'c')))); ?>

        运行它,并观察它的神奇之处,只需访问地址栏中的/index/test即可呈现index / test.volt模板。 (确保在索引控制器中定义了这样的操作)

        就其他解决方案而言,您还可以使用$compiler->addFunction()使功能可用于伏特,一次使用。手册中的页面提供了$compiler->addFunction('shuffle', 'str_shuffle');的示例。您可以尝试覆盖factoryDe​​fault for&#34; tag&#34;在DI中,使用我们已经定义的扩展标记的帮助器。因此,您只需从&#34;表单&#34;更改它到&#34;标记&#34;像这样:$di->set('tag',function () {return new FormHelper();});但是,正如您所看到的,它不会使函数postLink()可用作伏特作为函数,您会注意到您仍然需要以{tag.postLink()的形式访问它{1}}。相反,所有\ Phalcon \ Tag函数实际上都是硬编码到伏特引擎中的。通过查看\Phalcon\Mvc\View\Engine\Volt\Compiler if method_exists(className, method) { let arrayHelpers = this->_arrayHelpers; if typeof arrayHelpers != "array" { let arrayHelpers = [ "link_to": true, "image": true, "form": true, "select": true, "select_static": true, "submit_button": true, "radio_field": true, "check_field": true, "file_field": true, "hidden_field": true, "password_field": true, "text_area": true, "text_field": true, "email_field": true, "date_field": true, "tel_field": true, "numeric_field": true, "image_input": true ]; let this->_arrayHelpers = arrayHelpers; } if isset arrayHelpers[name] { return "$this->tag->" . method . "(array(" . arguments . "))"; } return "$this->tag->" . method . "(" . arguments . ")"; } 类的zephir源代码,您可以清楚地看到这一点。为了您的方便,如果链接被破坏,我在这里发布了一个片段,其中显示了&#34;标签&#34;伏特中的函数实际上是硬编码的:

        \Phalcon\Tags

        所以,如果你想要&#34; hack&#34;通过扩展$compiler->addExtension(new PhpFunctionExtension());课程的一些方法,你运气不好。但是,在伏特文档页面上here,存在注册自定义扩展以使用伏特的概念。文档提供了以下示例:<?php class PhpFunctionExtension { /** * This method is called on any attempt to compile a function call */ public function compileFunction($name, $arguments) { if (function_exists($name)) { return $name . '('. $arguments . ')'; } } }
        该类的来源是:

        str_shuffle

        这将允许伏特访问您喜欢的任何功能,而无需手动注册您可能需要的所有可能功能。您可以尝试访问伏特中的$compiler->addFunction('shuffle', 'str_shuffle');进行测试,就像之前使用<body>一样,但这次无需注册。

        就其他解决方案而言,您也可以尝试将CakePHP和PhalconPHP集成在一起,并尝试从PhalconPHP调用CakePHP的视图帮助程序,但是您遇到了CakePHP无法理解您的问题您在Phalcon中配置的路由器设置。但是,如果您确定了,您可以编写CakePHP的所有路由和配置并与PhalconPHP一起运行,但我强烈反对这种绝望的解决方法。最后,如果您了解该函数的工作原理,并且您几乎不使用它,那么您可以首先对HTML进行硬编码。老实说,CakePHP的逻辑对我来说看起来并不那么合理,因为它必须用插入的表格来破坏你的HTML文档,这可能会打扰你的布局。我认为使用JavaScript动态生成表单更有意义,如果我们已经使用JavaScript,并在单击按钮时将其附加到block,然后提交我们刚刚动态创建的表单。但是,你想要一个CakePHP实现,所以我把它编码为尽可能接近他们使用的逻辑。在支持所有功能方面,例如{{1}},它并不完美,但它应该适合您的大部分需求。

        我总是可以修改我的实现,但我认为它演示了如何与从CakePHP迁移的人一起使用Phalcon。