Write hyperlink inside the Zend Form? - zend-framework

I am using Zend-Framework in my project. I made a login form using the Zend Form that contains the User Id and Passwords fields with a submit button. Everything is working fine in the login form.
How do I add two hyperlinks inside the login form that is one for the Sign-Up and other for the Forget Password?

I've faced the same problem before, and solved it by creating a custom Zend_Form_Element_Html, as follows:
class Zend_Form_Element_Html extends Zend_Form_Element_Xhtml {
/**
* Default form view helper to use for rendering
* #var string
*/
public $helper = 'formNote';
public function isValid($value, $context = null) {
return true;
}
}
So, in your form you just have to do the following:
$tag = new Zend_Form_Element_Html('forgetPassword');
$tag->setValue('Forgotten your password?');
$this->addElement($tag);
Hope this helps!

In your viewscript file where you print the form, e.g. login.phtml
echo $this->form;
you can specify any other html markup, e.g. links
echo "<p><a href='".$this->url ( array ('controller' => 'authentication',
'action' => 'lostPW' ) )."'>
Lost pw </a></p>";
So you actually do not write it in the form itself but in the view script where you echo the form.

Try this:
$passwordElement->setDescription('Forgot password?');
$passwordElement->getDecorator('Description')->setOption('escape', false);
Description decorator will add this text beside your field.

You can use Zend_Form_Decorator_ViewScript
Or, create a custom Zend_Form_Element to render HTML elements or ViewScript.

For only decorators use directly in the form try:
$this->addElement(new Zend_Form_Element_Note(array(
'name' => 'forgotten',
'value' => __('Forgot your password?'),
'decorators' => array(
array('ViewHelper'),
array('HtmlTag', array(
'tag' => 'a',
'href' => $this->getView()->url(array(
'remind'
))
)),
)
)), 'forgotten');

Related

CSRF field is missing when I embed my form with a requestAction in CakePHP 3

I want to embed a contact form in multiple places on my website.
I developed a contact form in a contact() function within my MessagesController.php:
// MessagesController.php
public function contact()
{
$this->set('title', 'Contact');
$message = $this->Messages->newEntity();
... // shortened for brevity
$this->set(compact('message'));
$this->set('_serialize', ['message']);
}
I loaded the CSRF component in the initialize() function of the AppController.php:
// AppController.php
public function initialize()
{
parent::initialize();
$this->loadComponent('Csrf');
... // shortened for brevity
}
The form is rendered with a contact.ctp and it works fine.
I followed CakePHP's cookbook which suggests using requestAction() within an element, then echoing the element where I want it:
// contact_form.ctp
<?php
echo $this->requestAction(
['controller' => 'Messages', 'action' => 'contact']
);
?>
And:
// home.ctp
<?= $this->element('contact_form'); ?>
The problem is that the form is rendered fine, but the CSRF hidden field is missing. It should be automatically added to the form since the CSRF component is called in the AppController.php.
I guess either using an element with a requestAction() isn't the solution for this particular case, or I am doing something wrong.
Any ideas? Thanks in advance for the input!
Request parameters need to be passed manually
requestAction() uses a new \Cake\Network\Request instance, and it doesn't pass the _Token and _csrf parameters to it, so that's why things break.
While you could pass them yourself via the $extra argument, like
$this->requestAction(
['controller' => 'Messages', 'action' => 'contact'],
[
'_Token' => $this->request->param('_Token'),
'_csrf' => $this->request->param('_csrf')
]
);
Use a cell instead
I would suggest using a cell instead, which is way more lightweight than requesting an action, also it operates in the current request and thus will work with the CSRF component out of the box.
You'd pretty much just need to copy your controller action code (as far as the code is concerned that you are showing), and add a loadModel() call to load the Messages table, something like
src/View/Cell/ContactFormCell.php
namespace App\View\Cell;
use Cake\View\Cell;
class ContactFormCell extends Cell
{
public function display()
{
$this->loadModel('Messages');
$this->set('title', 'Contact');
$message = $this->Messages->newEntity();
// ... shortened for brevity
$this->set(compact('message'));
$this->set('_serialize', ['message']);
}
}
Create the form in the corresponding cell template
src/Template/Cell/ContactForm/display.ctp
<?php
echo $this->Form->create(
/* ... */,
// The URL needs to be set explicitly, as the form is being
// created in the context of the current request
['url' => ['controller' => 'Messages', 'action' => 'contact']]
);
// ...
And then wherever you want to place the form, just use <?= $this->cell('ContactForm') ?>.
See also
API > \Cake\Routing\RequestActionTrait::requestAction()
Cookbook > Views > Cells

