Form Dynamic Symfony2 ManyToMany - php

I have 2 Entities: Company and User that have a link company_user ManyToMany
I would like to be able to display the list of companies linked to the connected user.
So I followed this: http://symfony.com/doc/current/form/dynamic_form_modification.html#form-events-user-data
However, in my request, I can not display the company related to the user.
Here is my CompanyRepo
<?php
namespace BudgetBundle\Repository;
use Doctrine\ORM\EntityRepository;
/**
* CompanyRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class CompanyRepository extends EntityRepository
{
public function companyByUser($user){
return $qb = $this->createQueryBuilder('cr')
->where('cr.id = :user')
->setParameter('user', $user);
}
}
My FOrmType
public function buildForm(FormBuilderInterface $builder, array $options)
{
// grab the user, do a quick sanity check that one exists
$user = $this->tokenStorage->getToken()->getUser();
if (!$user) {
throw new \LogicException(
'The FriendMessageFormType cannot be used without an authenticated user!'
);
}
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($user) {
$form = $event->getForm();
$formOptions = array(
'class' => Company::class,
'property' => 'name',
'query_builder' => function (CompanyRepository $er) use ($user) {
// build a custom query
// return $er->createQueryBuilder('u')->addOrderBy('fullName', 'DESC');
return $er->companyByUser($user);
// or call a method on your repository that returns the query builder
// the $er is an instance of your UserRepository
// return $er->createOrderByFullNameQueryBuilder();
},
);
// create the field, this is similar the $builder->add()
// field name, field type, data, options
$form->add('company', EntityType::class, $formOptions);
}
);
}
And my controller
public function addDebitAction( Request $request ) {
$em = $this->getDoctrine()->getManager();
$debit = new Debit();
$form = $this->createForm( DebitType::class, $debit );
$amountCapital = $em->getRepository('BudgetBundle:Capital')->find($this->getUser());
if ( $request->isMethod( 'POST' ) && $form->handleRequest( $request )->isValid() ) {
$em = $this->getDoctrine()->getManager();
$capital = $em->getRepository( 'BudgetBundle:Capital' )->findOneBy( [ 'user' => $this->getUser()->getId() ] );
if ($capital == false){
$this->get('session')->getFlashBag()->set('error', 'Vous devez avoir un capital de départ, merci d\'en ajouter un !');
return $this->redirectToRoute('budget_add_gain');
}
else{
$capital->setTotalDebits($capital->getTotalDebits() + $debit->getAmount());
$amountCapital->setAmount($amountCapital->getAmount() - $debit->getAmount()); // MEt a jout le capital
}
$em = $this->getDoctrine()->getManager();
$debit->setUser( $this->getUser() );
$em->persist( $debit );
$em->flush();
$request->getSession()->getFlashBag()->add( 'success', 'Debit Added !' );
return $this->redirectToRoute( 'budget_homepage' );
}
return $this->render( '#Budget/Views/company/debit.html.twig', [ 'form' => $form->createView() ] );
}

Try this:
public function companyByUser($user){
return $this->createQueryBuilder('cr')
->innerJoin('cr.users', 'u', 'WITH', 'u = :user')
->setParameter('user', $user);
}
You also need to set a choice_label on your query builder in the form type. Something like :
choice_label => 'company_name'
I don't know what your company and user entities fields are, so make sure you replace users and company_name with the correct fields names.

Related

How Can I specified the object of my precedent form?

In my project I want to use the object created by my precedent form:
Here is the schema of my database:
My QuizController
public function creation(Request $request){
$quiz = new Quiz();
$user = $this->getUser();
$formQuiz = $this->createForm(QuizType::class, $quiz);
$formQuiz->handleRequest($request);
if ($formQuiz->isSubmitted() && $formQuiz->isValid() ) {
$quiz->setCreatedAt(new DateTimeImmutable());
$quiz->setCreatedBy($user);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($quiz);
$entityManager->flush();
return $this->redirectToRoute('creation_questions');
}
return $this->render('quiz/creation.html.twig', [
'formQuiz' => $formQuiz->createView(),
]);
}
And my QuestionController that must be connected with the quiz form
public function creation_questions(Request $request){
$quiz = ?
$question = new Questions();
$formQuestions = $this->createForm(QuestionType::class, $question);
$formQuestions->handleRequest($request);
if ($formQuestions->isSubmitted() && $formQuestions->isValid() ) {
$question->setCreatedAt(new DateTimeImmutable());
$question->setQuiz($quiz);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($question);
$entityManager->flush();
return $this->redirectToRoute('home');
}
return $this->render('questions/questions.html.twig', [
'formQuestion' => $formQuestions->createView()
]);
}
What do I have to write in place of the '?'?
You don't show your routing but you could use paramConverte "magic" from SensioFrameworkExtraBundle and do something like this.
/**
* #Route("/some-route/{id}", name="some_route_name")
*/
public function creation_questions(Request $request, Quiz $quiz)
{
$question = new Questions();
$formQuestions = $this->createForm(QuestionType::class, $question);
$formQuestions->handleRequest($request);
if ($formQuestions->isSubmitted() && $formQuestions->isValid()) {
$question->setCreatedAt(new DateTimeImmutable());
$question->setQuiz($quiz);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($question);
$entityManager->flush();
return $this->redirectToRoute('home');
}
return $this->render('questions/questions.html.twig', [
'formQuestion' => $formQuestions->createView()
]);
}
Where the {id} part of /someRoute/{id} is the Quiz Id. Symfony should automagically fetch the Quiz matching that id. Or you can be more explicit about how the param converter should interpret such a value. More info here https://symfony.com/bundles/SensioFrameworkExtraBundle/current/annotations/converters.html
Alternatively, you could pass the quiz id and fetch the quiz manually (less magic but totally legit).
/**
* #Route("/some-route/{id}", name="some_route_name")
*/
public function creation_questions(Request $request, int $id)
{
$entityManager = $this->getDoctrine()->getManager();
$quiz = $entityManager->getRepository(Quiz::class)->find($id);
$question = new Questions();
$formQuestions = $this->createForm(QuestionType::class, $question);
$formQuestions->handleRequest($request);
if ($formQuestions->isSubmitted() && $formQuestions->isValid()) {
$question->setCreatedAt(new DateTimeImmutable());
$question->setQuiz($quiz);
$entityManager->persist($question);
$entityManager->flush();
return $this->redirectToRoute('home');
}
return $this->render('questions/questions.html.twig', [
'formQuestion' => $formQuestions->createView()
]);
}

