我正在CRUD(版本1.3.4)开发Phalcon PHP系统。
我的目标是创建一个链接(删除行),要求确认点击(JavaScript确认框),然后(请求类型POST)到链接。
因此,假设用户点击"删除行"按钮。
我知道CakePHP有一个函数(FormHelper::postLink())就是这样做的。
我想知道Phalcon PHP是否也有这样的功能。
答案 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
的视图中。
app/helpers/
目录。app/config/config.php
文件,添加对我们新目录的引用:'helpersDir'=> APP_PATH . '/app/helpers/'
app/config/loader.php
文件,将$config->application->helpersDir
添加到已注册的目录。app/helpers/FormHelper.php
<?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;
}
}
app/config/services.php
文件并添加:$di->set('Form',function () {
return new FormHelper();
});
(你可以制作&#34; Form&#34;小写如果你愿意,两者都可以工作。我把它变得更接近CakePHP的语法。注意Volt在尝试访问服务时是区分大小写但是phtml会小写它。)
app/views/index/test.volt
{{ 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');
的示例。您可以尝试覆盖factoryDefault 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。