SilverStripe - Multilingual Custom Form Template - forms

I am building a page with two languages (English and German). For this I am using the translatable module offered on the SilverStripe page (http://addons.silverstripe.org/add-ons/silverstripe/translatable). On regular pages it works just like a charm.
The contact form gets created in a controller. By $form->setTemplate I load a custom template for the form, which is located in the template's include subdirectory. In the class file I defined the different TextFields (model part), which I want to use in the form template.
Here is the controller:
class MietenPage extends Page {
private static $db = array (
//Form
'ChoosPakage' => 'Varchar',
'FormEventHeadline' => 'Varchar',
'FormNoteHeadline' => 'Varchar',
'FormContactHeadline' => 'Varchar',
'FormAdditionalHeadline' => 'Varchar',
'FormCheckOverlay' => 'Varchar',
'FormCheckCaseDesign' => 'Varchar',
'FormCheckAGB' => 'Varchar',
'FormSubmit' => 'Varchar',
'AGBAlert' => 'Varchar'
);
public function getCMSFields() {
$fields = parent::getCMSFields();
//...
return $fields;
}
}
class MietenPage_Controller extends Page_Controller {
private static $allowed_actions = array('ContactForm');
public function ContactForm() {
$fields = new FieldList(
//...
);
$actions = new FieldList(
new FormAction('submit', 'Anfrage Senden!')
);
$form = new Form($this, 'ContactForm', $fields, $actions);
$form->setTemplate('ContactFormTemplate');
return $form;
}
public function submit($data, $ContactForm) {
$email = new Email();
//...
}
}
In my template I am calling the form using $ContactForm. This works totally fine, including all functionalities.
My Problem is, that I can not access the variables (like headline or submit button text), which hold the text in my custom template - just emptyness is returned. I think it has to do something with scope, but I can not solve this problem.

From your example I can't see where your variables live, and how you planned to use them, but to create a multlingual form, you'd best use the _t() functionality: https://docs.silverstripe.org/en/3.1/developer_guides/i18n/#translating-text
You'd use that for any 'hardcoded' text, in php as well as in your templates.

Related

Injecting variables into Forms __construct function Zend 2

I am trying to prepopulate a form's drop down options via data stored statically in the module.config.php in Zend 2 and am running into a problem which entails:
I try to get the Servicemanager in the __construct() function but it is unavailable.
I move the element declarations to another function within the form class so I can pass variables into it but the view controller cannot find the elements.
I currently call the form via a Servicemanager Invokable. How can I pass these arrays into the form's __construct() function?
Here is the code:
class ILLForm extends Form
{
public function __construct($fieldsetName, $campuses, $ILLTypes, $getFromOptions)
{
parent::__construct('create_ill');
$this
->setAttribute('method', 'post')
->setHydrator(new ClassMethodsHydrator(false))
->setInputFilter(new InputFilter())
;
$ill = new ILLFieldset('ill', $campuses, $ILLTypes, $getFromOptions);
$ill->setName('ill')
->setOptions(array(
'use_as_base_fieldset' => true,
));
$captcha = new Element\Captcha('captcha');
$captchaAdapter = new Captcha\Dumb();
$captchaAdapter->setWordlen(5);
$captcha->setCaptcha($captchaAdapter)
->setLabelAttributes(array('class' => 'sq-form-question-title'))
->setAttribute('class', 'sq-form-field required')
->setLabel("* Captcha")
->setAttribute('title', 'Help to prevent SPAM');
$submit = new Element\Submit('submit');
$submit->setAttribute('value', 'Submit ILL')
->setAttribute('class', 'sq-form-submit')
->setAttribute('title', 'Submit ILL');
$this->add($ill)
->add($captcha)
->add($submit);
}
}
The Indexcontroller Factory that calls the Form:
class IndexControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $controllers)
{
$allServices = $controllers->getServiceLocator();
$sm = $allServices->get('ServiceManager');
$smConfig = $allServices->get('config');
$campuses = $smConfig['campuses'];
$illCategories = $smConfig['ILLCategories'];
$getFromOptions = $smConfig['getFromOptions'];
$controller = new IndexController();
$controller->setCampuses($campuses);
$controller->setILLCategories($illCategories);
$controller->setGetFromOptions($getFromOptions);
$controller->setILLForm($sm->get('ILL-form'));
$controller->setILLFormFilter($sm->get('ILL-form-filter'));
//$controller->setParams($sm->get('params'));
return $controller;
}
}
and the relevant module.config.php excerpt:
'service_manager' => array(
'abstract_factories' => array(
'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
'Zend\Log\LoggerAbstractServiceFactory',
),
'invokables' => array(
'ILL-form-filter' => 'ILL\Form\ILLFormFilter',
'ILL-form' => 'ILL\Form\ILLForm',
),
I ended up taking the form out of the service manager invokables in module.config.php (removed line for 'ILL-form') and call it from the indexControllerFactory.php instead
$create_ill = new Form\ILLForm('create_ill', $campuses, $illCategories, $getFromOptions);
$controller->setILLForm($create_ill);
instead of
$controller->setILLForm($sm->get('ILL-form'));

How to pass default data when creating a form holding a CollectionType?

I am trying to create multi import data, so I need many form collection this same class in one place. I can do this using collection type.
I created pictures Class with have one field: pictures and it is arrayCollection type like this:
class Pictures {
protected $pictures;
public function __construct()
{
$this->pictures = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addPicture(Picture $picture)
{
$this->pictures[] = $picture;
return $this;
}
public function removePicture(Picture $picture)
{
$this->pictures->removeElement($picture);
}
public function getPictures()
{
return $this->pictures;
}
}
Next I created pictures form with collection to pictureType.
$builder
->add('pictures', 'collection', array(
'prototype' => false,
'by_reference' => true,
'entry_type' => PictureType::class,
'options' => array('label' => false))
)
;
Next I have picture Entity with fields for example name, width, height, image (nevermind).
So my PictureType is a simple form fith fields that same like Entity (standard).
Now I try to render this form and add some picture in controller (not from database). Then I create Picture Object and next I add it to pictures->addPicture($picture);
$pictures = new Pictures();
foreach($data as $d){
$picture = new Picture();
$picture->setName($d['title']);
$picture->setImage($d['thumbnail_400_url']);
$picture->setWidth($d['width']);
$picture->setHeight($d['height']);
$pictures->addPicture($picture);
}
$form = $this->createForm('PicturesType', $pictures, array(
'action' => $this->generateUrl('dashboard_fotolia_save'),
'method' => 'POST',
));
After it if rendered form is ok. I can see and change values.
But after submit form data disapear. I hope data will be stored in response but not:(
I want to use it only for create new object. Could you help me?
Form errors: This form should not contain extra fields
Actually it seems that your PicturesType holds a pictures field since you add it with :
$builder->add('pictures', 'collection', ...
So you got a form type with holds an array of data with a key 'pictures' for the corresponding fields.
You may want to set it by :
$form = $this->createForm('PicturesType', array('pictures' => $pictures), ...

Zend_Form renders all fields as text

I have a Zend_Form form, with some custom decorators, like this:
$decorators = array();
$decorators[] = new Zend_Form_Decorator_ViewHelper(array());
$decorators[] = new Zend_Form_Decorator_Errors;
$decorators[] = new Zend_Form_Decorator_HtmlTag(array('tag' => 'div', 'class' => 'form-item'));
$decorators[] = new Zend_Form_Decorator_Label(array('class' => 'form-label'));
$decorators[] = new Zend_Form_Decorator_Callback(array(
'callback' => function($content, $element, $options) {
return sprintf('<div class="form-row">%s</div>', $content);
},
'placement' => false
));
$this->setElementDecorators($decorators);
The problem is, that all of the fields are rendered as text inputs. Why does it happen?
EDIT: I discovered, that it doesn't render all the inputs necessarily as text inputs, but renders them with type of the first input in form. Here is example of a form that i use(the decorators are set int parent's init):
<?php
class Form_Users_Add extends Form_Base {
protected $pbxs = array(1 => 'Element 1', 2 => 'Element 2');
public function init() {
$monitors = new Zend_Form_Element_Checkbox('prefered_screen_count');
$monitors->setCheckedValue(2);
$monitors->setUncheckedValue(1);
$monitors->setLabel('two_monitors');
$this->addElement($monitors);
$pbx = new Zend_Form_Element_Select('asterisk_id');
$pbx->setMultiOptions($this->pbxs);
$pbx->setLabel('users_asterisk_id');
$this->addElement($pbx);
parent::init();
}
}
Yay! I have solved the issue! The cause was that I used INSTANCES of classes, not the names. This way every element was using the same instance of the decorator.

How does one create a validator that depends on more than one value for Zend_Form?

I've got a form that has a single text field (for company):
class Cas_Form_Company extends Zend_Form
{
public function init()
{
$this->addElement('hidden', 'id');
$this->addElement('text', 'name', array('label' => 'Name'));
$this->addElement('submit', 'submit', array('label' => 'Create'));
$name = $this->getElement('name');
$name->addValidator('stringLength', false, array(2,45));
$name->addValidator(new Cas_Model_Validate_CompanyUnique());
$this->setMethod('post');
$this->setAction(Zend_Controller_Front::getInstance()->getBaseUrl() . '/Company/Submit');
}
public function SetFromExistingCompany(Cas_Model_Company $company)
{
$this->getElement('id')->setValue($company->GetId());
$this->getElement('name')->setValue($company->GetName());
$this->getElement('submit')->setLabel('Edit');
$this->addElement('submit', 'delete', array('label' => 'Delete', 'value' => 'delete'));
}
public function Commit()
{
if (!$this->valid())
{
throw new Exception('Company form is not valid.');
}
$data = $this->getValues();
if (empty($data['id']))
{
Cas_Model_Gateway_Company::FindOrCreateByName($data['name']);
}
else
{
$company = Cas_Model_Gateway_Company::FindById((int)$data['id']);
$company->SetName($data['name']);
Cas_Model_Gateway_Company::Commit($company);
}
}
}
I've also created a little validator which enforces that I want companies to have unique names:
class Cas_Model_Validate_CompanyUnique extends Zend_Validate_Abstract
{
protected $_messageTemplates = array(
'exists' => '\'%value%\' is already a company.'
);
/**
* #param string $value
* #return bool
*/
public function isValid($value)
{
$this->_setValue($value);
$company = Cas_Model_Gateway_Company::FindByName($value);
if ($company)
{
$this->_error('exists');
return false;
}
return true;
}
}
Now, this works just fine for creating new companies. The problem comes in when I want to allow editing of companies. This is because for an edit operation, while the company name needs to be unique, a form containing the name already pertaining to the given ID isn't an edit at all (and therefore is valid). That is, the form is valid if either the name doesn't already exist in the database, or the name given matches the name already assigned to that ID.
However, writing this as a validator seems to be problematic, because the validator only gets the value it's working on -- not the ID in question.
How does one write a validator for this sort of thing?
You can use the poorly documented second $context argument to isValid().
See http://framework.zend.com/manual/en/zend.form.elements.html#zend.form.elements.validators and scroll down to the note "Validation Context"
I think this link may help you.
Zend Form Edit and Zend_Validate_Db_NoRecordExists
You have to user Db no record exist but for edit you can specify the exclude attribute in validation.

sfWidgetFormInputText weird behaviour

Well, I have this form:
class CaracteristicaForm extends sfForm {
public function configure() {
$this->setWidgets(array(
'caracteristica' => new sfWidgetFormInputText(array('default'=>'hola mundo'))
));
$this->setValidators(array(
'caracteristica' => new sfValidatorString(
array(
'max_length' => 150,
'required' => true
)
)
));
$this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
}
}
and then I try to...
$form = new CaracteristicaForm();
$this->embedForm('caracteristica', $form);
but the rendered inputText does not have any value at all.
What am I missing?
Ok, to reproduce this you need to embed this form into another form (mine is a Doctrine child form) so maybe is something about some method changing the value?
Well, passing an array defaults did the trick:
$form = new CaracteristicaForm(array('caracteristica' => $caracteristica));
Why not try to
$form->setDefault('caracteristica', $caracteristica);
in action?