I have a simple Zend Form that contains a textbox with setRequired(TRUE) and other validators and a simple submit button in IndexController.
My question is, is it possible another controller will process and validate my post form?
Login.php
<?php
class Application_Form_Login extends Zend_Form
{
public function init()
{
$username = $this->createElement('text', 'username');
$username->setLabel('Username:');
$username->setRequired(TRUE);
$username->addValidator(new Zend_Validate_StringLength(array('min' => 3, 'max' => 10)));
$username->addFilters(array(
new Zend_Filter_StringTrim(),
new Zend_Filter_StringToLower()
)
);
$this->addElement($username);
// create submit button
$this->addElement('submit', 'login',
array('required' => false,
'ignore' => true,
'label' => 'Login'));
}}
IndexController.php
<?php
class AttendantController extends Zend_Controller_Action
{
public function indexAction()
{
$loginForm = new Application_Form_Login();
$loginForm->setAction('/Auth/process');
$loginForm->setMethod('post');
$this->view->loginForm = $loginForm;
}
}
AuthController.php
class AuthController extends Zend_Controller_Action
{
public function processAction()
{
// How to validate the form posted here in this action function?
// I have this simple code but I'm stacked here validating the form
// Get the request
$request = $this->getRequest();
// Create a login form
$loginForm = new Application_Form_Login();
// Checks the request if it is a POST action
if($request->isPost()) {
$loginForm->populate($request->getPost());
// This is where I don't know how validate the posted form
if($loginForm->isValid($_POST)) {
// codes here
}
}
}
}
You're pretty close. In the process action you create a new instance of the login form (which you are doing), and you pass the POST data to the isValid() method of that form in order to validate. So:
public function processAction()
{
$request = $this->getRequest();
$loginForm = new Application_Form_Login();
if($request->isPost()) {
if($loginForm->isValid($request->getPost)) {
// codes here
} else {
// assign the login form back to the view so errors can be displayed
$this->view->loginForm = $loginForm;
}
}
}
Generally it is easier to display and process the form within the same action, and redirect when the submission is successful. This is the Post/Redirect/Get pattern - see http://en.wikipedia.org/wiki/Post/Redirect/Get. This saves you having to create an instance of the same form in two different actions and makes it easier to redisplay the form in case of errors.
Are you using ' ?
change $loginForm->setAction(/Auth/process); to $loginForm->setAction('/auth/process');
from processAction you may remove $login->populate($request->getPost());
Related
How can i show or hide login/logout link if user is loged in. Should this be done directly in view?
In my onDispatch i see that it is using $this->getAdminAuthService()->hasIdentity() to check if user is loged in.
How to use it in view like this?
if($this->getAdminAuthService()->hasIdentity()){
echo "login";
}
else {
echo "Logout"
}
Try this in your controller:
public function onDispatch(\Zend\Mvc\MvcEvent $e)
{
$header = new ViewModel(array('login'=>$this->getAdminAuthService()->hasIdentity()));
$header->setTemplate('layout/header');
$this->layout()->addChild($header, 'header');
}
then :
//layout/header.phtml
if($this->login){
echo "login";
} else {
echo "Logout"
}
A view helper might be a more self contained solution for this
namespace MyModule\View\Helper;
use Zend\View\Helper\AbstractHelper;
use MyModule\Service\AuthService;
class IsAuthenticated extends AbstractHelper
{
protected $authService;
public function __construct(AuthService $authService) {
$this->authService = $authService;
}
public function __invoke()
{
return $this->authService->hasIdentity();
}
}
Create a factory in your module.php
public function getViewHelperConfig()
{
return array(
'factories' => array(
'IsAuthenticated' => factory($sl) {
$authService = $sl->getServiceLocator()->get('AuthService');
return new View\Helper\IsAuthenticated($authService);
},
),
);
}
Then you can use this within the view or layout - perhaps with a view partial
if ($this->isAuthenticated()) {
// render the login/logout
$this->partial('some/view/file', array('foo', 'bar'));
}
The plugin could be expanded to proxy to other AuthService methods. However I hope this brief example shows how to go about it.
I don't know what version of ZF2 you're using, but 2.2.x ships with a view helper for checking a user's identity from the AuthenticationService out of the box.
$this->identity();
View Helper - Identity
I am learning Zend Framework and having issues with Zend_Session_Namespace.
Here is the scenario:
Homepage(user clicks on login-Index Controller)
login page(user auth is done->Login Controller)
On Successful login: Create a new zend_Session_Namespace("login") and take him to another page with home page button.
User Clicks the Home Page Button.I can Access the username from the session and display the welcome message.
User again clicks on the login page. I am checking isset($session->name) to prevent login again and take him to other page instead. --> I am failing here . The session is somehow reset , I am quite unsure what I am missing.
class IndexController extends Zend_Controller_Action
{
public function init()
{
}
public function indexAction()
{
$session = new Zend_Session_Namespace("login_session");
//Check if the session is already valid
if(isset($session->name)) {
$this->view->userLoggedIn="true";
$this->view->name=$session->name;
}
}
}
class LoginController extends Zend_Controller_Action
{
public function loginaction(){
$session = new Zend_Session_Namespace("login_session");
if(isset($session->name)){
//Redirect to New Page-Already Logged In
} else {
//Authenticate the user and if login is successful
$session->name="USER_NAME";
}
}
}
Thank You.
This code looks ok except for the previously mentioned typo.
It's possible and likely that somewhere else in your code you inadvertently overwrite the session namespace. I think we've all done that at least once.
I would suggest that instead of trying to roll your own authentication solution, use the one that ZF provides: Zend_Auth
a basic Zend_Auth login/logout might look like:
//non production code for example only
public function loginAction()
{
$form = new Application_Form_Login();
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())) {
$data = $form->getValues();
$authAdapter = new My_Auth_Adapter($data['username'], $data['password']);
//authenticate
$result = $authAdapter->authenticate();
if ($result->isValid()) {
//store the user object
$auth = Zend_Auth::getInstance();
//access Zend_Auth session namespace
$storage = $auth->getStorage();
$storage->write($authAdapter->getUser());
//add message to flashmessenger
$this->message->addMessage('Welcome');
//redirect to the homepage
return $this->_redirect('/');
} else {
//handle authentication errors
$this->view->loginMessage =
"Sorry, your username or password was incorrect";
}
} else {
//handle form validation errors
$this->_redirect('/users/index/register');
}
} else {
//if not post render empty form
$this->view->form = $form;
}
}
public function logoutAction()
{
$authAdapter = Zend_Auth::getInstance();
$authAdapter->clearIdentity();
}
http://www.ens.ro/2012/03/20/zend-authentication-and-authorization-tutorial-with-zend_auth-and-zend_acl/
Good Luck!
How can i set a input filter which is dependent from another input field.
I want to set a form field as required only when the othe form field (checkbox) is selected.
How can i handle this in zf2 ?
I use the same idea as Crisp but I prefer to do it in the Form classes instead of the controller. I think it's better to have all validators defined all together in the same place. I do it this way:
1 - All Form classes inherits from a custom BaseForm:
class BaseForm extends ProvidesEventsForm
{
private $postData;
protected function getPostData() {
return $this->postData;
}
public function __construct( $name = null, $serviceManager ) {
parent::__construct( $name );
$this->serviceManager = $serviceManager;
$this->request = $serviceManager->get( 'Application' )->getMvcEvent()->getRequest();
$this->postData = get_object_vars( $this->request->getPost() );
}
}
This way you can easily pick any value from the post, like your checkbox (you can do the same approach with the route parameters, so you'll have all the view data in your Form).
2 - In the FormEdit class that inherits from BaseForm, you pass the getPostData() value to the SomeFilter this way:
class FormEdit extends BaseForm
{
public function __construct( $name = null, $serviceManager ) {
parent::__construct( $name, $serviceManager );
$filter = new SomeFilter( $this->getPostData() );
$this->setInputFilter( $filter );
}
3 - And now just use it in the SomeFilter:
class SomeFilter extends InputFilter
{
public function __construct( $postData ) {
if ( $postData[ 'checkbox' ] ) {
$this->add( array(
'name' => 'other_input',
'required' => true,
) );
}
}
}
This way you keep the Controller clean and all the validators in the same place.
You could test if the checkbox is populated and setValidationGroup accordingly on the form before validating it in your controller action...
public function someAction()
{
$form = new MyForm; // contains name, title, checkbox, required_if_checked fields
// usual form related setup
if ($request->isPost()) {
$form->setData($request->getPost());
// see if the checkbox is checked
$checked = $this->params()->fromPost('checkbox', false);
// not checked, set validation group, omitting the dependent field
if (!$checked) {
$form->setValidationGroup(array(
'name',
'title',
'checkbox', // could probably skip this too
));
}
if ($form->isValid()) {
// do stuff with valid data
}
}
}
I am trying to make a stand alone Zend Form with a custom form element. I need use custom view helper to create this element. How do I register a custom view helper path without an application.ini file?
set_include_path(
implode(PATH_SEPARATOR, array(
get_include_path(),
PATH_TO_ZF_LIBRARY
)));
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace( 'My' );
$form = new Zend_Form;
... create and add zend form elements here
//display form
echo $form->render(new Zend_View());
Also, will the custom Zend_Form_Element know to look for the custom helper in the new path? According to the docs all I have to do is create public $helper var with the class name of the view helper. But I can't figure out if that will work with a custom view helper.
class My_Form_Element_Ssn extends Zend_Form_Element_Xhtml
{
public $helper = 'ssnElement';
public function setValue()
{
}
public function getValue()
{
return '12345';
}
}
class My_View_Helper_SsnElement
extends Zend_View_Helper_FormElement
{
public function ssnElement( $name, $value = null, $attribs = null )
{
return 'SSN';
}
}
I thank you in advance for your assistance.
Try:
$view = new Zend_View();
$view->addHelperPath('/path/to/My/View/Helper', 'My_View_Helper');
echo $form->render($view);
I've been working through the Apress book 'Pro Zend Framework Techniques'. I've hit a point where I am trying to render the form on a view.
The form is called BugReport, which is located at forms/BugReportForm.php; here is the contents of the file:
<?php
class Form_BugReportForm extends Zend_Form
{
public function init()
{
// add element: author textbox
$author = this->createElement('text', 'author');
$author->setLabel('Enter your name:');
$author->setRequired(TRUE);
$author->setAttrib('size', 30);
$this->addElement($author);
// add element: email textbox
$email = $this->createElement('text', 'email');
$email->setLabel('Your email address:');
$email->setRequired(TRUE);
$email->addValidator(new Zend_Validate_EmailAddress());
$email->addFilters(array(
new Zend_Filter_StringTrim(),
new Zend_Filter_StringToLower()
));
$email = setAttrib('size', 40);
$this->addElement($email);
// add element: date textbox
$date = $this->createElement('text', 'date');
$date->setLabel('Date the issue occurred (dd-mm-yyyy)');
$date->setRequired(TRUE);
$date->addValidator(new Zend_Validate_Date('MM-DD-YYYY'));
$date->setAttrib('size', 20);
$this->addElement($date);
// add element: URL textbox
$url = $this->createElement('text', 'url');
$url->setLabel('Issue URL:');
$url->setRequired(TRUE);
$url->setAttrib('size', 50);
$this->addElement($url);
// add element: description text area
$description = $this->createElement('textarea', 'description');
$description->setLabel('Issue description:');
$description->setRequired(TRUE);
$description->setAttrib('cols', 50);
$description->setAttrib('rows', 4);
$this->addElement($description);
// add element: priority select box
$priority = $this->createElement('select', 'priority');
$priority->setLabel('Issue priority:');
$priority->setRequired(TRUE);
$priority->addMultiOptions(array(
'low' => 'Low',
'med' => 'Medium',
'high' => 'High'
));
$this->addElement($priority);
// add element: status select box
$status = $this->createElement('select', 'status');
$status->setLabel('Current status:');
$status->setRequired(TRUE);
$status->addMultiOptions(array(
'new' => 'New',
'in_progress' => 'In Progress',
'resolved' => 'Resolved'
));
$this->addElement($status);
// add element: submit button
$this->addElement('submit', 'submit', array('label' => 'Submit'));
}
}
This form in controlled via the BugController controller located at /controllers/BugController.php
<?php
class BugController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
// action body
}
public function createAction()
{
// action body
}
public function submitAction()
{
$frmBugReport = new Form_BugReport();
$frmBugReport->setAction('/bug/submit');
$frmBugReport->setMethod('post');
$this->view->form = $frmBugReport();
}
}
And finally I have the following autoloaders in my bootstrap.
protected function _initAutoload()
{
// Add autoloader empty namespace
$autoLoader = Zend_Loader_Autoloader::getInstance();
$resourceLoader = new Zend_Loader_Autoloader_Resource(array(
'basePath' => APPLICATION_PATH,
'namespace' => '',
'resourceTypes' => array(
'form' => array(
'path' => 'forms/',
'namespace' => 'Form_',
)
),
));
// Return it so it can be stored by the bootstrap
return $autoLoader;
}
The error I am getting can be seen here: http://zend.danielgroves.net/bug/submit
Or, if you'd rather just read it: Fatal error: Class 'Form_BugReport' not found in /home/www-data/zend.danielgroves.net/htdocs/application/controllers/BugController.php on line 23
Any ideas on what I've done wrong, and so how this can be fixed?
Edit
ArneRie pointed out I was using the wrong class name, but unfortunately this hasn't fixed the issue. Here's how BugController looks now:
<?php
class BugController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
// action body
}
public function createAction()
{
// action body
}
public function submitAction()
{
$frmBugReport = new Form_BugReportForm();
$frmBugReport->setAction('/bug/submit');
$frmBugReport->setMethod('post');
$this->view->form = $frmBugReport;
}
}
Although this did get rid of the error in question, a new one has taken it's place.
Parse error: syntax error, unexpected T_OBJECT_OPERATOR in /home/www-data/zend.danielgroves.net/htdocs/application/forms/BugReportForm.php on line 8
Line 8 is interestingly /* Initialize action controller here */
You have a small typo. The bug is in your form. You are missing a $ before the "this" on line 9. Good luck with the rest of your project, it is a very good book for starters but there are a few small errors in it. Check the editors web site for details:http://www.apress.com/9781430218791/ in the errata section.
<?php
class Form_BugReportForm extends Zend_Form
{
public function init()
{
// add element: author textbox
//Next line is the line to change (add a $ before the "this")
$author = $this->createElement('text', 'author');
$author->setLabel('Enter your name:');
$author->setRequired(TRUE);
$author->setAttrib('size', 30);
$this->addElement($author);
Try it with: $frmBugReport = new Form_BugReportForm();
You're using the wrong class name.