I am a Zend Framework beginner.
I guess My question is very basic... but I can't solve it by myself.
In indexAction, $request->isPost() is always false.
What is happening?
EntryController::indexAction
public function indexAction() {
$form = new AgreementForm();
$form->get('submit')->setValue('Go Entry Form');
$request = $this->getRequest();
if ($request->isPost()) {
var_dump('//// $request->isPost() is true //////');
if ($form->get('agreementCheck')) {
// Redirect to list of entries
return $this->redirect()->toRoute('entry');
} else {
return array('form' => $form);
}
} else {
var_dump('//// $request->isPost() is false //////');
return array('form' => $form);
}
}
form in index.phtml
<?php
$form = $this->form;
$form->setAttribute('action', $this->url('entry', array('action' => 'index')));
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formCheckbox($form->get('agreementCheck'));
echo $this->formSubmit($form->get('submit'));
echo $this->form()->closeTag();
?>
AgreementForm is generated using code generator.
http://zend-form-generator.123easywebsites.com/formgen/create
as below.
class AgreementForm extends Form {
public function __construct($name = null) {
parent::__construct('');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'agreementCheck',
'type' => 'Zend\Form\Element\MultiCheckbox',
'attributes' => array(
'required' => 'required',
'value' => '0',
),
'options' => array(
'label' => 'Checkboxes Label',
'value_options' => array(
'0' => 'Checkbox',
),
),
));
$this->add(array(
'name' => 'csrf',
'type' => 'Zend\Form\Element\Csrf',
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Go',
'id' => 'submitbutton',
),
));
}
}
Please tell me some hints.
update:
In the result of analysis by Developer Tools, POST and GET works at the same time.
update:
router definition #module.config.php is this.
'router' => array(
'routes' => array(
'entry' => array(
'type' => 'segment',
'options' => array(
'route' => '/entry[/][:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Entry\Controller\Entry',
'action' => 'index',
),
),
),
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Entry\Controller\Entry',
'action' => 'index',
),
),
),
),
),
A few things are wrong:
In the form class you add a csrf element, but you don't render it in the view. This will cause a validation error. So you need to add this to your view:
echo $this->formHidden($form->get('csrf'));
You're adding a Multicheckbox element to the form, but in your view you're using the formCheckbox view helper to render it. If you really want a Multicheckbox then you should render it with the formMultiCheckbox helper:
echo $this->formMultiCheckbox($form->get('agreementCheck'));
After these changes it should work.
Edit: Also you may want to pass a name to the form constructor:
parent::__construct('agreementform');
I think, you do not need to explicitly say
$form->setAttribute('action', $this->url('entry', array('action' => 'index')));
Omit that line, and see what happens.
Related
I am working on a search form that I would like to post the searched by values in the url. I am having trouble getting the url to include the parameters however. They will post if I key in values in the view( if instead of $this->search_zip I key '12345'). Currently the search works as desired except for the url. I am currently getting the search terms from the form, would I need to change my controller setup to get them from the url instead? If this is the case how would I filter?
Ultimately I would like my url to read:
results/12345/otherparam
I am currently getting
results
No matter what variables I key into the form.
Module Config
return array(
'router' => array(
'routes' => array(
'home' => array(
'type' => 'segment',
'options' => array(
'route' => '/',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
'may_terminate' => true, //START OF CHILD ROUTES
'child_routes' => array(
'results' => array(
'type' => 'segment',
'options' => array(
'route' => 'results[/:search_zip][/:search_industry]',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'results',
Results view
$form->setAttribute('action', $this->url(
'home/results',
array(
'action' => 'results',
'search_zip'=> $this->search_zip,
'search_industry' => 'industry_name'
echo $this->formRow($form->get('industry_name'));//this is the form field
echo $this->formSubmit($form->get('submit'));
Controller
//beginning of the results action
$request = $this->getRequest();
$form = new SearchForm($dbAdapter);
if ($request->isPost()) {
$search = new MainSearch();
$form->setInputFilter($search->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
At the end of my resultsAction I return the form and the results (per the album example)
return array(
'form' => $form,
'pros' => $fetchPros,
);
Thank you,
M
//This will give you an array containing your desired parameters
$params = $this->params()->fromRoute();
//Then you can simply use them like this
$search_zip = $params['search_zip'];
$search_industry = $params['search_industry'];
Having a registration zend form in view looks like this :
<?php
$form = $this->form;
if(isset($form)) $form->prepare();
$form->setAttribute('action', $this->url(NULL,
array('controller' => 'register', 'action' => 'process')));
echo $this->form()->openTag($form);
?>
<dl class="form-signin">
<dd><?php
echo $this->formElement($form->get('name_reg'));
echo $this->formElementErrors($form->get('name_reg'));
?></dd>
<dd><?php
echo $this->formElement($form->get('email_reg'));
echo $this->formElementErrors($form->get('email_reg'));
?></dd>
<dd><?php
echo $this->formElement($form->get('password_reg'));
echo $this->formElementErrors($form->get('password_reg'));
?></dd>
<dd><?php
echo $this->formElement($form->get('confirm_password_reg'));
echo $this->formElementErrors($form->get('confirm_password_reg'));
?></dd>
<br>
<dd><?php
echo $this->formElement($form->get('send_reg'));
echo $this->formElementErrors($form->get('send_reg'));
?></dd>
<?php echo $this->form()->closeTag() ?>
And RegisterController as following.
<?php
namespace Test\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Session\Container;
use Test\Form\RegisterForm;
use Test\Form\RegisterFilter;
use Test\Form\LoginFormSm;
use Test\Form\LoginFilter;
use Test\Model\User;
use Test\Model\UserTable;
class RegisterController extends AbstractActionController
{
public function indexAction()
{
$this->layout('layout/register');
$form = new RegisterForm();
$form_sm = new LoginFormSm();
$viewModel = new ViewModel(array(
'form' => $form,
'form_sm' =>$form_sm,
));
return $viewModel;
}
public function processAction()
{
$this->layout('layout/register');
if (!$this->request->isPost()) {
return $this->redirect()->toRoute(NULL,
array( 'controller' => 'index'
)
);
}
$form = $this->getServiceLocator()->get('RegisterForm');
$form->setData($this->request->getPost());
if (!$form->isValid()) {
$model = new ViewModel(array(
'form' => $form,
));
$model->setTemplate('test/register/index');
return $model;
}
// Creating New User
$this->createUser($form->getData());
return $this->redirect()->toRoute(NULL, array (
'controller' => 'auth' ,
));
}
protected function createUser(array $data)
{
$userTable = $this->getServiceLocator()->get('UserTable');
$user = new User();
$user->exchangeArray($data);
$userTable->saveUser($user);
return true;
}
}
Also a RegisterForm where are declared all variables shown in index. Also RegisterFilter as following:
<?php
namespace Test\Form;
use Zend\InputFilter\InputFilter;
class RegisterFilter extends InputFilter
{
public function __construct()
{
$this->add(array(
'name' => 'email_reg',
'required' => true,
'filters' => array(
array(
'name' => 'StripTags',
),
array(
'name' => 'StringTrim',
),
),
'validators' => array(
array(
'name' => 'EmailAddress',
'options' => array(
'domain' => true,
'messages' => array(
\Zend\Validator\EmailAddress::INVALID_FORMAT => 'Email address format is invalid'
),
),
),
array(
'name' => 'AbstractDb',
'options' => array(
'domain' => true,
'messages' => array(
\Zend\Validator\Db\AbstractDb::ERROR_RECORD_FOUND => 'Current Email Already registered'
),
),
),
),
));
$this->add(array(
'name' => 'name_reg',
'required' => true,
'filters' => array(
array(
'name' => 'StripTags',
),
array(
'name' => 'StringTrim',
),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 2,
'max' => 140,
),
),
),
));
$this->add(array(
'name' => 'password_reg',
'required' => true,
'validators' => array(
array(
'name' => 'StringLength',
'options' =>array(
'encoding' => 'UTF-8',
'min' => 6,
'messages' => array(
\Zend\Validator\StringLength::TOO_SHORT => 'Password is too short; it must be at least %min% ' . 'characters'
),
),
),
array(
'name' => 'Regex',
'options' =>array(
'pattern' => '/[A-Z]\d|\d[A-Z]/',
'messages' => array(
\Zend\Validator\Regex::NOT_MATCH => 'Password must contain at least 1 digit and 1 upper-case letter'
),
),
),
),
));
$this->add(array(
'name' => 'confirm_password_reg',
'required' => true,
'validators' => array(
array(
'name' => 'Identical',
'options' => array(
'token' => 'password_reg', // name of first password field
'messages' => array(
\Zend\Validator\Identical::NOT_SAME => "Passwords Doesn't Match"
),
),
),
),
));
}
}
Problem
All i need is to throw a message when somebody tries to register and that e-mail is already registered. Tried with \Zend\Validator\Db\AbstractDb and added following validator to email in RegisterFilter as following
array(
'name' => 'AbstractDb',
'options' => array(
'domain' => true,
'messages' => array(
\Zend\Validator\Db\AbstractDb::ERROR_RECORD_FOUND => 'Current Email Already registered'
),
),
),
But that seems not to work.
Question: Is there a way to implement this validator in RegisterController?
Additional.
I've deleted from RegisterFilert validator and put inside Module.ph
'EmailValidation' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$validator = new RecordExists(
array(
'table' => 'user',
'field' => 'email',
'adapter' => $dbAdapter
)
);
return $validator;
},
And call it from RegisterController
$validator = $this->getServiceLocator()->get('EmailValidation');
if (!$validator->isValid($email)) {
// email address is invalid; print the reasons
$model = new ViewModel(array(
'error' => $validator->getMessages(),
'form' => $form,
));
$model->setTemplate('test/register/index');
return $model;
}
And when i use print_r inside view to check for it shows.
Array ( [noRecordFound] => No record matching the input was found ).
I want just to echo this 'No record matching the input was found'.
Fixed
Modified in RegisterController as following
$validator = $this->getServiceLocator()->get('EmailValidation');
$email_ch = $this->request->getPost('email_reg');
if (!$validator->isValid($email_ch)) {
// email address is invalid; print the reasons
$model = new ViewModel(array(
'error' => 'Following email is already registered please try another one',
'form' => $form,
));
$model->setTemplate('test/register/index');
return $model;
}
I had compared
if (!$validator->isValid($email_ch))
Before with nothing and that's why i needed to add first
$email_ch = $this->request->getPost('email_reg');
You don't have to do that in your controller, just try this in your RegisterFilter class :
First : Add $sm as parameter of the _construct() method :
public function __construct($sm) {....}
Second: Replace e-mail validation by this one :
$this->add ( array (
'name' => 'email_reg',
'required' => true,
'validators' => array(
array(
'name' => 'Zend\Validator\Db\NoRecordExists',
'options' => array(
'table' => 'user',
'field' => 'email',
'adapter' => $sm->get ( 'Zend\Db\Adapter\Adapter' ),
'messages' => array(
NoRecordExists::ERROR_RECORD_FOUND => 'e-mail address already exists'
),
),
),
),
)
);
When you call the RegisterFilter don't forget to pass the serviceLocator as parameter in your controller :
$form->setInputFilter(new RegisterFilter($this->getServiceLocator()));
Supposing you have this in your global.php File (config\autoload\global.php) :
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
To your previous request, ("I want just to echo this 'No record matching the input was found'")
$validator = $this->getServiceLocator()->get('EmailValidation');
$email_ch = $this->request->getPost('email_reg');
if (!$validator->isValid($email_ch)) {
// email address is invalid; print the reasons
foreach ($validator->getMessages() as $message) {
$msg = $message;
}
$model = new ViewModel(array(
'error' => $msg,
'form' => $form,
));
$model->setTemplate('test/register/index');
return $model;
}
I got an answer to this question here, but now I have another concern\problem.
I have a subnav bar in my module created from a view partial via a helper.
Here is the config in module.config.php:
'navigation' => array(
'default' => array(
array(
'label' => 'Search',
'route' => 'mymodule\search',
),
array(
'label' => 'Log Off',
'route' => 'logout',
),
),
),
I have a LoginController with 2 actions: login and logout. After logging in I want the user to click the logout button, be redirected to the login page and have their session cleared.
Now if I have a login and logout action I need a template for each. This seems unnecessary for the logout action- I don't want another template to load for this action.
Here's my routing config:
'login' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/login',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Application\Controller\Login',
'action' => 'login',
),
),
),
'logout' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/login',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Application\Controller\Login',
'action' => 'logout',
),
),
),
Is there a correct way to have an action get called without loading a corresponding template?
You can return a response object instead:
public function logoutAction()
{
// do stuff
return $this->redirect()->toRoute('login');
}
then you don't need a template.
On zf2
public function Action(){
$vm = new ViewModel();
$vm->setTerminal(true);
return $vm;
}
EDIT:::
In case that you want to return a custom response you can do:
public function Action(){
return $this->getResponse()->setContent("Hello world!");
}
This is my navigation in global.php
'navigation' => array(
'default' => array(
'loja' => array(
'label' => 'Loja',
'route' => 'loja',
'params' => array('action'=>'index'),
'pages' => array(
'estoque' => array(
'label' => 'Estoque',
'params' => array('action'=>'index'),
'action'=>'index',
'id' => 'estoque',
'route' => 'estoque',
)),
),
'suport'=> array(
'test' => array(
'label' => 'Loja',
'route' => 'loja',
'params' => array('action'=>'index'),
'pages' => array(
'estoque' => array(
'label' => 'Estoque',
'params' => array('action'=>'index'),
'action'=>'index',
'id' => 'estoque',
'route' => 'estoque',
)),
),),
when I call navigation the 'default' comes, I want to call the navigation 'suport', how I can do it?
My code in layout.phtml ..
echo $this->navigation('Navigation')->menu()->setUlClass('nav dropdown-submenu')->renderMenu();
Thanks :)
First create a container:
<?php $container = $this->navigation()->findOneByLabel('support');?>
Read more about finding nodes here: http://framework.zend.com/manual/2.2/en/modules/zend.navigation.containers.html
Than use it:
<?php echo $this->navigation()->menu()->renderMenu($container);?>
(Put this in your view script.)
Read more about this in the docs: http://framework.zend.com/manual/2.2/en/modules/zend.navigation.view.helper.menu.html
Can You Try This in view script:
Create Container Like this
<?php $container = $this->navigation('support')->getContainer(); ?>
Echo the Container to use this one:
<?php echo $this->navigation($container); ?>
Create your own navigation factory by extending Zend\Navigation\Service\DefaultFactory
namespace Application\Navigation\Service;
use Zend\Navigation\Service\DefaultNavigationFactory;
class MyNavigation extends DefaultNavigationFactory
{
public function getName() {
return 'suport';
}
}
and in Module.php
public function getServiceConfig()
{
return array(
'invokables' => array(
'my_navigation' => 'Application\Navigation\Service\MyNavigation'
}
}
}
Now you can use your navigation echo $this->navigation('my_navigation')->menu()
I have a little problem generate captcha in ZF2
Here is my Controller:
public function indexAction()
{
$form = new RegisterForm();
return array('form' => $form);
}
RegisterForm class:
public function __construct($name = null)
{
$this->url = $name;
parent::__construct('register');
$this->setAttributes(array(
'method' => 'post'
));
$this->add(array(
'name' => 'password',
'attributes' => array(
'type' => 'password',
'id' => 'password'
)
));
$this->get('password')->setLabel('Password: ');
$captcha = new Captcha\Image();
$captcha->setFont('./data/captcha/font/arial.ttf');
$captcha->setImgDir('./data/captcha');
$captcha->setImgUrl('./data/captcha');
$this->add(array(
'type' => 'Zend\Form\Element\Captcha',
'name' => 'captcha',
'options' => array(
'label' => 'Captcha',
'captcha' => $captcha,
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'button',
'value' => 'Register',
),
));
}
View: index.phtml:
...
<div class="group">
<?php echo $this->formlabel($form->get('captcha')); ?>
<div class="control-group">
<?php echo $this->formElementErrors($form->get('captcha')) ?>
<?php echo $this->formCaptcha($form->get('captcha')); ?>
</div>
</div>
...
Above code generate png images in data/captcha folder, but i can't generate them in view.
FireBug shows img element and url, but url to image seems to be empty.
Thanks for any help.
You have to set the img url correctly and define the route in your module.config.php
Controller
public function indexAction()
{
$form = new RegisterForm($this->getRequest()->getBaseUrl().'test/captcha');
return array('form' => $form);
}
remember to change the test/captcha to your own base url
in your registerForm class
public function __construct($name)
{
//everything remain the same, just change the below statement
$captcha->setImgUrl($name);
}
add this to your module.config.php, as your main route child
'may_terminate' => true,
'child_routes' => array(
'registerCaptcha' => array(
'type' => 'segment',
'options' => array(
'route' => '/[:action[/]]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'action' => 'register',
),
),
),
'captchaImage' => array(
'type' => 'segment',
'options' => array(
'route' => '/captcha/[:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'controller',
'action' => 'generate',
),
),
),
),
remember to change the controller under captcha image, the action generate is actually generating the captcha image file
add this to your controller file as well
public function generateAction()
{
$response = $this->getResponse();
$response->getHeaders()->addHeaderLine('Content-Type', "image/png");
$id = $this->params('id', false);
if ($id) {
$image = './data/captcha/' . $id;
if (file_exists($image) !== false) {
$imagegetcontent = #file_get_contents($image);
$response->setStatusCode(200);
$response->setContent($imagegetcontent);
if (file_exists($image) == true) {
unlink($image);
}
}
}
return $response;
}
with these, it should be working fine