zend form custom attribute in select option? - php

I want know how to add custom attribute for option in a select field of Zend form.
PHP:
$option_values = array("multiOptions" => array(
"US" => "United States",
"CA" => "Canada",
));
$type=array('big','small');
$option= new Zend_Form_Element_Select('option', $option_values);
HTML:
<select>
<option value='US' type='big'>United States</option>
<option value='CA' type='small'>Canada</option>
</select>
How to add this type attribute in the option?

It is not possible using ZF's implementation of Zend_Form_Element_Select. You need to create your own element. I have done something similar, here's the relevant code:
<?php
require_once 'Zend/Form/Element/Select.php';
/**
* Select, but with the possibility to add attributes to <option>s
* #author Dominik Marczuk
*/
class Zend_Form_Element_SelectAttribs extends Zend_Form_Element {
public $options = array();
public $helper = 'selectAttribs';
/**
* Adds a new <option>
* #param string $value value (key) used internally
* #param string $label label that is shown to the user
* #param array $attribs additional attributes
*/
public function addOption ($value,$label = '',$attribs = array()) {
$value = (string) $value;
if (!empty($label)) $label = (string) $label;
else $label = $value;
$this->options[$value] = array(
'value' => $value,
'label' => $label
) + $attribs;
return $this;
}
}
Put this into /library/Zend/Form/Element/SelectAttribs.php. You also need a helper to render the element. Put it into your view helpers directory, name it SelectAttribs.php as well. Here's the contents of my file:
<?php
require_once 'Zend/View/Helper/FormElement.php';
class Zend_View_Helper_SelectAttribs extends Zend_View_Helper_FormElement {
public function selectAttribs($name, $value = null, $attribs = null, $options = null, $listsep = "<br />\n") {
$info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
extract($info); // name, id, value, attribs, options, listsep, disable
// force $value to array so we can compare multiple values to multiple
// options; also ensure it's a string for comparison purposes.
$value = array_map('strval', (array) $value);
// now start building the XHTML.
$disabled = '';
if (true === $disable) {
$disabled = ' disabled="disabled"';
}
// Build the surrounding select element first.
$xhtml = '<select'
. ' name="' . $this->view->escape($name) . '"'
. ' id="' . $this->view->escape($id) . '"'
. $disabled
. $this->_htmlAttribs($attribs)
. ">\n ";
// build the list of options
$list = array();
$translator = $this->getTranslator();
foreach ($options as $opt_value => $option) {
$opt_disable = '';
if (is_array($disable) && in_array($opt_value, $disable)) {
$opt_disable = ' disabled="disabled"';
}
$list[] = $this->_build($option, $disabled);
}
// add the options to the xhtml and close the select
$xhtml .= implode("\n ", $list) . "\n</select>";
return $xhtml;
}
protected function _build($option, $disabled) {
$html = '<option';
foreach ($option as $attrib => $value) {
$html .= " $attrib=\"$value\"";
}
return $html.$disabled.">".$option['label']."</option>";
}
}
With this, you should be ready to go:
$elt = new Zend_Form_Element_SelectAttribs('whatever');
$elt->addOption($value,$label,array('attribname' => 'attribvalue'));

Using addMultiOption($value,$label) I just set the value parameter to something like:
$value = $id . '" ref="' . $ref;
and when it renders you get:
<option value="<idValue>" ref="<refValue"><labelValue></option>
Hope this helps....
Okay, value gets escaped but optionClasses does not so inside the loop that adds the addMultiOptions(val,lable) I do something like this:
$optionClasses[<val>] = 'ref_' . <val> . '" ref="' . <ref>;
and then after the loop just do a setAttrib('optionClasses',$optionClasses)
And that actually works...
I answered this for another question but could not find a way to add a comment here to reference it; It was Zend Framework addMultiOption adding custom parameters like "rel" for options