$_disableLoadDefaultDecorators and ZendX_JQuery

I use my class to alter decoration of my form.
In other words, instead of calling
Application_Form_Login extends Zend_Form
I use:
Application_Form_Login extends My_Form
In my "My_Form" class I define the following:
protected $_disableLoadDefaultDecorators = true;
protected $_elementDecorators = array(
'ViewHelper',
array(
'Errors',
array(
'data-icon'=>"alert",
'class'=>"ui-body ui-body-e errors"
)
),
'Label',
array(
array(
'row' => "HtmlTag"
), array(
'tag'=>"div",
'data-role'=>"fieldcontain"
)
)
);
This works perfect on my regular forms.
But once I use jQuery forms:
$this->addElement(new ZendX_JQuery_Form_Element_AutoComplete(
"ac1",
array('label' => "Your Address:"))
));
It has no effect on them, and they still render with their default decorators.
Any ideas how to globally set decorators for jQuery Form Elements as well?
I have solved the problem. Any default decorators defined this way will also work on any ZendX_JQuery_Form_Element
IF
The element is created inside of addElement function. In other words, instead of creating an element this way:
$this->addElement(new ZendX_JQuery_Form_Element_AutoComplete(
"address",
array(
'label' => "Your Address:"
)
));
You should create it this way:
$this->addElement('AutoComplete', 'address', array(
'label' => "Your Address:"
));
Because when addElement creates the element itself, it will pass the default decorators to the creating function. Otherwise the elements will be created outside of the form context.
There's no AutoComplete element in Zend_Form. So, the class you use to build your forms, that includes all your global settings and decorations (in my case: "My_Form") should extend ZendX_JQuery_Form, and not Zend_Form
ZendX_JQuery_Form_Element_UiWidget requires UiWidgetElement decorator. So we replace the ViewHelper decorator with ZendX_JQuery's: UiWidgetElement.

Zend form in a popup (fancybox, lightbox....)

