SF2 services and doctrine - symfony

Welcome,
I created a few projects in sf2 (2.4-2.8). The code was different quality...
I read few articles. Now I try to minimize the code in the controller. I use Repository, Services etc. When I use with the services, don't injects doctrine, forwards object. In the controller initializes forms, objects, services, check validation forms and returns values to template. But I have functionalities which I must generate query in the loop or I need many query, which can not be combined into one.
My structure folder: Controller, Services, Repository, Entity, Form, Resources.
How can I reconcile all this? Minimum controller, functionalities in the services and Repository to Entity.
Example ugly code controller:
/**
* #Route("/add", name="controller_admin_page_add")
* #Template()
* #param Request $request
*/
public function addAction(Request $request) {
$page = new Page;
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new FormPage, $page);
$form->handleRequest($request);
if ($request->isMethod("POST") && $form->isValid()) {
$links = $em->createQuery("...")->getResult();
foreach($link as links){
if(...){
$checkLink = $em->createQuery("...")->getResult();
...
}
.....
}
$em->persist($page);
$em->flush();
return $this->redirectToRoute('controller_admin_page_index');
}
return array(
'form' => $form->createView()
);
}
Example nicer code:
/** ...
*/
public function addAction(Request $request) {
$page = new Page;
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new FormPage, $page);
$form->handleRequest($request);
if ($request->isMethod("POST") && $form->isValid()) {
$generateUrl = $this->container->get('Url');
$generateUrl->checkLink($page);
$generateUrl->getUrl();
$em->persist($page);
$em->flush();
return $this->redirectToRoute('controller_admin_page_index');
}
return array(
'form' => $form->createView()
);
}
Here is problem.
The functionality takes over Services. In the "clean architecture", I should pass an object/objects to the Services. But I must send query in loop.
In my opinion I need 2 types classes helper in project.
1). Gets the object /objects by setters and returns the processed data. Class doesn't have access to the doctrine.
2) Gets arguments, created query and returns the processed data. Class have access to the doctrine.
In the project I have Repository, they only return the objects.
I have a problem with the class name, directory name, and using it.
Can someone please help?

Related

can't update entity Symfony2

Trying to update my entity, unfortunately didnt use Doctrines generate CRUD feature (have to change stuff I didnt write).
I am finally getting data into my form, but it just won't save the changes (also, it doesn't create a new entity as one might suspect).
When I click 'save', I always return to the page where I have my form to edit the entity.
Checked if method is POST, it is.
if ($form->get('save')->isClicked()) {
doesn't seem to do anything, how can that be?
Here's the rest of my action:
/**
* Updates.
*
* #Route("/offerweekchange/{offerid}", name="offerweekchange")
* #Template("")
*/
public function offerweekchangeAction(Request $request, $offerid)
{
$request = $this->get('request');
if ($offerid) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AlexanderBuerkleShopBundle:Promotion')->findOneBy(array('id' => $offerid));
$form = $this->createForm(new OfferWeekChangeType(), $entity);
# \Doctrine\Common\Util\Debug::dump($request->getMethod());
if ($form->get('save')->isClicked()) {
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('offerweeklist'));
}
}
}
return $this->render('AlexanderBuerkleShopBundle:OfferWeekList:offerweekchange.html.twig',
array('form' => $form->createView(), 'offerid' => $offerid, 'entity' => $entity));
}
}
Any help would be greatly appreciated.
First, here is a working sample of your code:
public function offerweekchangeAction(Request $request, $offerid)
{
if ($offerid) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AlexanderBuerkleShopBundle:Promotion')->findOneBy(array('id' => $offerid));
$form = $this->createForm(new OfferWeekChangeType(), $entity);
$form->handleRequest($request);
# \Doctrine\Common\Util\Debug::dump($request->getMethod());
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('offerweeklist'));
}
return $this->render('AlexanderBuerkleShopBundle:OfferWeekList:offerweekchange.html.twig',
array('form' => $form->createView(), 'offerid' => $offerid, 'entity' => $entity));
}
}
Secondly, you have several mistakes here, so let's analyse them one by one:
1:
if ($offerid) {
your code does nothing on the else branch.
2:
$request = $this->get('request');
you already have the request parameter injected into the action. This line is redundant.
3:
$form->bind($request);
This is deprecated since 2.3. Use $form->handleRequest($request) instead.
4:
$em->flush();
You are flushing the entity manager, but nothing is persisted, so nothing will happen. you have to persist the entity first with $em->persist($entity)
5:
if ($request->getMethod() == 'POST') {
The method $form->isValid() checks for this also, so checking for post is redundant.
That's it. Hope it helped.
The most likely issue here is with the AbstractType which define your form OfferWeekChangeType).
In order to map the form data on the entity you need to set the 'data_class'.
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => ' Acme\StoreBundle\Entity\Product',
)
);
}
then inside your controller you need to invoke :
$form->handleRequest($request);
This will bind the request to your form.
Only when you invoke:
$form->isValid()
The data from the form (if valid) will be mapped on the entity.
$em->persist($entity);
in this case is superflus because Doctrine UnityOfWork already 'knows' the entity from when you got it from the repository. Just invoke
$em->flush($entity);
As a side note remember that flushing only the needed entity is preferable (when possible) the flush the entire UnityOfWork in order to avoid unexpected behaviours.
Regards.

Symfony2 passing parameters to twig

