我可以找到一些 Twitter Bootstrap 2.x 插件,其中包含 CakePHP 2.x 的一些帮助程序,但我找不到 CakePHP 1.3.x。
https://github.com/slywalker/TwitterBootstrap
https://github.com/loadsys/twitter-bootstrap-helper
这两个插件非常酷,但仅适用于 CakePHP 2.x。
CakePHP 1.3.x 有插件吗?
我可以找到一些 Twitter Bootstrap 2.x 插件,其中包含 CakePHP 2.x 的一些帮助程序,但我找不到 CakePHP 1.3.x。
https://github.com/slywalker/TwitterBootstrap
https://github.com/loadsys/twitter-bootstrap-helper
这两个插件非常酷,但仅适用于 CakePHP 2.x。
CakePHP 1.3.x 有插件吗?
不,不会有。CakePHP 1.3 是旧的,而 Twitter Bootstrap 2.x 是新的。几乎没有人再用 1.3 创建新项目了,所以没有人会觉得有必要为它创建新项目的插件。
如果您使用 Twitter Bootstrap 启动一个新项目,请改用 Cake 2.x。它更好更快。
我为 Cake 2.0 移植了一个 Twitter Bootstrap 助手。它不是插件,而是助手,只需将它放在一个名为app/views/helpers/t_b_s.php
. 在您看来,替换所有$this->Form->input()
对$this->TBS->input()
. 此方法是我在生产应用程序中测试和使用的唯一方法。
此方法将自动或显式创建许多表单控件类型。'type' 选项可以是:text、textarea、textdate(使用 jquery.calendar 插件的文本输入)、checkbox、select、radioGroup(您通过 'selectOptions' 属性传递具有有效选项的数组)。您可以使用选项 'prepend'、'append'、'ly_w'=>[1,2,3,4](布局宽度:这会将 .spanN 类添加到您的控件中)
此外,默认情况下,“maxlength”属性是通过查询数据库元数据来设置的。但是,如果您设置了模型的 $_schema 属性,它将使用那里指定的长度(您可以只在属性的数组中放入您想要严格控制最大长度的字段)。Flash 和 Flashes 方法也可以使用,您可以使用它们在布局/元素中替换它们。
顺便说一句:我很想从 1.3 迁移到 2,但是我遇到了 dbo_firebird 数据源的问题。我从 github 的驱动程序开始,但我已经编程和修补了很多东西,例如我会在适当的线程上寻求一些帮助。
<?php
/**
* Helper to generate Twitter's Bootstrap UI interface controls and styles.
* Based on the code from Joey Trapp
*
* @author Lev A Gutierrez
*
*/
/**
* Helper that captures the Session flash and renders it in proper html
* for the twitter bootstrap alert-message styles.
*
* @author Joey Trapp
*
*/
class TBSHelper extends AppHelper {
/**
* Helpers available in this helper
*
* @var array
* @access public
*/
public $helpers = array("Form", "Html", "Ajax", "Session", 'Number', 'Time', 'Text');
// Confirm Replacement
/**
* Creates an HTML link.
*
* If $url starts with "http://" this is treated as an external link. Else,
* it is treated as a path to controller/action and parsed with the
* HtmlHelper::url() method.
*
* If the $url is empty, $title is used instead.
*
* ### Options
*
* - `escape` Set to false to disable escaping of title and attributes.
*
* @param string $title The content to be wrapped by <a> tags.
* @param mixed $url Cake-relative URL or array of URL parameters, or external URL (starts with http://)
* @param array $options Array of HTML attributes.
* @param string $confirmMessage JavaScript confirmation message.
* @return string An `<a />` element.
* @access public
* @link http://book.cakephp.org/view/1442/link
*/
function link($title, $url = null, $options = array(), $confirmMessage = false) {
$escapeTitle = true;
if ($url !== null) {
$url = $this->url($url);
} else {
$url = $this->url($title);
$title = $url;
$escapeTitle = false;
}
if (isset($options['escape'])) {
$escapeTitle = $options['escape'];
}
if ($escapeTitle === true) {
$title = h($title);
} elseif (is_string($escapeTitle)) {
$title = htmlentities($title, ENT_QUOTES, $escapeTitle);
}
if (!empty($options['confirm'])) {
$confirmMessage = $options['confirm'];
unset($options['confirm']);
}
if ($confirmMessage) {
$confirmMessage = str_replace("'", "\'", $confirmMessage);
$confirmMessage = str_replace('"', '\"', $confirmMessage);
$options['onclick'] = "return bootbox.confirm('{$confirmMessage}');";
} elseif (isset($options['default']) && $options['default'] == false) {
if (isset($options['onclick'])) {
$options['onclick'] .= ' event.returnValue = false; return false;';
} else {
$options['onclick'] = 'event.returnValue = false; return false;';
}
unset($options['default']);
}
return sprintf($this->Html->tags['link'], $url, $this->_parseAttributes($options), $title);
}
/**
* Takes an array of options to output markup that works with
* twitter bootstrap forms.
*
* @param array $options
* @access public
* @return string
*/
public function input($field, $options = array()) {
// Checkout how the input parameters are given
if (is_array($field)) {
$options = $field;
$field = $options['field'];
} else {
$options["field"] = $field;
}
if (!isset($field)) { return ''; }
$out = $theGroup = $theHelp = $theLabel = $theControl = $theError = $help_inline = $help_block = $theStyleClass = $theScripts = $thePrependAppendClass = $theSelectOptions = '';
// Default options, etc...
if(isset($options['type']))
$theType=$options['type'];
$defaults = array(
'help_inline' => '',
'help_block' => '',
);
// $options = array_merge($defaults, $options);
// Determine both model and field parameters
$theModel = ucfirst($this->Form->defaultModel);
$split = explode(".", $options["field"]);
if($split && sizeof($split)>1) {
$theModel = ucfirst($split[0]);
$theField = ucfirst($split[1]);
}
else {
$theField = ucfirst($split[0]);
}
$options['field'] = $theModel.(!empty($theModel)?'.':'').$theField;
// Introspects the Model to get field's info
if (!isset($this->Form->fieldset[$theModel])) {
$this->Form->_introspectModel($theModel);
}
// Get the field's metadata into the theFieldMeta variable
if( isset($this->Form->fieldset) &&
array_key_exists($theModel, $this->Form->fieldset) &&
array_key_exists('fields', $this->Form->fieldset[$theModel])
) {
$theFieldMeta=$this->Form->fieldset[$theModel]['fields'][strtolower($theField)];
}
// If the field's type is text or String,
// then set the MaxLength option when it is not passed by parameter.
if(!array_key_exists('maxlength', $options) &&
isset($theFieldMeta['length']) &&
isset($theFieldMeta['type']) &&
($theFieldMeta['type']=='text' || $theFieldMeta['type']=='string')
) {
$options['maxlength']=$theFieldMeta['length'];
}
// Generate a Label for the Control
if (!isset($options['label']) || $options['label'] === false) {
$options['label'] = '';
} else if (!empty($options['label'])) {
$theLabel = '<label for="'.$theModel.$theField.'" class="control-label">'.$options['label'].'</label>';
} else {
if(!isset($options['label']))
$theLabel = '<label for="'.$theModel.$theField.'" class="control-label">'.$theField.'</label>';
}
$options['label']=false;
// Generate the extra Prepend/Appended content
if (!empty($options['prepend'])) {
$thePrepend=$this->Html->tag('span',$options['prepend'], array('class'=>'add-on'));
$options['prepend']=null;
$thePrependAppendClass="input-prepend";
}
if (!empty($options["append"])) {
$theAppend=$this->Html->tag("span",$options['append'], array('class'=>'add-on'));
$options['append']=null;
$thePrependAppendClass.="input-append";
}
// generate the error...
list($help_inline, $help_block) = $this->_help_markup($options);
// generate the error message for the input field, if any...
if ($this->Form->error($field)) {
// echo WCR.WCR."Error-${field}::".$this->Form->error($field);
$theError=$this->Form->error($field);
$help_block = $this->Html->tag(
"span",
str_replace(array('<div class="error-message">','</div>'),'',$this->Form->error($field)),
array("class" => "help-inline")
);
}
// Get the control's layout width and define the control's style class
if(isset($options['class'])) $theStyleClass=trim($options['class']);
if(isset($options['ly_w'])) {
$theStyleClass.=' span'.$options['ly_w'];
$options['ly_w']=null;
}
$options['class']=trim($theStyleClass);
if(isset($options['type']) && $options['type']=='textdate') {
$options['type']='text';
$theScripts.=' $(\'#'.$theModel.'.'.$options['field'].'\').datepicker({ dateFormat: \'yy-mm-dd\'});';
// $options['dateFormat'] = 'DMY';
}
// generate the form's input control (main thing)
//
$options['div']=false;
if(isset($options['type']) && $options['type']=='radiogroup') {
$theSelectOptions=$options['selectOptions'];
$options['selectOptions']=null;
$theControl = $this->Form->radio($field, $theSelectOptions, array('label'=>'','legend'=>'','div'=>false));
}
else {
if(isset($this->data[$theModel][strtolower($theField)]) &&
!empty($this->data[$theModel][strtolower($theField)]) &&
is_numeric(trim($this->data[$theModel][strtolower($theField)])) &&
trim($this->data[$theModel][strtolower($theField)])<>'' &&
!is_integer(trim($this->data[$theModel][strtolower($theField)]))
)
if(isset($options['format']) ) {
if($options['format']==='currency') {
$options['value']=$this->Number->currency(trim($this->data[$theModel][strtolower($theField)]), array('places'=>'2'));
}
if($options['format']==='integer') {
$options['value']=$this->Number->format(trim($this->data[$theModel][strtolower($theField)]), array('places'=>'0'));
}
}
$theControl = $this->Form->input($field, $options);
}
// clean the error message, if any.
$theControl = str_replace($this->Form->error($field),'',$theControl);
/*
if(stristr('type="text"',$theControl) ) {
str_ireplace('type="text"', 'type="text" maxlength="'..'"');
}
*/
// create the prepend-append div
if(!empty($thePrepend) || !empty($theAppend)) {
$controlGroup = $this->Html->tag(
"div",
(!empty($thePrepend)?$thePrepend:'').
$theControl.
(!empty($theAppend)?$theAppend:''),
array("class" => $thePrependAppendClass));
}
else {
$controlGroup = $theControl;
}
// control's div
$controlGroup = $this->Html->tag(
"div",
$controlGroup.
$help_inline.$help_block,
array("class" => "controls input".(isset($options['multiple'])?' multiple-input':''))
);
if(!empty($theScripts)) {
$theScripts='<script>'.$theScripts.'</script>';
}
// final control-group div. Set the field's style here.
$controlGroup = $this->Html->tag(
"div",
$theLabel.$controlGroup.$theScripts,
array("class" => "control-group".(!empty($theError)?' error':''))
);
return $controlGroup."\n";
}
/**
* Takes the options from the input method and returns an array of the
* inline help and inline block content wrapped in the appropriate markup.
*
* @param mixed $options
* @access public
* @return string
*/
public function _help_markup($options) {
$help_markup = array("help_inline" => "", "help_block" => "");
foreach (array_keys($help_markup) as $help) {
if (isset($options[$help]) && !empty($options[$help])) {
$help_class = str_replace("_", "-", $help);
$help_markup[$help] = $this->Html->tag(
"span",
$options[$help],
array("class" => $help_class)
);
}
}
return array_values($help_markup);
}
/**
* Outputs a list of radio form elements with the proper
* markup for twitter bootstrap styles
*
* @param array $options
* @access public
* @return string
*/
public function radio($field, $options = array()) {
if (is_array($field)) {
$options["field"] = $field;
} else {
$options = $field;
}
if (!isset($options["options"]) || !isset($options["field"])) { return ""; }
$opt = $options["options"];
$options["options"]=null;
$inputs = "";
foreach ($opt as $key => $val) {
$input = $this->Form->radio(
$options["field"],
array($key => $val),
array("label" => false)
);
$id = array();
preg_match_all("/id=\"[a-zA-Z0-9_-]*\"/", $input, $id);
if (isset($id[0][1]) && !empty($id[0][1])) {
$id = $id[0][1];
$id = substr($id, 4);
$id = substr($id, 0, -1);
$input = $this->Html->tag("label", $input, array("for" => $id));
}
$inputs .= $this->Html->tag("li", $input);
}
$options["input"] = $this->Html->tag("ul", $inputs, array("class" => "inputs-list"));
return $this->input($options);
}
/**
* Wraps the form button method and just applies the Bootstrap classes to the button
* before passing the options on to the FormHelper button method.
*
* @param string $value
* @param array $options
* @access public
* @return string
*/
public function button($value = "Submit", $options = array()) {
$options = $this->button_options($options);
return $this->Form->button($value, $options);
}
/**
* Wraps the html link method and applies the Bootstrap classes to the options array
* before passing it on to the html link method.
*
* @param mixed $title
* @param mixed $url
* @param array $options
* @param mixed $confirm
* @access public
* @return string
*/
public function button_link($title, $url, $options = array(), $confirm = false) {
$options = $this->button_options($options);
return $this->Html->link($title, $url, $options, $confirm);
}
/**
* Wraps the postLink method to create post links that use the bootstrap button
* styles.
*
* @param mixed $title
* @param mixed $url
* @param array $options
* @param mixed $confirm
* @access public
* @return string
*/
public function button_form($title, $url, $options = array(), $confirm = false) {
$options = $this->button_options($options);
return $this->Form->postLink($title, $url, $options, $confirm);
}
/**
* Takes the array of options from $this->button or $this->button_link and returns
* the modified array with the bootstrap classes
*
* @param mixed $options
* @access public
* @return string
*/
public function button_options($options) {
$valid_styles = array("danger", "info", "primary", "success");
$valid_sizes = array("small", "large");
$style = isset($options["style"]) ? $options["style"] : "";
$size = isset($options["size"]) ? $options["size"] : "";
$disabled = isset($options["disabled"]) ? (bool)$options["disabled"] : false;
$class = "btn";
if (!empty($style) && in_array($style, $valid_styles)) { $class .= " {$style}"; }
if (!empty($size) && in_array($size, $valid_sizes)) { $class .= " {$size}"; }
if ($disabled) { $class .= " disabled"; }
unset($options["style"]);
unset($options["size"]);
unset($options["disabled"]);
$options["class"] = isset($options["class"]) ? $options["class"] . " " . $class : $class;
return $options;
}
/**
* Delegates to the HtmlHelper::getCrumbList() method and sets the proper class for the
* breadcrumbs class.
*
* @param array $options
* @access public
* @return string
*/
public function breadcrumbs($options = array()) {
return $this->getCrumbList(array_merge(array("class" => "breadcrumb"), $options));
}
/**
* Delegates to the HtmlHelper::addCrumb() method.
*
* @param mixed $title
* @param mixed $link
* @param array $options
* @access public
* @return string
*/
public function add_crumb($title, $url, $options = array()) {
return $this->Html->addCrumb($title, $url, $options);
}
/**
* Creates a Bootstrap label with $messsage and optionally the $type. Any
* options that could get passed to HtmlHelper::tag can be passed in the
* third param.
*
* @param string $message
* @param string $type
* @param array $options
* @access public
* @return string
*/
public function label($message = "", $style = "", $options = array()) {
$class = "label";
$valid = array("success", "important", "warning", "notice");
if (!empty($style) && in_array($style, $valid)) {
$class .= " {$style}";
}
if (isset($options["class"]) && !empty($options["class"])) {
$options["class"] = $class . " " . $options["class"];
} else {
$options["class"] = $class;
}
return $this->Html->tag("span", $message, $options);
}
/**
* Renders alert markup and takes a style and closable option
*
* @param mixed $content
* @param array $options
* @access public
* @return void
*/
public function alert($content, $options = array()) {
$close = "";
if ((isset($options['closable']) && $options['closable']) || !isset($options['closable']) ||true) {
$close = '<a href="#" class="close" data-dismiss="alert">x</a>';
}
$style = isset($options["style"]) ? $options["style"] : "flash";
$types = array("info", "success", "error", "warning");
if ($style === "flash") {
$style = "info";
}
if (strtolower($style) === "auth") {
$style = "error";
}
if (!in_array($style, array_merge($types, array("auth", "flash")))) {
$style = "error";
}
$class = "alert alert-{$style}";
return $this->Html->tag(
'div',
'<h4 class="alert-heading">'.$style.'!</h4>'.
"{$close}<p>{$content}</p>",
array("class" => $class)
);
}
/**
* Captures the Session flash if it is set and renders it in the proper
* markup for the twitter bootstrap styles. The default key of "flash",
* gets translated to the warning styles. Other valid $keys are "info",
* "success", "error". The $key "auth" with use the error styles because
* that is when the auth form fails.
*
* @param string $key
* @param $options
* @access public
* @return string
*/
public function flash($key = "flash", $options = array()) {
$content = $this->_flash_content($key);
if (empty($content)) { return ''; }
$close = false;
if ((isset($options['closable']) && $options['closable'])) {
$close = true;
}
return $this->alert($content, array("style" => $key, "closable" => $close));
}
/**
* By default it checks $this->flash() for 5 different keys of valid
* flash types and returns the string.
*
* @param array $options
* @access public
* @return string
*/
public function myflashes($options = array()) {
if (!isset($options["keys"]) || !$options["keys"]) {
$options["keys"] = array("info", "success", "error", "warning", "flash");
}
if (isset($options["auth"]) && $options["auth"]) {
$options["keys"][] = "auth";
unset($options["auth"]);
}
$keys = $options["keys"];
unset($options["keys"]);
$out = '';
foreach($keys as $key) {
$thisFlash=$this->_flash_content($key);
if(!empty($thisFlash)) {
if($key=='default') {
$out.='<div id="flashMessage" class="alert alert-info">
<a class="close" data-dismiss="alert">×</a>
<h4 class="alert-heading">Atencion !</h4>
<p>'.
$thisFlash.'
</p>
</div>';
}
else {
$out.=$thisFlash;
}
}
}
return $out;
}
/**
* By default it checks $this->flash() for 5 different keys of valid
* flash types and returns the string.
*
* @param array $options
* @access public
* @return string
*/
public function flashes($options = array()) {
if (!isset($options["keys"]) || !$options["keys"]) {
$options["keys"] = array("info", "success", "error", "warning", "flash");
}
if (isset($options["auth"]) && $options["auth"]) {
$options["keys"][] = "auth";
unset($options["auth"]);
}
$keys = $options["keys"];
unset($options["keys"]);
$out = '';
foreach($keys as $key) {
$out .= $this->flash($key, $options);
}
return $out;
}
/**
* Create a text field with Autocomplete.
*
* Creates an autocomplete field with the given ID and options.
*
* options['with'] defaults to "Form.Element.serialize('$field')",
* but can be any valid javascript expression defining the additional fields.
*
* @param string $field DOM ID of field to observe
* @param string $url URL for the autocomplete action
* @param array $options Ajax options
* @return string Ajax script
* @link http://book.cakephp.org/view/1370/autoComplete
*/
function autoComplete($field, $url = "", $options = array()) {
$out=$this->Ajax->autocomplete($field, $url, $options);
return $out;
}
/**
* Returns the content from SessionHelper::flash() for the passed in
* $key.
*
* @param string $key
* @access public
* @return void
*/
public function _flash_content($key = "flash") {
return $this->Session->flash($key, array("element" => null));
}
/**
* Displays the alert-message.block-messgae div's from the twitter
* bootstrap.
*
* @param string $message
* @param array $links
* @param array $options
* @access public
* @return string
*/
public function block($message = null, $options = array()) {
$style = "warning";
$valid = array("warning", "success", "info", "error");
if (isset($options["style"]) && in_array($options["style"], $valid)) {
$style = $options["style"];
}
$class = "alert-message block-message {$style}";
$close = $links = "";
if (isset($options["closable"]) && $options["closable"]) {
$close = '<a href="#" class="close">x</a>';
}
if (isset($options["links"]) && !empty($options["links"])) {
$links = $this->Html->tag(
"div",
implode("", $options["links"]),
array("class" => "alert-actions")
);
}
return $this->Html->tag("div", $close.$message.$links, array("class" => $class));
}
}
?>
没有插件,但在您的项目中安装并不是特别难。将样式表添加到 CSS 文件夹,将 JavaScript 添加到 js,将字形图标添加到 img。从您的布局中调用它们并开始更新所有视图中的 CSS 类。这种 CSS 类的手动更新是永远不会有插件的原因。
如果您想查看一个集成了 Bootstrap 的特别出色的 Cake 2.x 项目,请查看 CakeStrap。您也许可以从中复制 View 文件夹并将其调整为 1.3 的命名约定。
您仍然可以将 cakephp 1.3 与 bootstrap 3.0 一起使用。
<style>
.form-control {width:auto}
</div>
<?php
echo $this->Form->create('YourForm',array(
'inputDefaults'=>array(
'label' => array(
'class' => 'col col-md-4 control-label'
),
'div' => 'form-group',
'wrapInput' => 'col col-md-8',
'class' => 'form-control'
),
'class'=>'form-horizontal',
)); ?>
<div class='col-md-12'>
//your form control here
</div>
<?php echo $this->Form->end(__('', false)); ?>