Zend_Form Creation for Propel Objects - zend-framework

I'm currently working on a project where I use Zend Framework with Propel.
I'm looking for something that'll create Zend_Forms for Propel objects, preferably in a similar way to django's modelforms
Is there anything out there that does this already, and if not, what would be the best way to go about creating something like this?

One of my colleagues has provided the following as a "starting place"
<?php
class TestController extends Zend_Controller_Action
{
public function indexAction()
{
$product_table = ProductPeer::getTableMap();
$product_columns = $product_table->getColumns();
$elements = array();
foreach($product_columns as $col_name => $col_data)
{
$col_name = ucwords(str_replace('_', ' ', strtolower($col_name)));
switch($col_data->getType())
{
case 'TINYINT':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'SMALLINT':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'INTEGER':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'FLOAT':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'DOUBLE':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'VARCHAR':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'DECIMAL':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'LONGVARCHAR':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'DATE':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
case 'TIMESTAMP':
$element = new Zend_Form_Element_Text(
$col_name,
array(
'label' => $col_name
)
);
break;
default:
die("Unknown colum type: " . $col_data->getType());
}
$elements[] = $element;
echo $element;
}
die("END");
}
}

Related

Drupal programatically create a form with a for condition

I'm trying to create a form to create a person, and this person can have some relation with another one (like a wife, husband, child, ..), so I try to create something with a button to add a relation, here is my code :
if (empty($form_state['number_liaisons'])) {
$form_state['number_liaisons'] = 1;
}
$form['info_contact']['liaison'] = array(
"#type" => "fieldset",
"#title" => "Liaisons",
"#attributes" => array("class" => array("center"))
);
for ($i = 1; $i <= $form_state['number_liaisons']; $i++) {
$form['info_contact']['liaison'][$i] = array(
"#type" => "fieldset",
"#title" => "Liaison",
"#attributes" => array("class" => array("center"))
);
$form['info_contact']['liaison'][$i]['contact'] = array(
'#type' => 'textfield',
'#title' => t("Personne a lier"),
'#autocomplete_path' => 'crm/autocomplete_liaison',
);
$form['info_contact']['liaison'][$i]['type'] = array(
'#type' => 'select',
'#title' => t("Type de liaison"),
'#options' => Array('enfant' => 'Enfant', 'conjoint' => 'conjoint'),
'#empty_option' => t('- Choisir un type de liaison -'),
);
}
$form['info_contact']['liaison']['add_item'] = array(
'#type' => 'submit',
'#value' => t('Add liaison'),
'#submit' => array('liaison_add_item'),
'#limit_validation_errors' => array(),
);
if ($form_state['number_liaisons'] > 1) {
$form['info_contact']['liaison'] = array(
'#type' => 'submit',
'#value' => t('Remove liaison'),
'#submit' => array('liaison_remove_item'),
'#limit_validation_errors' => array(),
);
}
And the two methods to add / remove a relation :
function liaison_add_item($form, &$form_state)
{
$form_state['number_liaisons']++;
$form_state['rebuild'] = true;
}
function liaison_remove_item($form, &$form_state)
{
if ($form_state['number_liaisons'] > 1) {
$form_state['number_liaisons']--;
}
$form_state['rebuild'] = true;
}
My problem is that when I click on the "Add liaison" button all the fields disappear, and when I click on the remove liaison the fields came back.
So when I have more than 1 in my $form_state['number_liaisons'] the for doesn't show my fields.
Anyone know how to fix that?
I think it's because the liaisons all share the same field name, the $form_state doesn't really care if they are nested. So try renaming to something like;
["contact_{$i}"] rather than just ['contact']

Codeigniter form validation returns all errors if file is too big