Symfony controller code

Hi I just started a project with Symfony and I think I am doing something wrong. Right now I want to a create simple page with table and filters so I created controller for it.
/**
* #Route("/")
*/
class HomeController extends Controller {
public function index(Request $request) {
//Form to add new documents
$form = $this->newForm();
$form->handleRequest($request);
$user = $this->getDoctrine()->getRepository(User::class)->find($this->getUser());
//Gets all user documents
$files = $user->getDocuments();
//Gets all categories
$categories = $this->getDoctrine()->getRepository(Category::class)->findAll();
//Adds new document to database
if($form->isSubmitted() && $form->isValid()) {
$article = $form->getData();
$article->setUser($this->getUser());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($article);
$entityManager->flush();
return $this->redirectToRoute('index');
}
return $this->render('home/home.html.twig', [
'files' => $files,
'categories' => $categories,
'form' => $form->createView(),
]);
}
}
This controller just displays documents in table and categories in navigaton. So then to add category filters I just made new function:
/**
* #Route("/{categoryId}")
*/
public function categories(request $request, $categoryId)
{
$form = $this->newForm();
$form->handleRequest($request);
$user = $this->getDoctrine()->getRepository(User::class)->find($this->getUser());
$categories = $this->getDoctrine()->getRepository(Category::class)->findAll();
$category = $this->getDoctrine()->getRepository(Category::class)->findOneBy(["id" => $categoryId]);
$categoryFiles = $this->getDoctrine()->getRepository(Document::class)->categoryFiles($category, $user);
if($form->isSubmitted() && $form->isValid()) {
$article = $form->getData();
$article->setUser($this->getUser());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($article);
$entityManager->flush();
return $this->redirectToRoute('index');
}
return $this->render('home/home.html.twig', [
'files' => $categoryFiles,
'categories' => $categories,
'form' => $form->createView(),
]);
}
Everything works, but I have to repeat same code for categories and forms in all of my functions. Thank you for your help.
I suggest you use services, a Service can be (Business Rules, Helpers, MicroServices, etc.), the most import is the Business Rules, generally should exists a service by entity
$user = $this->getUser();
$info = $this->get(HomeService::class)->getInfo($user, null);
// TODO FORM
return $this->render('home/home.html.twig', [
'files' => $info['files'],
'categories' => $info['categories'],
'form' => $form->createView()
]);
Second Action
$user = $this->getUser();
$info = $this->get(HomeService::class)->getInfo($user, $categoryId);
// TODO FORM
return $this->render('home/home.html.twig', [
'files' => $info['category_files'],
'categories' => $info['categories'],
'form' => $form->createView()
]);
HomeService->info(), it will process all
Symfony Service
Create abstract class, then extend from child controllers. You can read also: http://php.net/manual/en/language.oop5.late-static-bindings.php
It's just one way, can be more ways!