I didn't find #mingos's answer complete and had some issues with implementing setting the value. His answer helped a lot with what needed to be extended and changed however. Once I had that start the rest was pretty easy. I just extended ZF1's Select and overrode where I needed:
/**
* Select, now with abbility to specify attributes on <Option>, addMultiOption has new syntax
* #author Seth Miller
*/
class MyNamespace_Form_Element_SelectAttribs extends Zend_Form_Element_Select {
public $options = array();
public $helper = 'selectAttribs';
/**
* Add an option
*
* #param string $option
* #param string $value
* #return Zend_Form_Element_Multi
*/
public function addMultiOption($value, $label = '', $attribs = array()) {
$value = (string) $value;
if (!empty($label)) {
$label = (string) $label;
}
else {
$label = $value;
}
$this->_getMultiOptions();
if (!$this->_translateOption($value, $label)) {
$this->options[$value] = array(
'value' => $value,
'label' => $label
) + $attribs;
}
return $this;
}
/**
* Add many options at once
*
* #param array $options
* #return Zend_Form_Element_Multi
*/
public function addMultiOptions(array $options) {
foreach ($options as $optionKey => $optionProperties) {
if (is_array($optionProperties)
&& array_key_exists('key', $optionProperties)
&& array_key_exists('value', $optionProperties)
) {
if(array_key_exists('key', $optionProperties)) $optionKey = $optionProperties['key'];
$this->addMultiOption($optionKey, $optionProperties['value'], $optionProperties['attribs']);
}
else {
$this->addMultiOption($optionKey, $optionProperties);
}
}
return $this;
}
public function isValid($value, $context = null)
{
if ($this->registerInArrayValidator()) {
if (!$this->getValidator('InArray')) {
$multiOptions = $this->getMultiOptions();
$options = array();
foreach ($multiOptions as $optionKey => $optionData) {
// optgroup instead of option label
if (is_array($optionData['options'])) {
$options = array_merge($options, array_keys($optionData['options']));
}
else {
$options[] = $optionKey;
}
}
$this->addValidator(
'InArray',
true,
array($options)
);
}
}
return parent::isValid($value, $context);
}
}
And the view helper:
class MyNamespace_View_Helper_SelectAttribs extends Zend_View_Helper_FormElement {
public function selectAttribs($name, $value = null, $attribs = null, $options = null, $listsep = "<br />\n") {
$info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
extract($info); // name, id, value, attribs, options, listsep, disable
// force $value to array so we can compare multiple values to multiple
// options; also ensure it's a string for comparison purposes.
$value = array_map('strval', (array) $value);
// check if element may have multiple values
$multiple = '';
if (substr($name, -2) == '[]') {
// multiple implied by the name
$multiple = ' multiple="multiple"';
}
if (isset($attribs['multiple'])) {
// Attribute set
if ($attribs['multiple']) {
// True attribute; set multiple attribute
$multiple = ' multiple="multiple"';
// Make sure name indicates multiple values are allowed
if (!empty($multiple) && (substr($name, -2) != '[]')) {
$name .= '[]';
}
}
else {
// False attribute; ensure attribute not set
$multiple = '';
}
unset($attribs['multiple']);
}
// now start building the XHTML.
$disabled = '';
if (true === $disable) {
$disabled = ' disabled="disabled"';
}
// Build the surrounding select element first.
$xhtml = '<select'
.' name="'.$this->view->escape($name).'"'
.' id="'.$this->view->escape($id).'"'
.$multiple
.$disabled
.$this->_htmlAttribs($attribs)
.">\n ";
// build the list of options
$list = array();
$translator = $this->getTranslator();
foreach ((array) $options as $optionKey => $optionData) {
if (isset($optionData['options'])) {
$optDisable = '';
if (is_array($disable) && in_array($optionData['value'], $disable)) {
$optDisable = ' disabled="disabled"';
}
if (null !== $translator) {
$optValue = $translator->translate($optionData['value']);
}
$optId = ' id="'.$this->view->escape($id).'-optgroup-'
.$this->view->escape($optionData['value']).'"';
$list[] = '<optgroup'
.$optDisable
.$optId
.' label="'.$this->view->escape($optionData['value']).'">';
foreach ($optionData['options'] as $optionKey2 => $optionData2) {
$list[] = $this->_build($optionKey2, $optionData2, $value, $disable);
}
$list[] = '</optgroup>';
}
else {
$list[] = $this->_build($optionKey, $optionData, $value, $disable);
}
}
// add the options to the xhtml and close the select
$xhtml .= implode("\n ", $list)."\n</select>";
return $xhtml;
}
/**
* Builds the actual <option> tag
*
* #param string $value Options Value
* #param string $label Options Label
* #param array $selected The option value(s) to mark as 'selected'
* #param array|bool $disable Whether the select is disabled, or individual options are
* #return string Option Tag XHTML
*/
protected function _build($optionKey, $optionData, $selected, $disable)
{
if (is_bool($disable)) {
$disable = array();
}
$opt = '<option';
foreach ($optionData as $attrib => $attribValue) {
$opt .= ' '.$this->view->escape($attrib).'="'.$this->view->escape($attribValue).'"';
}
// selected?
if (in_array((string) $optionData['value'], $selected)) {
$opt .= ' selected="selected"';
}
// disabled?
if (in_array($optionData['value'], $disable)) {
$opt .= ' disabled="disabled"';
}
$opt .= '>' . $this->view->escape($optionData['label']) . "</option>";
return $opt;
}
}
And implementation in a form would be something like:
$selectElement = new MyNamespace_Form_Element_SelectAttribs('selectElementName');
$selectElement->addMultiOption($value, $label, array('data-custom' => 'custom data embedded in option tag.');
I hope that helps someone. Thanks.

mingos,
you forgot about setvalue method of multiselect.
you shoul add something like:
...
foreach ($options as $opt_value => $option) {
$opt_disable = '';
$opt_selected = '';
if (is_array($disable) && in_array($opt_value, $disable)) {
$opt_disable = ' disabled="disabled"';
}
if (in_array($opt_value,$value)) {
$opt_selected = ' selected="selected"';
}
$list[] = $this->_build($option, $disabled, $opt_selected);
}
...
and
protected function _build($option, $disabled, $opt_selected) {
$html = '<option';
foreach ($option as $attrib => $value) {
$html .= " $attrib=\"$value\"";
}
return $html . $disabled . $opt_selected . " foo>" . $option['label'] . "</option>";
}

You could extend / overwrite the Zend_View_Helper_FormSelect helper but the real problem is going to be getting the extra data into each option.
By default, Zend_Form_Element_Select (via Zend_Form_Element_Multi) expects two strings for each option, one for the value attribute and an optional one for the text content. You may need to create your own element to handle the extra data.

No need for custom form element at all, what u can do is:
$element->setAttrib('disable', array(1, 2, 5));
As explained at http://pietervogelaar.nl/set-attribute-on-select-option-with-zend_form/

use Zend\Form\Element;
use Zend\Form\Form;
$select = new Element\Select('language');
$select->setLabel('Which is your mother tongue?');
$select->setValueOptions([
[
'value' => '0',
'label' => 'French',
'attributes' => [
'data-locale' => 'fr'
],
],
[
'value' => '1',
'label' => 'Italian',
'disabled' => true,
],
]);
$form = new Form('language');
$form->add($select);
I found this way much easier than any of the above suggestions

Related

separate html from php comments class

I found this class for threaded comment using php and MySQL:
<?php
class Threaded_comments
{
public $parents = array();
public $children = array();
/**
* #param array $comments
*/
function __construct($comments)
{
foreach ($comments as $comment)
{
if ($comment['parent_id'] === NULL)
{
$this->parents[$comment['id']][] = $comment;
}
else
{
$this->children[$comment['parent_id']][] = $comment;
}
}
}
/**
* #param array $comment
* #param int $depth
*/
private function format_comment($comment, $depth)
{
for ($depth; $depth > 0; $depth--)
{
echo "\t";
}
echo $comment['text'];
echo "\n";
}
/**
* #param array $comment
* #param int $depth
*/
private function print_parent($comment, $depth = 0)
{
foreach ($comment as $c)
{
$this->format_comment($c, $depth);
if (isset($this->children[$c['id']]))
{
$this->print_parent($this->children[$c['id']], $depth + 1);
}
}
}
public function print_comments()
{
foreach ($this->parents as $c)
{
$this->print_parent($c);
}
}
}
this worked with this array:
$comment = array( array('id'=>1, 'parent_id'=>NULL, 'text'=>'Parent'),
array('id'=>2, 'parent_id'=>1, 'text'=>'Child'),
array('id'=>3, 'parent_id'=>2, 'text'=>'Child Third level'),
array('id'=>4, 'parent_id'=>NULL, 'text'=>'Second Parent'),
array('id'=>5, 'parent_id'=>4, 'text'=>'Second Child')
);
and for result:
$tc = new Threaded_comments($comment);
$tc->print_comments();
and result is:
Parent
Child
Child Third level
Second Parent
Second Child
this worked true But for defign comment list(html) I need to add all html code into private function format_comment($comment, $depth). this is not good way and I think need separate html from php class.
EDIT:(this is my page for show/print threaded comment)
function _comments_($id,$type){
$DB_QUERY = mySqli::f("SELECT id,user,email,message,timestamp,parent_id,rfield_1,rfield_2,rfield_3,rfield_4,rfield_5 FROM " . NEWS_COMMENTS . " LEFT JOIN " . NEWS_REVIEWS . " ON " . NEWS_COMMENTS . ".id = " . NEWS_REVIEWS . ".cid WHERE
pid = ? AND type = ? AND approved = 1 ORDER BY timestamp DESC LIMIT 12", $id, $type);
foreach($DB_QUERY as $row){
$commentdata[] = $row;
}
return $commentdata;
}
$comments_list = _comments_('125','book');
foreach($comments_list as $row){
$comments[] = array(
'id' => $row['id'],
'parent_id' => $row['parent_id'],
'name' => $row['user'],
'text' => $row['message'],
'datetime' => $row['timestamp']
);
}
$tc = new Threaded_comments($comments);
$tc->print_comments();
In my page threaded comments show with format_comment and work true. in case i need to design output using separate html from php class.
how do we separate html code from class in this case?!
You're right.
1) Most simple solution is to pass your array to a template. This template doesn't contain logic, but only html and php (e.g. foreach of your your array).
2) For beter separation, use Model-View-Controller pattern:
With this layer construction, each layer has its own responsibilities. Never html in model and controller. Queries in the models only.
Frameworks as Laravel and CodeIgniter have an implementation of this pattern.

