I'm trying to validate a field inside a Collection.
The Collection refers to Company Areas and is tied to a Company Fieldset
The validation needs to check that the Area Name doesn't exists for that Company in the Database yet.
I'm trying to do this using a Callback validator within my collection element 'area_name', my problem is that the collection is aware only of its own context, that means all fields associated to the Area but not aware of the Company context, so i can't filter my validator by its Company parent.
Is there a way to access the parent context of a collection? or should i need to initialize my form passing the Company object to the Collection prior validating?
EDIT: I forgot to mention that i'm using Doctrine2 so i'm not sure if it is possible to use the Db_NoRecordExists Validator bundled with ZF2
This is an old question and you might have fixed this already, but I had a similar problem recently.
You can create a function in your area model/service: validateAreaCompanyRelation(area, company)and in your fieldset use the callback to use it:
AreaService class:
add a method to return true or false based on query limited by 1 row.
in my case it was somthing like this:
public function validateAreaCompanyRelation($company, $area)
{
$result = false;
$count = $this->getRepository()
->createQueryBuilder('q')
->select('q')
->innerJoin('q.company', 'c')
->innerJoin('q.area','b')
->where('b.id = :area and c.company = :company')
->setParameter('area',$area)
->setParameter('company',$area)
->setMaxResults( 1 )
->getQuery()
->getArrayResult();
if(count($count) <>1){
$result=true;
}
return $result;
}
Area Field set:
inject AreaService to the field set (pass it to construct in factory)
class AreaFieldset extends Fieldset implements InputFilterProviderInterface
{
private $areaService;
public function __construct(areaServiceEntityService $areaService)
{
$this->areaService = $areaService;
}
public function init()
{
$this->add(
array(
'name' => 'area',
'filters' => array(),
'validators' => array (
array(
'name' => 'Zend\Validator\Callback',
'options' => array(
'messages' => array(
\Zend\Validator\Callback::INVALID_VALUE => 'Your custom error message',
),
'callback' => array($this,'vlidateUniqueRelation'),
),
),
)
)
);
array(
'name' => 'company',
'filters' => array(),
'validators' => array (
array(
'name' => 'Zend\Validator\Callback',
'options' => array(
'messages' => array(
\Zend\Validator\Callback::INVALID_VALUE => 'Your custom error message',,
),
'callback' => array($this,'vlidateUniqueRelation'),
),
),
)
)
);
}
public function vlidateUniqueRelation($value, $context)
{
// $value = value
// $context['xxxx'] = xxxxx value
// Logic to validate goes here
$context["company"]
$context["area"]
return $this->AreaService->validateAreaCompanyRelation($context["company"], $context["Area"]);
}
Related
I am working on an edit screen for my grid row. This is what I have so far for this form:
<?php
class Intellibi_Integration_Block_Adminhtml_Manageasendiapickinglists_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form();
$this->setForm($form);
$fieldset = $form->addFieldset('integration_form', array(
'legend' => Mage::helper('integration')->__('Asendia Pick Information')
));
$fieldset->addField('order_number', 'label', array(
'label' => Mage::helper('integration')->__('Order Number'),
'name' => 'order_number'
));
// snipped
$fieldset->addField('pick_status', 'select', array(
'required' => false,
'class' => 'required-entry',
'label' => Mage::helper('integration')->__('Pick Status'),
'name' => 'pick_status',
'values' => Mage::getSingleton('ibi/asendiapickstatus')->getOptionArray(),
'readonly' => 'readonly'
));
// snipped
return parent::_prepareForm();
}
}
This produces the following output in the admin backend:
What I would like to do is change the pick_status column from a select to a label. When I do this, instead of showing the status value "New" it shows the array index like this:
My option array for asendiapickstatus is defined like this in my model:
class Intellibi_Integration_Model_Asendiapickstatus extends Varien_Object
{
const PICK_STATUS_NEW = 1;
const PICK_STATUS_SENT = 2;
const PICK_STATUS_SHIPPED = 3;
static public function getOptionArray()
{
return array(
self::PICK_STATUS_NEW => Mage::helper('integration')->__('New'),
self::PICK_STATUS_SENT => Mage::helper('integration')->__('Sent'),
self::PICK_STATUS_SHIPPED => Mage::helper('integration')->__('Shipped')
);
}
}
So my question is; on the edit form fieldset builder, how do I show the dropdown field "pick_status" value, rather than the current index it's at? So the output will say "New" instead of "1" as shown above. Will I need a custom renderer?
I've solved it like this (with a custom form rendered element):
Added custom fieldset type
$fieldset->addType('pickstatus', 'Intellibi_Integration_Block_Adminhtml_Manageasendiapickinglists_Edit_Tab_Form_Renderer_Fieldset_Pickstatus');
Used the fieldset like this
$fieldset->addField('pick_status', 'pickstatus', array(
'label' => Mage::helper('integration')->__('Pick Status'),
'name' => 'pick_status',
));
Coded the rendered like this
class Intellibi_Integration_Block_Adminhtml_Manageasendiapickinglists_Edit_Tab_Form_Renderer_Fieldset_Pickstatus extends Varien_Data_Form_Element_Abstract
{
protected $_element;
public function getElementHtml()
{
// Load Pick Status
$pick_status = (int)$this->getValue();
$pick_status_list = Mage::getSingleton('ibi/asendiapickstatus')->getOptionArray();
// Finish
return array_key_exists($pick_status, $pick_status_list) ? $pick_status_list[$pick_status] : 'Unknown';
}
}
And it renders like this
So, disclaimer first: I'm a bit of a noob when it comes to SilverStripe, but this one is vexxing me.
I'm using GridField to add and edit the entries in a DataObject. This is all well and good, and works perfectly. The only thing I can't figure out is how to change the order of the EDITABLE fields - this isn't the initial table display of the entries (which is set by $config), it's the actual input fields once you click "add new" or go to edit a record.
At the moment the Image uploadForm and the Signature <select> box are below the Body HTMLText field, which is messy and doesn't work right. I want them up the top, right below the Summary element.
I've tried playing around with changeFieldOrder(), but that doesn't work on a GridField object type and $fields doesn't know anything about the input elements (I dump()'ed it and had a look).
MediaReleaseItem.php:
class MediaReleaseItem extends DataObject {
static $db = array (
'Title' => 'Varchar',
'DateUpdated' => 'Date',
'Summary' => 'Varchar',
'Image' => 'Varchar',
'Body' => 'HTMLText',
);
private static $has_one = array(
"Image" => "Image",
"MediaReleaseItem" => "MediaReleases",
"Signature" => "MediaReleaseSignature",
);
}
And MediaReleases.php:
class MediaReleases extends Page {
private static $has_many = array(
"MediaReleaseItems" => "MediaReleaseItem",
"Signature" => "MediaReleaseSignature",
);
function getCMSFields() {
$fields = parent::getCMSFields();
$config = GridFieldConfig_RecordEditor::create();
$config->getComponentByType('GridFieldDataColumns')->setDisplayFields(array(
'Title'=> 'Title',
'DateUpdated' => 'Date',
'Summary' => 'Summary',
));
$mediaReleasesField = new GridField(
'MediaReleaseItem', // Field name
'Media Releases', // Field title
$this->MediaReleaseItems(),
$config
);
$fields->addFieldToTab('Root.MediaReleaseItems', $mediaReleasesField);
return $fields;
}
}
(Signature is just another DataObject with a different GridField on a different tab, I didn't include the code for it because it's almost identical.)
so, you mean when you edit a MediaReleaseItem the fields are not the way you want then to be?
simple: just also define a method getCMSFields() on the class MediaReleaseItem.
<?php
class MediaReleaseItem extends DataObject {
private static $db = array (
'Title' => 'Varchar',
'DateUpdated' => 'Date',
'Summary' => 'Varchar',
'Image' => 'Varchar',
'Body' => 'HTMLText',
);
private static $has_one = array(
"Image" => "Image",
"MediaReleaseItem" => "MediaReleases",
"Signature" => "MediaReleaseSignature",
);
public function getCMSFields() {
$arrayOfSignatures = MediaReleaseSignature::get()->map()->toArray();
$fields = FieldList::create(array(
TextField::create('Title', 'Title for this Item'),
DateField::create('DateUpdated', 'Updated')->setConfig('showcalendar', true),
TextField::create('Image', 'Image'),
// not sure if it works to have both a DB field and a has_one with the same name
UploadField::create('ImageID', 'Image'),
DropdownField::create('Signature', 'Signature', $arrayOfSignatures),
// you can add more fields here
));
// but you can also add fields here
$fields->insertBefore(TextField::create('Summay', 'Summary'), 'DateUpdated');
$fields->push(HTMLEditorField::create('Body', 'Body Content'));
return $fields;
}
}
I'm creating a select form element within FuelPHP's model _properties variable:
protected static $_properties = array(
'category_id' => array(
'data_type' => 'int',
'label' => 'Category',
'form' => array(
'type' => 'select',
'options' => array()
)
)
);
I want to set [category_id][form][options] to the result of an SQL query, however this obviously cannot be done within the class declaration and I've tried modifying the variable from with __construct(), this code is below but yielded errors.
function _construct() {
parent::__construct();
self::$_properties['category_id']['form']['options'] = array('a');
}
My question is, how do I set the field options to something dynamic using FuelPHP?
You are almost there. Fuel provides a static constructor called init that will allow you to assign static properties.
function _init() {
parent::_init();
self::$_properties['category_id']['form']['options'] = array('a');
}
I am trying to retrieve data (a dependency) from a database and use the returned values to populate a zend form select element.
The final values should look like below:
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'jobId',
'options' => array(
'label' => 'countryList',
'value_options' => array(
'1'=>'USA',
'2'=> 'United Kingdom',
etc
'
),
),
'attributes' => array(
'value' => '1' //set selected to '1'
)
));
I have used doctrine2 to retrieve the values, i.e:
public function getOptionsForSelect()
{
$entity = $this->getEntityManager()
->getRepository('Workers\Entity\CountryList')
->findAll();
foreach ($entity as $entity)
{
echo $entity->country;
echo $entity->id;
}
}
The above gives me all the required values. I am however stuck on how to then place these values into an array such that once the $this->getOptionsForSelect() is placed in the form, it will immediately populate the values;
i.e.
foreach ($entity as $entity)
{
$id = $entity->id;
$country= $entity->country;
$data['data'] = $id.'=>'.$country;
}
return $data;
The final version of the form field will look like below:
$this->add(array(
'name' => 'countrylist',
'type' => 'Zend\Form\Element\Select',
'options' => array(
'label' => 'countrylist',
'value_options' => $this->getOptionsForSelect(),
'empty_option' => '--- please choose ---'
)
));
There is ObjectSelect/EntitySelect in DoctrineModule for ZF2 which might simplify this - https://github.com/doctrine/DoctrineModule/blob/master/docs/form-element.md
You don't need your own getOptionsForSelect(), because doctrine can handle that already.
If I understood you correctly, you could implement your getOptionsForSelect like so:
public function getOptionsForSelect()
{
$entity = $this->getEntityManager()
->getRepository('Workers\Entity\CountryList')
->findAll();
$options = array();
foreach ($entity as $entity) {
$options[$entity->id] = $entity->country;
}
return $options;
}
I haven't worked with doctrine, but I'd expect it to have some method to extract data as an array, or at least that I'd be possible to pass it to some serialized object to do that.
I'm trying to set custom values for Select Options using Form types and 'choice_list'.
Type:
->add('status', 'choice', array(
'constraints' => array(
new Assert\NotBlank(array('message' => 'Required field missing: status'))
),
'error_bubbling' => true,
'choice_list' => new StatusChoiceList()
StatusChoiceList file:
class StatusChoiceList extends LazyChoiceList
{
/**
* Loads the choice list
*
* Should be implemented by child classes.
*
* #return ChoiceListInterface The loaded choice list
*/
protected function loadChoiceList()
{
$array = array(
'Preview' => 'Preview',
'Hidden' => 'Hidden',
'Live' => 'Live'
);
$choices = new ChoiceList($array, $array);
return $choices;
}
}
the select tag have a wrong values 0,1,2 and a good labels
ChoiceList class used for choices of arbitrary data types. In your case you should use SimpleChoiceList instead. First parameter is an array with choices as keys and labels as values.
protected function loadChoiceList()
{
$array = array(
'Preview' => 'Preview',
'Hidden' => 'Hidden',
'Live' => 'Live'
);
$choices = new SimpleChoiceList($array);
return $choices;
}