I want to create a register handler. I have a User entity and Register.php. Register.php extends User, registers set hashing password and returns results.
Code:
public function registerAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createTestForm(new User);
$form->handleRequest($request);
if ($form->isValid()) {
$service = new Register($form->getData());
$register = $service->register();
$em->persist($register);
$em->flush();
// return $this->redirectToRoute(...);
}
return $this->render('AcmeExampleBundle:User:test.html.twig', array(
'form' => $form->createView(),
));
}
I get this error: The class 'Acme\ExampleBundle\Libs\Register' was not found in the chain configured namespaces AcmeExample\Bundle\Entity
Related
How to configure module.php?
I am trying to fetch data from two tables with in 2 different views using different controllers.
Below is my code that shows you what I am doing in my module, business controller and registration controller.
Module.php
public function getServiceConfig(){
return array(
'factories' => array(
// Instantiating StudentTable class by injecting TableGateway
'TaskForce\Model\RegistrationTable'=>function($sm){
$registerationGateway = $sm->get('RegistrationTableGateway');
$table = new RegistrationTable($registerationGateway);
return $table;
},
//Instantiating TableGateway to inject to StudentTable class
'RegistrationTableGateway'=>function($sm){
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Registration());
return new TableGateway('users', $dbAdapter,null,$resultSetPrototype);
},
'TaskForce\Model\BusinessTable'=>function($sm){
$businessGateway = $sm->get('BusinessTableGateway');
$businesstable = new BusinessTable($businessGateway);
return $businesstable;
},
//Instantiating TableGateway to inject to StudentTable class
'BusinessTableGateway'=>function($sm){
$dbAdapter2 = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype2 = new ResultSet();
$resultSetPrototype2->setArrayObjectPrototype(new Business());
return new TableGateway('business', $dbAdapter2,null,$resultSetPrototype2);
},
)
);
}
BusinessController.php
public function indexAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
return new ViewModel(array(
// Fetching data from database
'business'=>$this->getBusinessTable()->fetchAll()
));
}
and RegistrationController.php
public function indexAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
$form = new RegistrationForm();
$request = $this->getRequest();
if ($request->isPost()) {
$registration = new Registration();
//$form->get('submit')->setAttribute('value', 'Add New User');
$post = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
$form->setData($post);
if ($form->isValid()) {
$registration->exchangeArray($form->getData());
$this->getRegistrationTable()->saveRegistration($registration);
// Redirect to list of users
return $this->redirect()->toRoute('registration');
}
}
return new ViewModel(array(
'form' => $form
));
}
If there is a relationship between the Business and the Registration records, you may wish to clarify it. However, if it is simply a matter of code arrangement, you can do this:
BusinessController.php
public function indexAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
return new ViewModel(array(
// Fetching data from database
'business'=>$this->getBusinessTable()->fetchAll(),
'registration' => $this->getRegistrationTable()->fetchAll(),
));
}
RegistrationController.php
public function indexAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
return new ViewModel(array(
// Fetching data from database
'business'=>$this->getBusinessTable()->fetchAll(),
'registration' => $this->getRegistrationTable()->fetchAll(),
));
}
// rename your index action in registrationcontroller.php to form
// so that the form is displayed on the formAction
public function formAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
$form = new RegistrationForm();
$request = $this->getRequest();
if ($request->isPost()) {
$registration = new Registration();
//$form->get('submit')->setAttribute('value', 'Add New User');
$post = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
$form->setData($post);
if ($form->isValid()) {
$registration->exchangeArray($form->getData());
$this->getRegistrationTable()->saveRegistration($registration);
// Redirect to list of users
return $this->redirect()->toRoute('registration');
}
}
return new ViewModel(array(
'form' => $form
));
}
I have a simple registration form which has 3 fields. Email, name and password. So far so good. I'm able to create new users. The problem comes when I want to edit user information.
I want to update password field in the database only if html password field is not empty
public function editAction(User $user, Request $request)
{
$form = $this->createForm(new UserForm(), $user);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->redirectToRoute('bd_user_list');
}
return $this->render('BDUserBundle:User:add.html.twig', [
'form' => $form->createView()
]);
}
If I left password field blank I get this error (which is normal)
An exception occurred while executing 'UPDATE users SET password = ? WHERE id = ?' with params [null, 5]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'password' cannot be null
I've read about validation groups but I'm not sure they can help.
// the solution
UserForm.php
[...]
builder->addEventSubscriber(new UserFormListener());
[...]
UserFormListener.php
<?php
namespace SDUserBundle\Form\EventListener;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class UserFormListener implements EventSubscriberInterface
{
private $password;
public static function getSubscribedEvents()
{
return array(
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::POST_SUBMIT => 'postSubmit'
);
}
public function preSetData(FormEvent $event)
{
$this->password = $event->getData()->getPassword();
}
public function postSubmit(FormEvent $event)
{
$data = $event->getData();
if ($data->getPassword() == false) {
$data->setPassword($this->password);
}
}
}
Fast solution
Modify your code as follows
public function editAction(User $user, Request $request)
{
$old_pwd = $user->getPassword(); //or whatever the method is called
$form = $this->createForm(new UserForm(), $user);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$em = $this->getDoctrine()->getManager();
if (null == $user->getPassword()) {
$user->setPassword($old_pwd);
}
$em->persist($user);
$em->flush();
$this->redirectToRoute('bd_user_list');
}
return $this->render('BDUserBundle:User:add.html.twig', [
'form' => $form->createView()
]);
}
More elegant solution
This is a first solution but involves some logic inside controller; maybe you need that code elsewhere, so you could migrate it into form events like FormEvents::PRE_SET_DATA
So you need to modify your UserForm as follows
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
[...]
class UserForm extends AbstractType
{
private $old_pwd;
[...]
$builder
[...]
->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
$data = $event->getData();
$this->old_pwd = $data->getPassword();
})
->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
$data = $event->getData();
if (false == $data->getPassword()) {
$data->setPassword($this->old_pwd);
$this->setData($data);
}
})
}
I really don't know if second approach is a working one as I can't test it at the moment but FormEvents should help you accomplish what you need.
Another approach, not so good?
Maybe you could modify User setter directly
class User
{
[...]
public function setPassword($pwd)
{
if ($pwd) {
$this->pwd = //logic here to store a safe pwd
}
}
}
Why this third solution is the worst at all I let you to find yourself ;)
Side note
Just to let you know that isValid() take care for you about submitted controls from Symfony2.3 on so you don't need isSubmitted() control explicitly
when I try to update one of my entites, I get this exception:
UndefinedMethodException: Attempted to call method "bindRequest" on class "Symfony\Component\Form\Form" in /Applications/MAMP/htdocs/Seotool/src/Seotool/MainBundle/Controller/TaskController.php line 64.
edit Action:
/**
#Route(
* path = "/tasks/edit/{id}",
* name = "edit_task"
* )
* #Template()
*/
public function edit_taskAction($id, Request $request)
{
$request = $this->get('request');
if (is_null($id)) {
$postData = $request->get('task');
$id = $postData['id'];
}
$em = $this->getDoctrine()->getManager();
$task = $em->getRepository('SeotoolMainBundle:Task')->find($id);
$form = $this->createForm(new TaskType(), $task);
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
// perform some action, such as save the object to the database
$em->flush();
return $this->redirect($this->generateUrl('taskmanager'));
}
}
return array('form' => $form->createView());
}
What's wrong with my code?
Because there is no method bindRequest. The exception is quite explicit. If you check the official API, I suppose you want to use handleRequest
I have this code in two methods (create and update). Each time I need to update or create a new user I need to encode the user password with the salt.
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($entity);
$password = $encoder->encodePassword($entity->getPassword(), $entity->getSalt());
$entity->setPassword($password);
To avoid code duplication what should I do?
Create a new method in controller getEncondedPassword($entity) : return $encodedPassword
Add this logic to the Form using DI injecting the $encoder as required field
Add this logic to model, and pass the $encoder in the constructor of the entity object.
Thank you!
If your create and edit are fairly simple and pretty much the same, you can combine it to one function which actually generates and validates the form.
Some code:
class ProductController extends Controller
{
/**
* #Route("/create", name="_product_create")
*/
public function createAction()
{
$product = new Product();
return $this->productForm($product, $this->getRequest(), 'create');
}
/**
* #Route("/edit/{product_id}", name="_product_edit_id")
*/
public function editIdAction($product_id)
{
$entity_manager = $this->getDoctrine()->getEntityManager();
$product_repository = $entity_manager->getRepository('VendorBundle:Product');
$product = $product_repository->findOneBy(
array('id' => $product_id)
);
return $this->productForm($product, $this->getRequest(), 'editId');
}
protected function productForm(Product $product, Request $request, $twig_name)
{
$form = $this->createForm(new ProductType(), $product);
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
// Do whatever we want before persisting/flushing
return $this->redirect($redirect_url);
}
}
$twig_params = array(
);
return $this->render(
'VendorBundle:Product:' . $twig_name . '.html.twig', $twig_params
);
}
}
this will render create.html.twig and editId.html.twig depending on the route.
if $product->getId() === null we are creating a new entity, else we are editing.
I think that the correct option is the model/entity approach.
So, I leave here the my solution:
public function hashPassword($container)
{
$factory = $container->get('security.encoder_factory');
$encoder = $factory->getEncoder($this);
$password = $encoder->encodePassword($this->getPassword(), $this->getSalt());
return $password;
}
In the controller:
//hash user password
$userEntity->setPassword($userEntity->hashPassword($this->container));
Right now I have improved(I at least think...) the answer to this question.
I have created an class that will receive the $encoderFactory form the DI
#services.yml
parameters:
password_encoder.class: Beubi\SignatureBundle\Handler\PasswordEncoder
services:
password_encoder:
class: %password_encoder.class%
arguments: [#security.encoder_factory]
So, I create a class that will be used in Service container:
class PasswordEncoder
{
protected $encoderFactory;
public function __construct(EncoderFactory $encoderFactory)
{
$this->encoderFactory = $encoderFactory;
}
public function encodePassword($entity){
$encoder = $this->encoderFactory->getEncoder($entity);
return $encoder->encodePassword($entity->getPassword(), $entity->getSalt());
}
}
And then in my controller:
$password = $this->get('password_encoder')->encodePassword($entity);
$entity->setPassword($password);
This way, my User object doesn't have any knowledge of $factoryEncoder or how to encode an password.
I'm expecting more comments on this question...
Ok, I've been at this for two hours now and I see some other people have had this error, but I can't seem to match their causes/resolutions with mine.
Fatal error: require() [function.require]: Cannot redeclare class companycontroller in /var/www/biztv_symfony/vendor/symfony/src/Symfony/Component/ClassLoader/DebugUniversalClassLoader.php on line 55
The terminal gives a better error message pointing me to the end clause of the actual class that it reports having trouble with (trying to redeclare).
If I remove or rename the file companyController.php it throws a Symfony2 error saying that the it went looking for the class but didn't find it where it was expected.
If I put the file back in its place, apache throws a php error saying that the class companyController can't be redeclared.
I only have it once?!
Here is the entire class... if anyone has patience to try and help me out...
<?php
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use BizTV\BackendBundle\Entity\company;
use BizTV\BackendBundle\Form\companyType;
/**
* company controller
*
*/
class companyController extends Controller
{
/**
* Lists all company entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getEntityManager();
$entities = $em->getRepository('BizTVBackendBundle:company')->findAll();
return $this->render('BizTVBackendBundle:company:index.html.twig', array(
'entities' => $entities
));
}
/**
* Finds and displays a company entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('BizTVBackendBundle:company')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find company entity.');
}
$deleteForm = $this->createDeleteForm($id);
return $this->render('BizTVBackendBundle:company:show.html.twig', array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
));
}
/**
* Displays a form to create a new company entity.
*
*/
public function newAction()
{
$entity = new company();
$form = $this->createForm(new companyType(), $entity);
return $this->render('BizTVBackendBundle:company:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView()
));
}
/**
* Creates a new company entity.
*
*/
public function createAction()
{
$entity = new company();
$request = $this->getRequest();
$form = $this->createForm(new companyType(), $entity);
$form->bindRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($entity);
$em->flush();
/* Create adminuser for this company to go along with it */
$userManager = $this->container->get('fos_user.user_manager');
$user = $userManager->createUser();
//make password (same as username)
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user); //get encoder for hashing pwd later
$tempPassword = $entity->getCompanyName(); //set password to equal company name
//Get company
$tempCompanyId = $entity->getId(); //get the id of the just-inserted company (so that we can retrieve that company object below for relating it to the user object later)
$tempCompany = $em->getRepository('BizTVBackendBundle:company')->find($tempCompanyId); //get the company object that this admin-user will belong to
$user->setUsername($entity->getCompanyName() . "/admin"); //set username to $company/admin
$user->setEmail('admin.'.$entity->getCompanyName().'#example.com'); //set email to non-functioning (#example)
$user->setPassword($encoder->encodePassword($tempPassword, $user->getSalt())); //set password with hash
$user->setCompany($tempCompany); //set company for this user
$user->setConfirmationToken(null); //we don't need email confirmation of account
$user->setEnabled(true); //without a confirmation token, we of course also need to flag the account as enabled manually
$user->addRole('ROLE_ADMIN');
$userManager->updateUser($user);
return $this->redirect($this->generateUrl('company_show', array('id' => $entity->getId())));
}
return $this->render('BizTVBackendBundle:company:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView()
));
}
/**
* Displays a form to edit an existing company entity.
*
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('BizTVBackendBundle:company')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find company entity.');
}
$editForm = $this->createForm(new companyType(), $entity);
$deleteForm = $this->createDeleteForm($id);
return $this->render('BizTVBackendBundle:company:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Edits an existing company entity.
*
*/
public function updateAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('BizTVBackendBundle:company')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find company entity.');
}
$editForm = $this->createForm(new companyType(), $entity);
$deleteForm = $this->createDeleteForm($id);
$request = $this->getRequest();
$editForm->bindRequest($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('company_edit', array('id' => $id)));
}
return $this->render('BizTVBackendBundle:company:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a company entity.
*
*/
public function deleteAction($id)
{
$form = $this->createDeleteForm($id);
$request = $this->getRequest();
$form->bindRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('BizTVBackendBundle:company')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find company entity.');
}
$em->remove($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('company'));
}
private function createDeleteForm($id)
{
return $this->createFormBuilder(array('id' => $id))
->add('id', 'hidden')
->getForm()
;
}
}
So, turns out that was a clumpsy typo by moi there.
But for anyone else who runs into this error message in Symfony2:
Fatal error: require() [function.require]: Cannot redeclare class...
Here is a hint: check if you have accidentally deleted or typo:ed the namespace in the file that contains the definition of the class that php claims it is trying to re-define.
The php error message doesn't really give you a clue to look for that... =)
Personally, I juste removed cache manually and it worked
rm -rf app/cache/*
Clearing cache was not fixing my problem.
redeclare class - Likely there is tow classes with the same name
Sometimes, if you got seduced by copy/paste, check your classnames, namespaces and for other "typos" that could have happened. (copy/paste is the devil of programming :/)
Similar to other answers, in my case I had renamed the class but not the containing file. Every class should be declared in a file with the same name. So check that, too.
In my case, it was a use statement under the namespace which used the same classname (but another path).
namespace Bsz\RecordTab;
use \Bsz\Config\Libraries; // I used this in constructor
class Libraries
{
...
}
Without the use directive, it Worked