Foreach act wierd

i try to make an simple way to create an box in a class.
The problem is , it only give me the first element in the array. I echo out the $values and i get the whole css code and i try to place them in style at div. But still get only the last element.
My currently code looks like:
class general {
public function box($content,$style,$width = 50,$height = 50) {
foreach ($style as $k => $v) {
$values = ''.$k.':'.$v.';';
echo($values);
$box = '<div class="testBox" style="'.$values.'">'.$content.'</div> ';
}
return $box;
}
}
$general = new general();
$test = array(
'background-color' => '#000',
'font-size' => '120px'
);
echo $general->box('testValue',$test);
Try like this:
public function box($content,$style,$width = 50,$height = 50) {
$values = '';
foreach ($style as $k => $v) {
$values .= ''.$k.':'.$v.';';
}
$box = '<div class="testBox" style="'.$values.'">'.$content.'</div> ';
return $box;
}
$box = '<div class="testBox" style="'.$values.'">'.$content.'</div> ';
to
$box .= '<div class="testBox" style="'.$values.'">'.$content.'</div> ';
And declare
$box = ''; outside the loop.
You need to concate the data using .

Phalcon - multiple checkboxes in forms

Basically, I need to serialize multiple checkboxes before saving them in database and unserialize before displaying the form.
<input type="checkbox" name="list[option1]" value="1">
<input type="checkbox" name="list[option2]" value="1">
<input type="checkbox" name="list[option3]" value="1">
Could someone point me to the right direction please?
I've tried the following code to generate the checkboxes, but it's not working after the request.
Selected options are not getting populated to the form (other fields are fine)
<?php
$form->bind($_POST, $entity);
....
foreach ($list as $key => $option) {
$form->add(new Check("list[$key]", array('value' => 1)));
}
I suppose the same issue exists with using multi-choice select boxes.
I think you've got a typo. Try:
<?php
$form->bind($_POST, $entity);
....
foreach ($list as $key => $option) {
$form->add(new Check($list[$key], array('value' => 1)));
}
On a side note, the Phalcon\Tag helper can be used to generate HTML.
<?php
echo Phalcon\Tag::checkField(array($list[$key], "value" => "1"));
You can using my code Fdola.com.
Use
<?php
$list_module = new \App\Vendor\Fdola\Forms\CheckBoxList('list_module', ['a' => 'A', 'b' => 'B'], ['a'], ['class' => 'checkBoxList']);
$list_module->setLabel('Module hiển thị banner:');
$list_module->addValidators([
new \Phalcon\Validation\Validator\PresenceOf([
'message' => '<b>:field</b> không được phép rỗng'
])
]);
$this->add($list_module);
<?php
/**
* Created by PhpStorm.
* User: thanhansoft
* Date: 4/29/2016
* Time: 4:21 PM
*/
namespace App\Vendor\Fdola\Forms;
use Phalcon\Http\Request;
use Phalcon\Tag;
class CheckBoxList extends \Phalcon\Forms\Element {
private $_data;
private $_dataOld;
public function __construct($name, $data, $dataOld = null, $attribute = null) {
$this->_data = $data;
$this->_dataOld = $dataOld;
parent::__construct($name, $attribute);
}
public function render($attribute = null) {
$get_value = $this->getValue();
if ($get_value) {
$data = $get_value;
} else {
$data = $this->_dataOld;
}
$tag = new Tag();
$string = '';
if ($this->_data) {
foreach ($this->_data as $key => $value) {
$arr = ['id' => $this->_name . '-' . $key, 'name' => $this->_name . '[]', 'value' => $key];
if ($data && in_array($key, $data)) {
$arr['checked'] = 'checked';
}
$string .= '<label>' . $tag::checkField($arr) . ' ' . $value . '</label>';
}
}
if (isset($this->_attributes['class'])) return '<div class="' . $this->_attributes['class'] . '">' . $string . '</div>';
return $string;
}
}