I have a controller method that checks for post data and parses this through form_validation run method. There is also an image upload field in my view where an image can be uploaded.
The problem is that when a file gets uploaded which is way too big, let's say over 10MB, the form validation will return every single error defined in my validation rules.
If i upload a file which is still too big, but not too much, i will get the correct error message back.
My code looks like this:
public function addVacancy()
{
$this->is_logged_in();
//Check if user has correct permission to access this page
$aclConfig = array('userID' => $this->auth_user_id);
$this->load->library('acl', $aclConfig);
$redirect_protocol = USE_SSL ? 'https' : NULL;
if (!empty($this->auth_user_id)) {
if ( $this->acl->hasPermission("create_vacancy") ) {
//If the value is filled in we know it is an admin creating a vacancy for an organisation, we also set a boolean so we show a bit different message in confirmation.php
$orgId = $this->input->post('orgid');
if (empty($orgId)) {
$orgId = $this->userRoles_model->getOrgUserId($this->auth_user_id);
} else {
$adminEditing = TRUE;
}
$vacancyId = null;
$data = null;
if (strlen($this->input->post('occupancy')) != 1) {
$occupancy = 3;
} else {
$occupancy = $this->input->post('occupancy');
}
$vacancy_data = [
'org_id' => $orgId,
'offer' => $this->input->post('offer'),
'name' => $this->input->post('title'),
'website' => $this->input->post('website'),
'description' => $this->input->post('vacdescription'),
'address_line_1' => $this->input->post('route'),
'address_line_2' => $this->input->post('street_number'),
'address_postal_code' => $this->input->post('postalcode'),
'address_city' => $this->input->post('city'),
'address_country' => $this->input->post('country'),
'number_required' => $this->input->post('count'),
'engagement' => $this->input->post('time'),
'occupancy_kind' => $occupancy,
'create_time' => date('Y-m-d H:i:s'),
'accessibility' => $this->input->post('vacaccessibility'),
'status' => 0
];
$dates_data = [
'fullvacancydate' => $this->input->post('daterange-vacancy')
];
if (!empty($dates_data['fullvacancydate'])) {
$splitfromandto = explode(" - ", $dates_data['fullvacancydate']);
$vacancy_data['vacancy_start_date'] = date( 'Y-m-d', strtotime($splitfromandto[0]));
$vacancy_data['vacancy_end_date'] = date( 'Y-m-d', strtotime($splitfromandto[1]));
} else {
$today = date('Y-m-d');
$todayPlus6Months = date('Y-m-d', strtotime("+6 months", strtotime($today)));
$vacancy_data['vacancy_start_date'] = $today;
$vacancy_data['vacancy_end_date'] = $todayPlus6Months;
}
$contactId = $this->input->post('contactpersons');
if ($contactId == 0) {
$contact_data = [
'org_id' => $orgId,
'family_name' => $this->input->post('family_name'),
'first_name' => $this->input->post('first_name'),
'email' => $this->input->post('email'),
'phone' => $this->input->post('phone'),
'function' => $this->input->post('function')
];
}else{
$contact_data = (array) $this->orgContacts_model->get($contactId);
}
$this->load->library('form_validation');
$validation_data = array_merge($vacancy_data, $contact_data);
$this->form_validation->set_data($validation_data);
$validation_rules = [
[
'field' => 'offer',
'label' => 'offer',
'rules' => 'trim|required',
'errors' => ['required' => 'Wat heb je te bieden is verplicht.']
],
[
'field' => 'name',
'label' => 'name',
'rules' => 'trim|required',
'errors' => ['required' => 'Naam is verplicht.']
],
[
'field' => 'description',
'label' => 'description',
'rules' => 'trim|required',
'errors' => ['required' => 'Beschrijving is verplicht.']
],
[
'field' => 'address_postal_code',
'label' => 'address_postal_code',
'rules' => 'trim|required',
'errors' => ['required' => 'Postcode is verplicht.']
],
[
'field' => 'address_city',
'label' => 'address_city',
'rules' => 'trim|required',
'errors' => ['required' => 'Stad of gemeente is verplicht.']
],
[
'field' => 'address_country',
'label' => 'address_country',
'rules' => 'trim|required',
'errors' => ['required' => 'Land is verplicht.']
],
[
'field' => 'number_required',
'label' => 'number_required',
'rules' => 'trim|required',
'errors' => ['required' => 'Aantal vrijwilligers is verplicht.']
],
[
'field' => 'occupancy_kind',
'label' => 'occupancy_kind',
'rules' => 'trim|required',
'errors' => ['required' => 'Bezetting is verplicht.']
],
[
'field' => 'family_name',
'label' => 'family_name',
'rules' => 'trim|required',
'errors' => ['required' => 'Familie naam van de contactpersoon is verplicht.']
],
[
'field' => 'first_name',
'label' => 'first_name',
'rules' => 'trim|required',
'errors' => ['required' => 'Voornaam van de contactpersoon is verplicht.']
],
[
'field' => 'email',
'label' => 'email',
'rules' => 'trim|required',
'errors' => ['required' => 'Email van de contactpersoon is verplicht.']
],
[
'field' => 'phone',
'label' => 'phone',
'rules' => 'trim|required',
'errors' => ['required' => 'Telefoonnummer van de contactpersoon is verplicht.']
],
[
'field' => 'function',
'label' => 'function',
'rules' => 'trim|required',
'errors' => ['required' => 'Functie van de contactpersoon is verplicht.']
],
];
$this->form_validation->set_rules($validation_rules);
if ($this->form_validation->run()) {
// Create new contact
if ($contactId == 0) {
$contactId = $this->orgContacts_model->add($contact_data);
}
// Create vacancy
$this->load->model('vacancy/vacancy_model');
// Var to check
$check = false;
$isNoImageChosen = false;
if(isset($_FILES['userfile']['name']) && is_uploaded_file($_FILES['userfile']['tmp_name'])) {
// Banner Upload
$config['upload_path'] = VACANCY_IMAGES;
$config['allowed_types'] = 'jpg|png|PNG|JPG|jpeg|bmp';
$config['min_width'] = 1024;
$config['min_height'] = 768;
$config['max_size'] = 3072;
$config['quality'] = 60;
$this->load->library('upload', $config);
if ($this->upload->do_upload('userfile')) {
$uploadData = $this->upload->data();
if (isset($uploadData)) {
$vacancy_data['banner'] = $uploadData['file_name'];
$check = true;
}
} else {
$imageOk = array('error' => $this->upload->display_errors());
// Passing Variables
$data['title'] = 'Give a Day - Error';
$data['class'] = 'vacancy';
$data['validationErrors'] = validation_errors();
$data['imgErrors'] = $imageOk['error'];
$data['feedback'] = array(
'type' => 'alert-danger',
'icon' => 'fa-times',
'title' => 'Oops!',
'text' => 'Uploaden van de foto is niet gelukt'
);
$content = 'dashboard/vacancy/error';
}
} else {
//check on true cause there is no image selected
$check = true;
$isNoImageChosen = true;
}
//Check if image upload went without errors
if($check) {
//Serialize the accessibility (because more than 1 value can be entered)
$vacancy_data['accessibility'] = serialize($vacancy_data['accessibility']);
$vacancyId = $this->vacancy_model->add($vacancy_data);
// Create Vacancy Contact
$vacancyContact['contact_id'] = $contactId;
$vacancyContact['vacancy_id'] = $vacancyId;
$this->vacancyContacts_model->add($vacancyContact);
// Set Interests
$this->load->model('vacancy/vacancyInterests_model');
$interests = $this->input->post('interests');
if ($interests != '') {
$interests = explode(",", $interests);
foreach ($interests as $id) {
$this->vacancyInterests_model->add($vacancyId, $id);
}
}
if ($isNoImageChosen) {
$k = array_rand($interests);
$randomInterestId = $interests[$k];
$randomBannerImageLocation = return_random_interest_banner($randomInterestId);
//Because the vacancy has already been created we need to do an update for setting the banner image
$bannerData = array (
'banner' => $randomBannerImageLocation
);
$this->vacancies_model->update($vacancyId, $bannerData);
}
// Set Skills
$this->load->model('vacancy/vacancySkills_model');
$skills = $this->input->post('skills');
if ($skills != '') {
$skills = explode(",", $skills);
foreach ($skills as $id) {
$this->vacancySkills_model->add($vacancyId, $id);
}
}
//Get organisation information for the name
$orgdata = $this->organization_model->get($orgId);
$orgname = $orgdata->name;
$orguserid = $this->userRoles_model->getAdminUserId($orgId);
$orguserdata = $this->users_model->get($orguserid[0]->user_id);
$orgemail = $orguserdata->email;
$mail_data['vacid'] = $vacancyId;
$mail_data['vacname'] = $vacancy_data['name'];
$mail_data['org_id'] = $orgId;
$mail_data['orgname'] = $orgname;
$mail_data['contactpersonfirstname'] = $contact_data['first_name'];
$this->email->from(GENERAL_MAIL, 'Give a Day');
$this->email->to($contact_data['email']);
$this->email->cc($orgemail);
$this->email->bcc(GENERAL_MAIL);
$this->email->subject('Je vrijwilligersactiviteit is aangemaakt');
$message = $this->load->view('mail/vacancy/creation_confirmation', $mail_data, TRUE);
$this->email->message($message);
$this->email->send();
// Passing Variables
$data['title'] = 'Give a Day - Succes!';
$data['class'] = 'vacancy';
$data['vacancyId'] = $vacancyId;
$data['vacancyName'] = $vacancy_data['name'];
if ($adminEditing) {
$data['adminedit'] = TRUE;
$data['orgid'] = $orgId;
}
$content = 'dashboard/vacancy/confirmation';
} else {
// Passing Variables
$data['title'] = 'Give a Day - Error';
$data['class'] = 'vacancy';
$data['validationErrors'] = validation_errors();
$imageOk = array('error' => $this->upload->display_errors());
$data['imgErrors'] = $imageOk['error'];
$content = 'dashboard/vacancy/error';
}
} else {
// Passing Variables
$data['title'] = 'Give a Day - Error';
$data['class'] = 'vacancy';
$data['validationErrors'] = validation_errors();
//$imageOk = array('error' => $this->upload->display_errors());
//$data['imgErrors'] = $imageOk['error'];
$content = 'dashboard/vacancy/error';
}
// Template declaration
$partials = array('head' => '_master/header/head', 'navigation' => '_master/header/navigation_dashboard', 'content' => $content, 'footer' => '_master/footer/footer');
$this->template->load('_master/master', $partials, $data);
} else {
//User does not have correct permissions --> Go to 404
redirect(site_url( 'error/my404', $redirect_protocol));
}
} else {
//User is anonymous -> go to login page (and remember the current URL for redirecting again after log in)
$this->session->set_flashdata('referred_from', uri_string());
redirect(site_url( 'login?redirect=user', $redirect_protocol));
}
}
Note that when I upload an image of 19 MB, for some reason I end up in the else clause all the way at the bottom and I get a page showing all the validation errors saying "Wat heb je te bieden is verplicht.", "naam is verplicht", ... and all of them literally.
All data is filled in correctly, and when i perform the exact same steps, but take an image which is less than 3MB, it works perfect.
So 0-3MB - works perfect.
3-10MB - gives perfect error
and >10 MB - gives all validation errors.
You may find this useful, this is a helper I've created for form uploads to determine the maximum size for uploads based on post_max_size and upload_max_size
Usage:
$config['max_size'] = convert_bytes_to_type(file_upload_max_size(), 'KB');
Helper:
/**
* Gets max upload size from post_max_size and upload_max_filesize
* Returns whichever is smaller
*
* #return int
*/
function file_upload_max_size() {
$max_size = convert_to_bytes(ini_get('post_max_size'));
$upload_max = convert_to_bytes(ini_get('upload_max_filesize'));
if ($upload_max > 0 && $upload_max < $max_size) {
$max_size = $upload_max;
}
return $max_size;
}
/**
* Converts KB (K) through GB (G) to bytes
*
* #param string $from
* #return int bytes
*/
function convert_to_bytes($from) {
$number = filter_var($from, FILTER_SANITIZE_NUMBER_INT);
if (empty($number)) {
return 0;
}
$type = strtoupper(str_replace($number, '', $from));
switch ($type) {
case "KB":
case "K":
$number = $number * 1024;
break;
case "MB":
case "M":
$number = $number * pow(1024, 2);
break;
case "GB":
case "G":
$number = $number * pow(1024, 3);
break;
default:
return 0;
}
return fix_integer_overflow($number);
}
/**
* Converts bytes to KB (K) through GB (G)
*
* #param int $bytes
* #param string $type Type to convert to
* KB (K) through GB (G)
* #return int bytes
*/
function convert_bytes_to_type($bytes, $type = 'MB') {
$number = filter_var($bytes, FILTER_SANITIZE_NUMBER_INT);
if (empty($number)) {
return 0;
}
$type = strtoupper($type);
switch ($type) {
case "KB":
case "K":
$divisor = 1024;
break;
case "MB":
case "M":
$divisor = pow(1024, 2);
break;
case "GB":
case "G":
$divisor = pow(1024, 3);
break;
default:
return 0;
}
return $bytes / $divisor;
}
/**
* Converts bytes into human readable form
*
* #param string || File
* #param int precision round precision
* #return int rounded bytes in units
*/
function human_readable_bytes($bytes, $precision = 2) {
$CI = & get_instance();
$CI->lang->load('number');
if (is_file($bytes)) {
$bytes = fix_integer_overflow(filesize($bytes));
}
$units = array(
$CI->lang->line('bytes'),
$CI->lang->line('kilobyte_abbr'),
$CI->lang->line('megabyte_abbr'),
$CI->lang->line('gigabyte_abbr'),
$CI->lang->line('terabyte_abbr')
);
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
/**
* Fixes integer overflow
*
* #param int $size
* #return int
*/
function fix_integer_overflow($size) {
if ($size < 0) {
$size += 2.0 * (PHP_INT_MAX + 1);
}
return $size;
}
https://pastebin.com/2zDJ90Qr
I figured out that post_max_size in php.ini was set to 8MB, this caused the $_POST variable to become NULL... Setting an if case to check if $_POST is not null solved the issue! Thanks

MOODLE ROLES AND CAPABILITIES

I had developed a block in 2.5. I installed the block successfully..and gave permissions settings on front end to view this block only for one role users say 'Manager'. So, Manager/Admin can only view this block and no one else.
But this block is still visible for all. Could you please judge me.. where I went wrong.. Here is my leisure block code
Blocks/block_leisure/block_leisure.php
<?php
class block_leisure extends block_base
{
public function init()
{
global $CFG;
$this->title = get_string('leisure', 'block_leisure');
}
public function get_content()
{
global $COURSE, $DB, $PAGE, $CFG, $USER, $CFG, $SESSION, $OUTPUT;
if ($this->content !== null)
{
return $this->content;
}
$this->content = new stdClass;
$context = $PAGE->context;
$this->content->text = 'This is a leisure block content';
$this->content->footer = 'Footer here...';
return $this->content;
} // Function - get_content().
public function getmodules()
{
return true;
}
}
Blocks/block_leisure/db/access.php
<?php
defined('MOODLE_INTERNAL') || die;
$capabilities = array(
'block/leisure:myaddinstance' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => array(
'user' => CAP_ALLOW
),
'clonepermissionsfrom' => 'moodle/my:manageblocks'
),
'block/leisure:addinstance' => array(
'riskbitmask' => RISK_SPAM | RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_BLOCK,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'moodle/site:manageblocks'
),
'block/leisure:viewpages' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_COURSE,
'legacy' => array(
'guest' => CAP_PREVENT,
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'coursecreator' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'block/leisure:managepages' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_COURSE,
'legacy' => array(
'guest' => CAP_PREVENT,
'student' => CAP_PREVENT,
'teacher' => CAP_PREVENT,
'editingteacher' => CAP_ALLOW,
'coursecreator' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
)
);
and as usual I have lang folder, version.php and read me file.
You need to do something with the capability you have defined, otherwise it will have no effect.
Check the capability within get_content, then return null if nothing should be displayed.

Nesting Fieldsets under Radio or Checkbox items: Zend Framework 2

I would like to create a fieldset under each radio/checkbox item.
e.g
Which animals do you like:
[x] Cats
[Fieldset of cat related questions]
[ ] Dogs
[Fieldset of dog related questions]
...
I can create Fieldsets and Forms with ease, but nesting them under each item is causing me some headaches.
Ultimately I had in mind something like this:
$this->add(array(
'type' => 'Zend\Form\Element\Radio',
'name' => 'profile_type',
'options' => array(
'label' => 'Which animals do you like:',
'label_attributes' => array('class'=>'radio inline'),
'value_options' => array(
'1' =>'cats',
'fieldsets' => array(
array(
'name' => 'sender',
'elements' => array(
array(
'name' => 'name',
'options' => array(
'label' => 'Your name',
),
'type' => 'Text'
),
array(
'type' => 'Zend\Form\Element\Email',
'name' => 'email',
'options' => array(
'label' => 'Your email address',
),
),
),
)),
'2'=>'dogs',
'fieldsets' => array(
array(
'name' => 'sender',
'elements' => array(
array(
'name' => 'name',
'options' => array(
'label' => 'Your name',
),
'type' => 'Text'
),
array(
'type' => 'Zend\Form\Element\Email',
'name' => 'email',
'options' => array(
'label' => 'Your email address',
),
),
),
))
),
),
'attributes' => array(
'value' => '1' //set checked to '1'
)
));
Ok I managed to get round this issue using a bit of a hack, but it works.
TestForm.php (note the additional attributes in the elements ('parent' and 'childOf')
class TestForm extends Form
{
public $user_agent;
public $user_ip;
public function __construct($name = null)
{
// we want to ignore the name passed
parent::__construct('profile');
$this->setAttributes(array(
'method'=>'post',
'class'=>'form-horizontal',
));
$this->add(array(
'type' => 'Zend\Form\Element\Radio',
'name' => 'profile_type',
'options' => array(
'label' => 'Which animals do you like:',
'label_attributes' => array('class'=>'radio inline'),
'value_options' => array(
array('label' =>'cats', 'value'=>1, 'parent'=>'cat'),
array('label'=>'dogs', 'value'=>2, 'parent'=>'dog'),
),
),
'attributes' => array(
'value' => '1' //set checked to '1'
)
));
$this->add(array(
'type' => 'Text',
'name' => 'name',
'attributes' => array(
'childOf' => 'cat',
),
'options' => array(
'label' => 'Your name',
),
));
$this->add(array(
'type' => 'Zend\Form\Element\Email',
'name' => 'email',
'attributes' => array(
'childOf' => 'dog',
),
'options' => array(
'label' => 'Your email address',
),
));
}
}
Then extended Zend\Form\View\Helper\FormMultiCheckbox and overwrote the RenderOptions Method (look out for the new optionSpec 'parent') this basically creates a tag e.g.{#cat#} after the parent element:
protected function renderOptions(MultiCheckboxElement $element, array $options, array $selectedOptions,
array $attributes)
{
$escapeHtmlHelper = $this->getEscapeHtmlHelper();
$labelHelper = $this->getLabelHelper();
$labelClose = $labelHelper->closeTag();
$labelPosition = $this->getLabelPosition();
$globalLabelAttributes = $element->getLabelAttributes();
$closingBracket = $this->getInlineClosingBracket();
if (empty($globalLabelAttributes)) {
$globalLabelAttributes = $this->labelAttributes;
}
$combinedMarkup = array();
$count = 0;
foreach ($options as $key => $optionSpec) {
$count++;
if ($count > 1 && array_key_exists('id', $attributes)) {
unset($attributes['id']);
}
$value = '';
$parent = '';
$label = '';
$inputAttributes = $attributes;
$labelAttributes = $globalLabelAttributes;
$selected = isset($inputAttributes['selected']) && $inputAttributes['type'] != 'radio' && $inputAttributes['selected'] != false ? true : false;
$disabled = isset($inputAttributes['disabled']) && $inputAttributes['disabled'] != false ? true : false;
if (is_scalar($optionSpec)) {
$optionSpec = array(
'label' => $optionSpec,
'value' => $key
);
}
if (isset($optionSpec['value'])) {
$value = $optionSpec['value'];
}
if (isset($optionSpec['parent'])) {
$parent = $optionSpec['parent'];
}
if (isset($optionSpec['label'])) {
$label = $optionSpec['label'];
}
if (isset($optionSpec['selected'])) {
$selected = $optionSpec['selected'];
}
if (isset($optionSpec['disabled'])) {
$disabled = $optionSpec['disabled'];
}
if (isset($optionSpec['label_attributes'])) {
$labelAttributes = (isset($labelAttributes))
? array_merge($labelAttributes, $optionSpec['label_attributes'])
: $optionSpec['label_attributes'];
}
if (isset($optionSpec['attributes'])) {
$inputAttributes = array_merge($inputAttributes, $optionSpec['attributes']);
}
if (in_array($value, $selectedOptions)) {
$selected = true;
}
$inputAttributes['value'] = $value;
$inputAttributes['checked'] = $selected;
$inputAttributes['disabled'] = $disabled;
$input = sprintf(
'<input %s%s',
$this->createAttributesString($inputAttributes),
$closingBracket
);
if (null !== ($translator = $this->getTranslator())) {
$label = $translator->translate(
$label, $this->getTranslatorTextDomain()
);
}
$tag = ($parent != '')? "{#*".$parent."*#}": "";
$label = $escapeHtmlHelper($label);
$labelOpen = $labelHelper->openTag($labelAttributes);
$template = $labelOpen . '%s%s%s' . $labelClose;
switch ($labelPosition) {
case self::LABEL_PREPEND:
$markup = sprintf($template, $label, $input, $tag);
break;
case self::LABEL_APPEND:
default:
$markup = sprintf($template, $input, $label, $tag);
break;
}
$combinedMarkup[] = $markup;
}
return implode($this->getSeparator(), $combinedMarkup);
}
Extended and overwrote Zend\Form\View\Helper\FormRow render method this is the same except for the return of the method:
..... more code .....
$child_of = $element->getAttribute('childOf');
if($child_of != '')
{
return array($child_of => sprintf('<div class="control-group%s">%s</div>', $status_type, $markup));
}
return sprintf('<div class="control-group%s">%s</div>', $status_type, $markup);
And finally extended and overwrote the render method of Zend\Form\View\Helper\FormCollection and changed the element foreach loop, basically overwriting the tags if the element is an array, and therefore has a ChildOf tag. Then a clean up of tags:
foreach ($element->getIterator() as $elementOrFieldset) {
if ($elementOrFieldset instanceof FieldsetInterface) {
$markup .= $fieldsetHelper($elementOrFieldset);
} elseif ($elementOrFieldset instanceof ElementInterface) {
$elementString = $elementHelper($elementOrFieldset);
if(!is_array($elementString))
{
$markup .= $elementString;
}
// is child of another element
else
{
foreach($elementString as $key => $value)
{
$match = "{#*".$key."*#}";
$replacement = $value.$match;
$markup = str_replace($match, $replacement, $markup);
}
}
}
}
$pattern = '/[{#\*]+[a-z0-0A-Z]*[\*#}]+/';
$markup = preg_replace($pattern, '', $markup);
This (although ugly) produces the desired results, also because we are just playing with the rendering, validation and form creation are untouched.
All the best,
Aborgrove

Zend Framework Custom Validator on Form Elements

Hi I am trying to set up element custom validator in a zend form this is what I have.
class Siteanalysis_Form_User_ChangePassword extends SA_Form_Abstract
{
public function init()
{
// add path to custom validators
$this->addElementPrefixPath(
'Siteanalysis_Validate',
APPLICATION_PATH . '/modules/siteanalysis/models/validate/',
'validate'
);
$this->addElement('text', 'passwdVerify', array(
'filters' => array('StringTrim'),
'validators' => array('PasswordVerification',array('StringLength', true, array(6, 128))),
'decorators' => array('ViewHelper','Errors',
array('HtmlTag', array('id' => 'passwdVerify')),
array('Label', array('placement'=>'prepend','class'=>'label'))),
'required' => true,
'label' => 'Confirmar contraseña nueva',
));
$this->addElement('submit', 'change', array(
'label' => 'Cambiar',
'required' => false,
'ignore' => true,
'decorators' => array('ViewHelper')
));
}
}
class Siteanalysis_Validate_PasswordVerification extends Zend_Validate_Abstract
{
const NOT_MATCH = 'notMatch';
protected $_messageTemplates = array(
self::NOT_MATCH => 'Verifique que las contraseñs sean iguales.'
);
public function isValid($value, $context = null)
{
$value = (string) $value;
$this->_setValue($value);
if (is_array($context)) {
if (isset($context['passwdNew'])
&& ($value == $context['passwdNew']))
{
return true;
}
} elseif (is_string($context) && ($value == $context)) {
return true;
}
$this->_error(self::NOT_MATCH);
return false;
}
}
The problem is that its not calling the PasswordVerification custom validator, does any one see something wrong with it?
Thanks.
Update: Test Setup
$form = new Siteanalysis_Form_User_ChangePassword();
$value = 'Adam';
$data = array('passwdVerify' => $value);
$validation = $form->isValid($data);
if ( $validation === false ) {
$element = $form->getElement('passwdVerify');
$errors = $element->getErrors();
$msg = $element->getMessages();
} else {
$values = $form->getValidValues($data);
}
If $value is
empty I get $errors "isEmpty"
'Adam' I get $errors "noMatch" and "stringLengthTooShort"
'AdamSandler' I get $errors "noMatch"
Your validators array should look like this:
'validators' => array('PasswordVerification' => array('StringLength', true, array(6, 128)))
not
'validators', array('PasswordVerification',array('StringLength', true, array(6, 128))),