I am developping a web application using Zend and I ran out of ideas for a problem I am having. In just a few words, I am trying to have a contact form in a popup (Fancybox, lightbox, colorbox or whatever...). The whole thing works fine, in the sense that it shows up the contact form in the popup and allows to send emails. However, whenever there are errors (unfilled input or filled wrong), I couldn't get those errors to be displayed on the popup (it actually redirects me back to the form in a normal display (view+layout), to show the errors.
It is perhaps possible but I now thought that perhaps I could more easily bring my error message to a new popup (the contact page, filled unproperly, would lead to a error popup page...). I think this alternative could look cool but am having real trouble doing it. Now my real question is : Can we really make a form on a popup, using Facybox (Lighbox or any other actually ... just want my popup) and Zend? Any Guru outhere??
Thanks a lot
here is the code:
the link for instance:
<a class="popLink" href=" <?php echo $this->url(array('module'=>'default', 'controller'=>'contact', 'action'=>'sendmail')).'?ProID='.$this->proProfil->getProID(); ?>">Contact</a>
the action:
public function sendmailAction()
{
$this->_helper->layout()->setLayout('blank');
$request = $this->getRequest();
$proID = $this->_getParam("ProID");
$professionalsList = new Model_DirPro();
$proName = $professionalsList->getProInfo($proID);
$translate = Zend_Registry::get('translate');
Zend_Validate_Abstract::setDefaultTranslator($translate);
Zend_Form::setDefaultTranslator($translate);
$contactform = new Form_ContactForm();
$contactform->setTranslator($translate);
$contactform->setAttrib('id', 'contact');
$this->view->contactform = $contactform;
$this->view->proName = $proName;
if ($request->isPost()){
if ($contactform->isValid($this->_getAllParams())){
$mailSubject = $contactform->getValue('mailsubject');
if ($contactform->mailattcht->isUploaded()) {
$contactform->mailattcht->receive();
//etc....
the form:
class Form_ContactForm extends Zend_Form
{
public function init ()
{
$this->setName("email");
$this->setMethod('post');
$this->addElement('text', 'mailsubject',
array('filters' => array('StringTrim'),
'validators' => array(), 'required' => true, 'label' => 'Subject:'));
$mailattcht = new Zend_Form_Element_File('mailattcht');
$mailattcht->setLabel('Attach File:')->setDestination(APPLICATION_PATH.'/../public/mails');
$mailattcht->addValidator('Count', false, 1);
$mailattcht->addValidator('Size', false, 8000000);
$mailattcht->addValidator('Extension', false,
'jpg,png,gif,ppt,pptx,doc,docx,xls,xslx,pdf');
$this->addElement($mailattcht, 'mailattcht');
$this->addElement('textarea', 'mailbody',
array('filters' => array('StringTrim'),
'validators' => array(), 'required' => true, 'label' => 'Body:'));
$this->addElement('submit', 'send',
array('required' => false, 'ignore' => true, 'label' => 'Send'));
$this->addElement('hidden', 'return', array(
'value' => Zend_Controller_Front::getInstance()->getRequest()->getRequestUri(),
));
$this->setAttrib('enctype', 'multipart/form-data');
}
}
I would suggest implementing AJAX validation. This would allow for the form to be verified before it is submitted. ZendCasts has a good tutorial on how to accomplish this: http://www.zendcasts.com/ajaxify-your-zend_form-validation-with-jquery/2010/04/
Ajax requests are handled via the contextSwitch action helper. You can to specify the various contexts an action needs to handle (xml or json) in the init method of the controller as follows:
public function init()
{
$this->_helper->contextSwitch()
->addActionContext('send-mail', 'json')
->initContext()
;
}
The request url should contain a "format=json" appended to the query string. This will execute the action and send the response in json format. The default behaviour of JSON context is to extract all the public properties of the view and encode them as JSON. Further details can be found here http://framework.zend.com/manual/en/zend.controller.actionhelpers.html
I found a "probably not the prettiest" working solution, it is to indeed use ajax as mentioned in the previous zendcast for validation to stop the real validation (preventdefault), process the data return the result and if everything's ok restart it.

How to get information from my controller to my form?

For a form I'm trying to add a selectbox which contains a list of items from my database.
My form is situated in /application/forms/News/Edit.php
In my controller I want to fetch this list which I want to use in my form.
How can I add that list from my controller to my form?
This is how my code in Edit.php looks like:
$this->addElement(
'select',
'view_status',
array(
'label' => 'View status',
'multioptions' => array(
//THIS SHOULD BE FILLED WITH DYNAMIC CONTENT FROM MY CONTROLLER
)
)
);
You can pass the options of your select in the first param of the form constructor. When initialising the form, Zend_Form look for a set method postfixed by the option name:
class App_Form_News_Edit extends Zend_Form
{
public function setViewStatusOptions($options)
{
$this->view_status->setMultioptions($options);
}
}
$form = new App_Form_News_Edit(array('viewStatusOptions' => array(..)));
Just use the constructor or _init function of your forms class to set any custom values you would have.
It would get you something looking like (in your controller):
$myForm = new form_News_Edit($myArrayOfValues);
Then in your forms class :
public function __construct($myArrayOfValue){
....
$this->addElement(
'select',
'view_status',
array(
'label' => 'View status',
'multioptions' => $myArrayOfValue
)
);
}
yvoyer's Solution is good too but takes out some of the business logic for the form out of it.
In your controller's action, you could initialize the options you wants depending on the action. You should set the optoions before sending the form to the view.
$Form = new form_News_Edit();
$Form->getElement('view_status')
->setMultioptions($arrayOptions);
$this->view->assign('Form', $Form);

Zend Form instantiation failing silently in white screen of death

Zend newbie trying to configure and use Zend_Form.
Just for the record I'm on Zend Framework Version: 1.11.1 on Win XP running Apache 2.something. I'm working on a site which for the most part works just fine. (Somebody else started it. I have to extend it).
I am having trouble in the area of forms and am trying to introduce Zend_Form in the hope that this will somehow simplify matters. But trying to use Zend_Form is presenting problems of it's own.
When I try to instantiate the first test form, I'm getting the white screen of death -- without even an error message.
Data as follows:
Dir Structure:
MYAPPNAME
....controllers
....forms
....models
....services
....views
Bootstrap.php contains:
protected function _initAutoLoading()
{
$loader = new Zend_Loader_Autoloader_Resource(array(
'namespace' => 'MYAPPNAME',
'basePath' => APPLICATION_PATH . '/modules/MYAPPNAME',
));
$loader->addResourceTypes(array(
'model' => array(
'path' => 'models',
'namespace' => 'Model'),
'form' => array(
'path' => 'forms',
'namespace' => 'Form'),
'service' => array(
'path' => 'services',
'namespace' => 'Service')));
}
This works fine for models with names like:
class MYAPPNAME_Model_DataRecordName extends Doctrine_Record
{
etc...
But it seems to be failing miserably for forms ... although mind you, this is my first pass at using Zend_Form.
My form is defined in file MYAPPNAME/forms/Formtest.php:
<?php
class MYAPPNAME_Form_Formtest extends Zend_Form
{
public function init($action){
$this->setAction($action)
->setMethod('post')
->setAttrib('id', 'formtestForm');
$email = $this->addElement( 'text', 'email',
array('label', => 'EMail'));
)
$submit = $this->addElement('submit', 'Submit and Be Free!');
}// End init
} // End class def
The form is being displayed in a view defined as:
<div class=""testForm">
<p style="margin-top:20px; margin-bottom:10px"">Explanatory Text</p>
<h2>This is a Form Test</h2>
<?php echo $this->formResponse; ?>
<?php echo $this->form; ?>
<hr>
<p>FORM ABOVE THIS BAR</p>
</div>
The view works just fine.
It is being managed by an action (in a working controller) defined as:
public function formtestAction(){
echo "formtestAction: ENTERED";
$form = new MYAPPNAME_Form_Formtest('ThisController/formtest2');
//$form = "<p>GARBAGE DATA</p>";
if(!empty($form)){$this->view->form = $form;}
else{
$form = "<p>THE FORM VAR IS EMPTY</p>";
$this->view->form = $form;
$formResponse = "<p>INSTANTIATION FAILED</p>";
$this->view->formResponse = $formResponse;
}
}
public function formtest2Action(){
echo "formtest2Action: ENTERED";
}
If I comment out both the form instantiation and the garbage data lines, I get valid output in the view. If I set $form to "GARBAGE DATA" I also get valid predictable output.
However when I try to instantiate the form object I get the white screen of death containing only "formtestAction: ENTERED" (from the echo statement at the top.)
I am going slowly mad.
I can't figure out if this is an autoloader problem, a routing problem, an object instantiation problem, or what.
I'd be very much obliged for any advice.
Thanks for reading.
With Zends, I've run into that several times, and it usually is something annoying as a superflous comma. In
... 'basePath' => APPLICATION_PATH . '/modules/MYAPPNAME',));
it looks just like on of those. Only a quick look, but you might check it anyway.
HTH,
Marcus
mtoepper: Very close. Good catch!
It was indeed an extra comma, only it was in the Form class definition -- preventing successful object instantiation.
These silent failures are VERY annoying.