Laravel 4: Generate HTML Table Like CodeIgniter

So in CodeIgniter, there was a cool feature of creating an HTML table just by passing it an array and it handles the header, etc. Is there ANYTHING out there for Laravel, has anybody been able to use the CI version in Laravel? just asking around
There is nothing like this in Laravel AFAIK but you may create your own, something like (an idea only) this (a php class, not only for Laravel)
class Table {
protected $table = null;
protected $header = null;
protected $attr = null;
protected $data = null;
public function __construct($data = null, $attr = null, $header = null)
{
if(is_null($data)) return;
$this->data = $data;
$this->attr = $attr;
if(is_array($header)) {
$this->header = $header;
}
else {
if(count($this->data) && $this->is_assoc($this->data[0]) || is_object($this->data[0])) {
$headerKeys = is_object($this->data[0]) ? array_keys((array)$this->data[0]) : array_keys($this->data[0]);
$this->header = array();
foreach ($headerKeys as $value) {
$this->header[] = $value;
}
}
}
return $this;
}
public function build()
{
$atts = '';
if(!is_null($this->attr)) {
foreach ($this->attr as $key => $value) {
$atts .= $key . ' = "' . $value . '" ';
}
}
$table = '<table ' . $atts . ' >';
if(!is_null($this->header)) {
$table .= '<thead><tr>';
foreach ($this->header as $value) {
$table .= '<th>' . ucfirst($value) . '</th>';
}
$table .= '</thead></tr>';
}
$table .= '<tbody>';
foreach ($this->data as $value) {
$table .= $this->createRow($value);
}
$table .= '</tbody>';
$table .= '</table>';
return $this->table = $table;
}
protected function createRow($array = null)
{
if(is_null($array)) return false;
$row = '<tr>';
foreach ($array as $value) {
$row .= '<td>' . $value . '</td>';
}
$row .= '</tr>';
return $row;
}
protected function is_assoc($array){
return is_array($array) && array_diff_key($array, array_keys(array_keys($array)));
}
}
Now, you can use it as given below (An Example Here.)
$data = array(
array('name' => 'Heera', 'age'=>'35', 'address' =>'Masimpur', 'phone'=>'123456'),
array('name' => 'Usman', 'age'=>'28', 'address' =>'Kamal Gor', 'phone'=>'654321')
);
$attr = array('class'=>'tbl someClass', 'id'=>'myTbl', 'style'=>'width:400px;color:red', 'border'=>'1');
$t = new Table($data, $attr);
echo $t->build();
Or, set an header using third argument, like
$t = new Table($data, $attr, array('Known As', 'Years', 'Location', 'Contact'));
This is just an idea and could be better. Now just integrate this class with Laravel using Laravel's rule. You may extend Html class or use as an individual class by registering it as a service. Take a look at this answer for extending a class in laravel.
Try nayjest/grids Laravel package.
You could take the script drupal uses and convert it to laravel: https://api.drupal.org/api/drupal/core%21includes%21theme.inc/function/theme_table/8
Doing a quick look at it, you would just need to replace a couple of functions:
Attributes()... I think laravel has something like this you could use. Drupal 8 is using something from symfony2 I think... laravel might be using the same thing.
_theme_table_cell(), tablesort_header(), etc... These type of functions have drupal_render() in them... you don't want to try and port that over... so you probably just delete that from the functions (untested) as it doesn't make sense in the context of laravel .
This would make for a very nice implementation of what your looking for.
EDIT: I also just ran into this: http://kohana.keyframesandcode.com/docs/modules/table/ I've not tested it but it was referenced here: http://forumsarchive.laravel.io/viewtopic.php?id=2178

