I'm using AbstractTableGateway and HydratingResultset to do db operations. (with BjyProfiler)
when i post my form data with add action it works, but edit action doesn't work. when i make a bind it works, but i m redirected to the add page because submitting the form resets paramaters coming from route.
here is my code for editAction() (same with Album editAction())
$id = (int)$this->params()->fromRoute('id');
if (!$id) {
return $this->redirect()->toRoute('voyage', array('action'=>'add'));
}
$voyage = $this->getVoyageTable()->getVoyage($id);
$form = new VoyageForm($this->getTypeVoyageTable());
$form->bind($voyage);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getVoyageTable()->saveVoyage($voyage);
// Redirect to list of voyages
return $this->redirect()->toRoute('voyage');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
and my table :
class VoyageTable extends AbstractTableGateway
{
protected $table ='voyages';
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new HydratingResultSet();
$this->resultSetPrototype->setObjectPrototype(new Voyage());
$this->initialize();
}
[...]
Can sombody help me? How can i fix this problem ? Thanks.
You need to inform the form about the hydrator since ClassMethods is not the default
$form->setHydrator(new ClassMethods());
Related
I am trying to update records in my database. I am following a book but something isnt working.
This is the edit action. On post form action leads to process action.
public function editAction()
{
$userTable = $this->getServiceLocator()->get('UserTable');
$user = $userTable->getUser($this->params()->fromRoute('id'));
$form = $this->getServiceLocator()->get('UserEditForm');
$form->bind($user);
$viewModel = new ViewModel(array(
'form' => $form,
'user_id' => $this->params()->fromRoute('id')
));
return $viewModel;
}
Process action
public function processAction()
{
// Get User ID from POST
$post = $this->request->getPost();
$userTable = $this->getServiceLocator()->get('UserTable');
// Load User entity
$user = $userTable->getUser($post->id);
// Bind User entity to Form
$form = $this->getServiceLocator()->get('UserEditForm');
$form->bind($user);
$form->setData($post);
// Save user
$this->getServiceLocator()->get('UserTable')->saveUser($user);
}
And this is the class UserTable with function save user:
public function saveUser(User $user)
{
$data = array(
'email' => $user->email,
'name' => $user->name,
'password' => $user->password,
);
$id = (int)$user->id;
if ($id == 0) {
$this->tableGateway->insert($data);
} else {
if ($this->getUser($id)) {
$this->tableGateway->update($data, array('id' => $id));
} else {
throw new \Exception('User ID does not exist');
}
}
}
There is no error showing. It passes $this->tableGateway->update and just nothing !
EDIT: I can delete users, add users.
u miss this
if ($form->isValid()) {
$this->getServiceLocator()->get('UserTable')->saveUser($form->getData());
}
After validation you can now retrieve validate form data with $form->getData().
Also note that because of binding entity to form via $form->bind($user) $form->getData() is an instance of User
Hope it helps ;)
I dont know why but i must check if form is valid.
if($form->isValid()){
// do the save
}
Hi everyone I'm new with Zend Framework 2 , for ruthentification on my project i used this module (( http://samsonasik.wordpress.com/2013/05/29/zend-framework-2-working-with-authenticationservice-and-db-session-save-handler/#comment-5393 )) and i add the field "Role" on data base.
I want to ask how can i make a specific route for any member of user, for example if the user’s Admin when he connect he will be redirected automatically to route “Admin” and if the user’s “visitor” he will be redirected to route “visitor” ???
Thx
/** this function called by indexAction to reduce complexity of function */
protected function authenticate($form, $viewModel)
{
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$dataform = $form->getData();
$this->authService->getAdapter()
->setIdentity($dataform['username'])
->setCredential($dataform['password']);
$result = $this->authService->authenticate();
if ($result->isValid()) {
//authentication success
$resultRow = $this->authService->getAdapter()->getResultRowObject();
$this->authService->getStorage()->write(
array('id' => $resultRow->id,
'username' => $dataform['username'],
'ip_address' => $this->getRequest()->getServer('REMOTE_ADDR'),
'user_agent' => $request->getServer('HTTP_USER_AGENT'))
);
// your userid -> select the role
$role = $this->getRoleUser($resultRow->id);
return $this->redirect()->toRoute('success', array('action' => 'index', 'role'=>$role));
} else {
$viewModel->setVariable('error', 'Login Error');
}
}
}
}
Then into your success page, just perform some actions using the param role
Don't forget to create a function $role = $this->getRoleUser($resultRow->id); to get the role of the user.
To implement roles function
check before this documentation to how to configure and create models/database: http://framework.zend.com/manual/2.1/en/user-guide/database-and-models.html
protected function getRoleUser($userid){
$table = $this->getServiceLocator()->get('User\Model\UserTable');
return $table->find($userid)->current()->role;
}
Hi I created two modules first application second comment.
Idea is to use comment module(Widget) in any application action (website page).
Application module
Test controller
public function commentAction(){
//seting redirection for form
$this->getCommentService()->setRedirection('test/comment');
$list = $this->forward()->dispatch('comment_controrller', array('action' => 'list'));
$add = $this->forward()->dispatch('comment_controrller', array('action' => 'add'));
$view = new ViewModel();
$view->addChild($list, 'list');
$view->addChild($add, 'add');
return $view;
}
View
Comment module
Comment controller
public function addAction()
{
$form = new CommentForm();
$form->get('submit')->setAttribute('value', 'Add');
$request = $this->getRequest();
if ($request->isPost()) {
$comment = new Comment();
$form->setInputFilter($comment ->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$comment ->exchangeArray($form->getData());
$this->getCommentTable()->saveComment($comment);
// Redirect to test controller in application module
return $this->redirect()->toRoute($this->getCommentService()->getRedirection());
}
}
return array('form' => $form);
}
public function listAction()
{
return new ViewModel(array(
$list=> 'test'
));
}
With simple variable (list) all working fine,
Problem I get when trying to redirect form back to comment action in test controller
I can add redirection to test/comment in case form is not valid
but how I will pass all validating errors to test/comment(form)
Can you tell me, if what I'm doing logically correct or in ZF2 we have different way to do widgets
Thanks for help
Answer from weierophinney
http://zend-framework-community.634137.n4.nabble.com/zf2-widget-base-app-logic-td4657457.html
This what I've got so far:
https://github.com/nsenkevich/comment
I need to get the adapter from the form, but still could not.
In my controller I can recover the adapter using the following:
// module/Users/src/Users/Controller/UsersController.php
public function getUsersTable ()
{
if (! $this->usersTable) {
$sm = $this->getServiceLocator();
$this->usersTable = $sm->get('Users\Model\UsersTable');
}
return $this->usersTable;
}
In my module I did so:
// module/Users/Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Users\Model\UsersTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$uTable = new UsersTable($dbAdapter);
return $uTable;
},
//I need to get this to the list of groups
'Users\Model\GroupsTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$gTable = new GroupsTable($dbAdapter);
return $gTable;
},
),
);
}
Could someone give me an example how to get the adapter to the table from the group form?
I have followed this example to my form users:
http://framework.zend.com/manual/2.0/en/modules/zend.form.collections.html
EDITED from here...
Maybe I expressed myself wrong to ask the question.
What I really need to do is populate a select (Drop Down) with information from my table groups.
So I need to get the services inside my userForm class by ServiceLocatorAwareInterface (see this link) implemented because By default, the Zend Framework MVC registers an initializer That will inject into the ServiceManager instance ServiceLocatorAwareInterface Implementing any class.
After retrieving the values from the table groups and populate the select.
The problem is that of all the ways that I've tried, the getServiceLocator() returns this:
Call to a member function get() on a non-object in
D:\WEBSERVER\htdocs\Zend2Control\module\Users\src\Users\Form\UsersForm.php
on line 46
I just wanted to do this in my UserForm...
namespace Users\Form;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Form\Element;
use Zend\Form\Form;
class UsersForm extends Form implements ServiceLocatorAwareInterface
{
protected $serviceLocator;
public function getServiceLocator ()
{
return $this->serviceLocator;
}
public function setServiceLocator (ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
public function __construct ($name = null)
{
parent::__construct('users');
$this->setAttribute('method', 'post');
$sm = $this->getServiceLocator();
$groups = $sm->get('Users\Model\GroupsTable')->fetchAll(); // line 46
$select = new Element\Select('groups');
$options = array();
foreach ($groups as $group) {
$options[$group->id] = $group->name;
}
$select->setValueOptions($options);
$this->add($select);
// and more elements here...
The other various answers here generally correct, for ZF < 2.1.
Once 2.1 is out, the framework has a pretty nice solution. This more or less formalizes DrBeza's solution, ie: using an initializer, and then moving any form-bootstrapping into an init() method that is called after all dependencies have been initialized.
I've been playing with the development branch, it it works quite well.
This is the method I used to get around that issue.
firstly, you want to make your form implement ServiceLocatorInterface as you have done.
You will then still need to manually inject the service locator, and as the whole form is generated inside the contrstuctor you will need to inject via the contructor too (no ideal to build it all in the constructor though)
Module.php
/**
* Get the service Config
*
* #return array
*/
public function getServiceConfig()
{
return array(
'factories' => array(
/**
* Inject ServiceLocator into our Form
*/
'MyModule\Form\MyForm' => function($sm) {
$form = new \MyModule\Form\MyFormForm('formname', $sm);
//$form->setServiceLocator($sm);
// Alternativly you can inject the adapter/gateway directly
// just add a setter on your form object...
//$form->setAdapter($sm->get('Users\Model\GroupsTable'));
return $form;
},
),
);
}
Now inside your controller you get your form like this:
// Service locator now injected
$form = $this->getServiceLocator()->get('MyModule\Form\MyForm');
Now you will have access to the full service locator inside the form, to get hold of any other services etc such as:
$groups = $this->getServiceLocator()->get('Users\Model\GroupsTable')->fetchAll();
In module.php I create two services. See how I feed the adapter to the form.
public function getServiceConfig()
{
return array(
'factories' => array(
'db_adapter' => function($sm) {
$config = $sm->get('Configuration');
$dbAdapter = new \Zend\Db\Adapter\Adapter($config['db']);
return $dbAdapter;
},
'my_amazing_form' => function ($sm) {
return new \dir\Form\SomeForm($sm->get('db_adapter'));
},
),
);
}
In the form code I use that feed to whatever:
namespace ....\Form;
use Zend\Form\Factory as FormFactory;
use Zend\Form\Form;
class SomeForm extends Form
{
public function __construct($adapter, $name = null)
{
parent::__construct($name);
$factory = new FormFactory();
if (null === $name) {
$this->setName('whatever');
}
}
}
We handle this in the model, by adding a method that accepts a form
public function buildFormSelectOptions($form, $context = null)
{
/**
* Do this this for each form element that needs options added
*/
$model = $this->getServiceManager()->get('modelProject');
if (empty($context)){
$optionRecords = $model->findAll();
} else {
/**
* other logic for $optionRecords
*/
}
$options = array('value'=>'', 'label'=>'Choose a Project');
foreach ($optionRecords as $option) {
$options[] = array('value'=>$option->getId(), 'label'=>$option->getName());
}
$form->get('project')->setAttribute('options', $options);
}
As the form is passed by reference, we can do something like this in the controller where the form is built:
$builder = new AnnotationBuilder();
$form = $builder->createForm($myEntity);
$myModel->buildFormSelectOptions($form, $myEntity);
$form->add(array(
'name' => 'submitbutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Submit',
'id' => 'submitbutton',
),
));
$form->add(array(
'name' => 'cancel',
'attributes' => array(
'type' => 'submit',
'value' => 'Cancel',
'id' => 'cancel',
),
));
Note: The example assumes the base form is build via annotations, but it doesn't matter how you create the initial form.
An alternative method to the other answers would be to create a ServiceManager Initializer.
An example of an existing Initializer is how the ServiceManager is injected if your instance implements ServiceLocatorAwareInterface.
The idea would be to create an interface that you check for in your Initialiser, this interface may look like:
interface FormServiceAwareInterface
{
public function init();
public function setServiceManager(ServiceManager $serviceManager);
}
An example of what your Initializer may look like:
class FormInitializer implements InitializerInterface
{
public function initialize($instance, ServiceLocatorInterface $serviceLocator)
{
if (!$instance instanceof FormServiceAwareInterface)
{
return;
}
$instance->setServiceManager($serviceLocator);
$instance->init();
}
}
Anything that happens in init() would have access to the ServiceManager. Of course you would need to add your initializer to your SM configuration.
It is not perfect but it works fine for my needs and can also be applied to any Fieldsets pulled from the ServiceManager.
This is the way I used get around that issue.
firstly, In Module.php, create the service (just as you have done):
// module/Users/Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Users\Model\UsersTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$uTable = new UsersTable($dbAdapter);
return $uTable;
},
//I need to get this to the list of groups
'Users\Model\GroupsTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$gTable = new GroupsTable($dbAdapter);
return $gTable;
},
),
);
}
Then in the controller, I got a reference to the Service:
$users = $this->getServiceLocator()->get('Test\Model\TestGroupTable')->fetchAll();
$options = array();
foreach ($users as $user)
$options[$user->id] = $user->name;
//get the form element
$form->get('user_id')->setValueOptions($options);
And viola, that work.
I'm creating my own blog engine to learn Symfony, and I have a question :
In the generated administration pages for a blog post, I have a drop-down list of authors, to indicate the author_id.
I'd like to hide that drop-down list, and set the author_id to the id of the current logged-in user when the post is created (but not when it is edited)
How can I accomplish that ?
Edit
I've tried those :
$request->setParameter(sprintf("%s[%s]", $this->form->getName(), "author_id"), $this->getUser()->getAttribute("user_id"));
$request->setParameter("content[author_id]", $this->getUser()->getAttribute("user_id"));
$request->setParameter("author_id", $this->getUser()->getAttribute("user_id"));
$request->setParameter("author_id", 2);
$request->setParameter("content[author_id]", 2);
$request->setParameter("author_id", "2");
$request->setParameter("content[author_id]", "2");
In processForm() and executeCreate()
Resolved !
The final code is :
public function executeCreate(sfWebRequest $request)
{
$form = $this->configuration->getForm();
$params = $request->getParameter($form->getName());
$params["author_id"] = $this->getUser()->getGuardUser()->getId();;
$request->setParameter($form->getName(), $params);
parent::executeCreate($request);
}
Override the executeCreate function in the actions file. When binding post data to the form, merge the current user's id into it.
2nd update
I did some experimenting, and this works:
class fooActions extends autoFooActions
{
public function executeCreate(sfWebRequest $request)
{
$form = $this->configuration->getForm();
$params = $request->getParameter($form->getName());
$params["author_id"] = 123;
$request->setParameter($form->getName(), $params);
parent::executeCreate($request);
}
}
change the widget in the form with the sfWidgetFormInputHidden and set the value with sfUser attribute (that defined when a user logged in)
override the executeCreate() and set the author_id widget (thanks to maerlyn :D )
public function executeCreate(sfWebRequest $request){
parent::executeCreate($request);
$this->form->setWidget('author_id', new sfWidgetFormInputHidden(array(),array('value'=>$this->getUser()->getAttribute('author_id'))) );
}
In Objects , the solution is: (new and $this)
class fooActions extends autoFooActions
{
public function executeCreate(sfWebRequest $request)
{
$this->form = new XxxxxForm();
$params = $request->getParameter($this->form->getName());
$params["author_id"] = 123;
$request->setParameter($this->form->getName(), $params);
parent::executeCreate($request);
}
}