I'm working with Symfony 2 and I want to pass from my controller to my twig template a simple string and then use it on my template to descriminate the user role.
The controller code has something like :
public function modify_user_asAction(Request $request, $username)
{
$stringtopass="admin";
$um = $this->get('fos_user.user_manager');
$user = $um->findUserByUsername($username);
if($user == null){
//error page here..
}
$form = $this->createForm(new UserForm(), $user);
$form->handleRequest($request);
if ($form->isValid()) {
$um->updateUser($user);
return $this->redirect($this->generateUrl('acme_query_success'));
}
return $this->render('AcmeUserBundle:Default:modifyuserform.html.twig', array(
'form' => $form->createView(),
));
}
I want to pass $stringtopass in the generateUrl (if it's possible).
I can't find anything online.
Thanks
You are almost there!
API: generateUrl
Basically, just pass an array as second param to generateUrl.
return $this->redirect($this->generateUrl('acme_query_success', array('stringToPass' => $stringtopass)));
And also, #Brewal has a very valid point there. Be careful not to pass some sensitive data or leave unrestricted access to that controller's action. You could do more harm than good...
UPDATE:
public function acmeQuerySuccessAction(){
// ... action's logic
$stringToPass = $this->getRequest()->query->get('stringToPass');
// .....
return array(
'stringToPass' => $stringToPass,
// all other elements that you would normally return
);
}

Symfony2 add current user to form input data

I've got a standard FOS user that's got a ManyToOne entity relationship with a blog entity.
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="blog")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
private $user;
I've used the app/console generate:doctrine:crud command to generate a basic crud system.
When I create a new blog entity I want to insert the logged in user that performed the action. By default Symfony generates CRUD code that allows the user to select which user is connected to the entity.
$builder
->add('name')
->add('address')
->add('facebook')
->add('twitter')
->add('user')
;
In the controller I can access the logged in user using security.context:
$user = $this->get('security.context')->getToken()->getUser();
Whats the best course of action to change this?
Okay! solved my own question (if I'm doing it wrong please feel free to correct me, and I'll accept a better answer). This one does appear to work well however!
The user can be added in the controller after the $form->isValid() check is performed. Here's my controller function for example.
public function createAction(Request $request)
{
$entity = new Blog();
$form = $this->createForm(new BlogType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$entity->setUser($this->get('security.context')->getToken()->getUser());
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('blog_show', array('id' => $entity->getId())));
}
return $this->render('ExampleBundle:Blog:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
The user needs to be removed from the form builder for this to work.

Symfony adding extra fields by CreateAction

I have a createAction for a Symfony request.
How can I add some values in another entity, by creating a new Entity value.
See the following foreach part; whats wrong with it?
public function createAction(Request $request)
{
$entity = new FooType();
$form = $this->createForm(new FooTypeType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
$entities = $em->getRepository('OtherBundle:Lists')->findAll();
foreach($entities as $list){
$manager = $this->getDoctrine()->getManager();
$listValue = new ListValue();
$listValue->setSpecification( new ListsType(), $list );
$manager->persist($listValue);
$manager->flush();
}
return $this->redirect($this->generateUrl('foo_foobar_show', array('id' => $entity->getId())));
}
if you have a proper association mapping between your entities and use Doctrine's persist option for the cascade operation you won't have to persist your related entities explicitly.
You can in this case ommit
$manager->persist($listValue);
Furthermore for performance reasons make sure you flush your entityManager only once - you don't need to flush more than once often except in case you need the auto-generated ID of a newly persisted entity!
create a new method in your repository ( addListsToEntity() ) or in a manager class for adding your lists!

Symfony2 - Establish one form parameter from outside so cannot be modified by the users

I have a CRUD for one of my entities in Symfony2. In order to create a new entry, I have two controller functions:
public function newAction($id) {
$entity = new Clientes();
// Get the reference to the Login entity using its ID
$em = $this->getDoctrine()->getManager();
$ref_login = $em->getReference('LoginBundle:Login', $id);
// Put the retrieved reference to the entity
$entity->setLogin($ref_login);
$form = $this->createForm(new ClientesType(), $entity);
return $this
->render('MovinivelBundle:Persona/Clientes:new.html.twig',
array('entity' => $entity,
'form' => $form->createView(),));
}
public function createAction(Request $request) {
$entity = new Clientes();
$form = $this->createForm(new ClientesType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('clientes'));
}
return $this
->render('MovinivelBundle:Persona/Clientes:new.html.twig',
array('entity' => $entity,
'form' => $form->createView(),));
}
In the previous code I added the $id input parameter to the newAction() function because I want it to be established from outside, because each of this Clientes is additional info of Login and has to be linked.
In the ClientesType form I have the following:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('login')
->add('direccion')
->add('localidad')
->add('provincia')
->add('telefono')
;
}
So far it works. In my form, the login parameter is chosen depending on the $id value. But the thing is that I want the login parameter to be fixed once the form is created, so the user cannot modify it from the form, but only calling the newAction($id) function with the appropiate value.
The thing is that if I delete the ->add('login') line in the FormType, it doesn't work anymore. It comes to my mind two options:
Hide somehow the 'login' in the form, but keeping it working, although I don't know how, or
pass to the createAction the $id parameter along with the $request one as input parameters, but I cannot figure out how do it either.
Any thoughts on this?
I think you are looking for a hidden field type:
public function buildForm(...)
{
$builder
->add('login', 'hidden')
// ...
;
}
Ok, I came out with the solution. All I was looking for is actually the following:
<div style="display:none">
{{ form_rest(form) }}
</div>
Typing this at the end of the template after having shown explicitly any other form field avoids any user to modify the fields I don't want to, while it still sends the info using the $POST method.

Resources