PHP function to build query string from array

I'm looking for the name of the PHP function to build a query string from an array of key value pairs. Please note, I am looking for the built in PHP function to do this, not a homebrew one (that's all a google search seems to return). There is one, I just can't remember its name or find it on php.net. IIRC its name isn't that intuitive.
You're looking for http_build_query().
Here's a simple php4-friendly implementation:
/**
* Builds an http query string.
* #param array $query // of key value pairs to be used in the query
* #return string // http query string.
**/
function build_http_query( $query ){
$query_array = array();
foreach( $query as $key => $key_value ){
$query_array[] = urlencode( $key ) . '=' . urlencode( $key_value );
}
return implode( '&', $query_array );
}
Just as addition to #thatjuan's answer.
More compatible PHP4 version of this:
if (!function_exists('http_build_query')) {
if (!defined('PHP_QUERY_RFC1738')) {
define('PHP_QUERY_RFC1738', 1);
}
if (!defined('PHP_QUERY_RFC3986')) {
define('PHP_QUERY_RFC3986', 2);
}
function http_build_query($query_data, $numeric_prefix = '', $arg_separator = '&', $enc_type = PHP_QUERY_RFC1738)
{
$data = array();
foreach ($query_data as $key => $value) {
if (is_numeric($key)) {
$key = $numeric_prefix . $key;
}
if (is_scalar($value)) {
$k = $enc_type == PHP_QUERY_RFC3986 ? urlencode($key) : rawurlencode($key);
$v = $enc_type == PHP_QUERY_RFC3986 ? urlencode($value) : rawurlencode($value);
$data[] = "$k=$v";
} else {
foreach ($value as $sub_k => $val) {
$k = "$key[$sub_k]";
$k = $enc_type == PHP_QUERY_RFC3986 ? urlencode($k) : rawurlencode($k);
$v = $enc_type == PHP_QUERY_RFC3986 ? urlencode($val) : rawurlencode($val);
$data[] = "$k=$v";
}
}
}
return implode($arg_separator, $data);
}
}
Implode will combine an array into a string for you, but to make an SQL query out a kay/value pair you'll have to write your own function.

Categories