Search filter with method get doesn't found results [symfony2]

I have a search form that works with the method POST, but the method POST doesn't display the requested data in the url.
With method POST the url look like this:
/search_flight
with the method GET no results found, the url look like this:
/search_flight?from=Cape+Town%2C+International+CPT&to=Johannesburg%2C+O.R.+Tambo+International+JNB&departuredate=2016%2F01%2F08&arrivaldate=2016%2F10%2F04&price=57.5%2C1000
I also noticed that with the method GET the data is reset in each input of the form.
routing.yml
searchFlight:
path: /search_flight
defaults: { _controller: FLYBookingsBundle:Post:searchtabflightResult }
requirements:
_method: GET|POST
controller
This method send the requested data to the method searchtabflightResultAction that will handle the query.
public function searchtabflightAction()
{
//$form = $this->createForm(new SearchflightType(),null, array('action' => $this->generateUrl('searchFlight'),'method' => 'GET',));
$form = $this->get('form.factory')->createNamed(null, new SearchflightType());
return $this->render('FLYBookingsBundle:Post:searchtabflight.html.twig', array(
'form' => $form->createView(),
));
}
.
<form action="{{ path ('searchFlight') }}" method="GET">
{# here I have my forms #}
</form>
.
public function searchtabflightResultAction(Request $request)
{
//$form = $this->createForm(new SearchflightType());
$form = $this->get('form.factory')->createNamed(null, new SearchflightType());
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
$airport1 = $form["to"]->getData();
$airport = $form["from"]->getData();
$departureDateObj = $form["departuredate"]->getData();
$arrivalDateObj = $form["arrivaldate"]->getData();
$price = $form["price"]->getData();
$entities = $em->getRepository('FLYBookingsBundle:Post')->searchflight($airport1,$airport,$departureDateObj,$arrivalDateObj,$price);
return $this->render('FLYBookingsBundle:Post:searchtabflightResult.html.twig', array(
'entities' => $entities,
'form' => $form->createView(),
));
}
How can I make my search filter works with method get ?
Everything should be done within two actions, the basic concept is:
SearchFlightType has with/wo price option:
class SearchFlightType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('from', FormType\TextType::class)
->add('to', FormType\TextType::class)
->add('departuredate', FormType\TextType::class)
->add('arrivaldate', FormType\TextType::class);
if ($options['price']) {
$builder->add( 'price', FormType\TextType::class );
}
$builder
->add('submit', FormType\SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'price' => false,
));
}
}
Controller.php
class PostController extends Controller
{
/**
* #Route("/index", name="index")
*/
public function indexAction(Request $request)
{
$defaultData = array();
$form = $this->createForm(SearchFlightType::class, $defaultData, array(
// action is set to the specific route, so the form will
// redirect it's submission there
'action' => $this->generateUrl('search_flight_result'),
// method is set to desired GET, so the data will be send
//via URL params
'method' => 'GET',
));
return $this->render('Post/searchtabflight.html.twig', array(
'form' => $form->createView(),
));
}
/**
* #Route("/search_flight_result", name="search_flight_result")
*/
public function searchTabFlightResultAction(Request $request)
{
$defaultData = array();
$entities = null;
$form = $this->createForm(SearchFlightType::class, $defaultData, array(
// again GET method for data via URL params
'method' => 'GET',
// option for price form field present
'price' => true,
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// get data from form
$data = $form->getData();
// process the data and get result
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('FLYBookingsBundle:Post')->searchflight($data['from'], $data['to'], ...);
}
return $this->render('Post/searchtabflight.html.twig', array(
'form' => $form->createView(),
// present the result
'entities' => $entites,
));
}
}

I want to upload a profile picture with symfony2 and doctrine

In User.php (Entity name is User), I have a field in User entity named userPic , type String
In file UserType.php I mention userPic as shown below :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('userFullname')
->add('userName')
->add('userEmail')
->add('userPassword')
->add('userPic', 'file', array ('label'=>'profile Picture'))
->add('gender','choice',array('choices' => array('m' => 'Male', 'f' => 'Female')))
->add('isActive')
;
}
Now in the controller I'm getting the form fields as shown below
/**
* Creates a new User entity.
*
*/
public function createAction(Request $request)
{
$entity = new User();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('user_show', array('id' => $entity->getId())));
}
return $this->render('MWANRegisterBundle:User:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
Where do I have to give the path in which I want to save the picture? How can I save the uploaded file in my desired directory and save directory path in database?
Christian's answer is valid, however I'd just like to point out more specificaly how to do what is asked. Simply do :
if ($form->isValid()) {
$file = $form->getData()['file'];
$file->move('/your/path/to/your/file', 'yourFileName');
// Do the rest
...
}
Hope this helps.
You need to create an upload method in your entity. Check this link for more details http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html
public function uploadFile()
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
// use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and then the
// target filename to move to
$this->getFile()->move($this->getUploadDir(), $this->getFile()->getClientOriginalName());
// set the path property to the filename where you've saved the file
$this->path = $this->getFile()->getClientOriginalName();
// clean up the file property as you won't need it anymore
$this->file = null;
}
/**
* Creates a new User entity.
*
*/
public function createAction(Request $request)
{
$entity = new User();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
// Upload file
$entity->uploadFile();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('user_show', array('id' => $entity->getId())));
}
return $this->render('MWANRegisterBundle:User:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}

Symfony2, How do I perform a database retrieve in Doctrine with a drop down list form?

I have a form that will perform a search action with a drop down list of choices of category to search. The drop down list are subjects to search by. So:
Search by:
1) Invoice #
2) Tracking #
3) BL #
Then enter in the value and submit to search.
I have my form:
// src Bundle\Form\Type\SearchType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('kind', 'choice', array(
'choices' => array(
'invoice' => 'Invoice #',
'trackingno' => 'Tracking Number'
'blno' => 'BL #',
),
'label' => 'Search by: '
))
->add('value', 'text', array(
'label' => false
))
->add('Submit','submit');
}
With this function in the controller:
public function getForm() {
$form = $this->createForm(new SearchType(), array(
'action' => $this->generateUrl('search_view'),
'method' => 'POST'
) );
return $form;
}
With the action going to 'search_view' function:
/**
* #param Request $request
* #Route("/results/", name="search_view")
*/
public function searchAction(Request $request) {
$kind = $request->get('kind');
$value = $request->get('value');
$em = $this->getDoctrine()->getManager();
$findCfs = $em->getRepository("CFSBundle:Cfs")
->searchCfs($kind, $value);
return $this->render("CFSBundle:Search:index.html.twig", array(
'results' => $findCfs
));
}
My problem is I do not where to go to perform the database retrieval base on the category. This is what I have in the repository:
public function searchCfs($kind, $value) {
$query = $this->getEntityManager()
->createQuery('
SELECT
c.blno, m.ctrno, c.carrier, m.refno
FROM
CFSBundle:Cfs c
LEFT JOIN
cfs.refno m
WHERE
:kind LIKE :value
')->setParameter("kind", $kind)
->setParameter("value", $value);
try {
return $query->getResult();
} catch(\Doctrine\ORM\NoResultException $e) {
return null;
}
}
Of course this isn't working. I thought about creating different queries for each category and have the conditions submit according to its category, but I was wondering if there was one simple solution to this?
I'd advise using the QueryBuilder class when writing a query such as this, rather than writing DQL directly.
You could then do something like the following in your repository:
const KIND_INVOICE_NO = 'invoice';
const KIND_TRACKING_NO = 'tracking';
const KIND_BL_NO = 'blno';
public function searchCfs($kind, $value) {
$queryBuilder = $this->createQueryBuilder('c')
->select('c.blno, m.ctrno, c.carrier, m.refno')
->leftJoin('cfs.refno', 'm');
if ($kind === self::KIND_INVOICE_NO) {
$queryBuilder->where('c.invoiceno = :queryValue');
} elseif ($kind === self::KIND_TRACKING_NO) {
$queryBuilder->where('m.ctrno = :queryValue')
} elseif ($kind === self::KIND_BL_NO) {
$queryBuilder->where('c.blno = :queryValue')
}
$queryBuilder->setParameter('queryValue', $value);
$query = $queryBuilder->getQuery();
try {
return $query->getResult();
} catch(\Doctrine\ORM\NoResultException $e) {
return null;
}
}

Categories