Called a function of an entity in twig - symfony

I'm looking to retrieve information from an entity by twig by passing the id as a parameter. But I block on the function in my entity:
My entity (function need call):
public function getNameFournisseur($id)
{
???
}
My twig:
{{ staticFournisseur.getNameFournisseur(idFournisseur) }}
My controller:
/**
* #Route("/new", name="new_invoice", methods={"GET","POST"})
*/
public function new(Request $request, SessionInterface $session, ArticlesRepository $articlesRepository, FournisseursRepository $fournisseursRepository): Response
{
$invoice = new Invoice();
$form = $this->createForm(InvoiceType::class, $invoice);
$form->handleRequest($request);
$articles = $session->get('articleInvoice', []);
$articleData = [];
foreach ($articles as $k => $article) {
$articleData [] = [
'articleInvoice' => $articlesRepository->find($k),
'quantityInvoice' => $article
];
}
$total = 0;
foreach ($articleData as $totalArticle) {
$totalArticles = $totalArticle['articleInvoice']->getPrice() * $totalArticle['quantityInvoice'];
$total += $totalArticles;
}
$session->set('totalHt', $total);
$totalAllArticles = $session->get('totalHt');
$tauxDiscount = $session->get('discountTaux');
if (!$tauxDiscount) {
$totalWithDiscount = $total;
} else {
$totalWithDiscount = $totalAllArticles - ($totalAllArticles * $tauxDiscount) / 100;
}
if ($form->isSubmitted()) {
//$session->remove('idFournisseur');
$id_fournisseur = (int)$request->request->get('order')['fournisseur_id'];
$fournisseur = $fournisseursRepository->findOneBy(['id' => $id_fournisseur]);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($invoice);
$entityManager->flush();
return $this->redirectToRoute('invoices');
}
return $this->render('admin/invoices/new.html.twig', [
'staticFournisseur' => new Fournisseur(),
'idFournisseur' => $session->get('idFournisseur'),
'discountTaux' => $tauxDiscount,
'totalHt' => $totalWithDiscount,
'art' => $articleData,
'form' => $form->createView()
]);
}
I therefore seek to recover the name of the supplier thanks to the id that I pass as a parameter in my twig.

getNameFournisseur($id) is a function that retrieves data from the database, not from a single (already loaded) entity; in other words, it should be in FournisseursRepository instead
Also, if you're using Doctrine, you usually want to load the full entity instead of just a field
'staticFournisseur' => $fournisseursRepository->findOneById($session->get('idFournisseur'));
and in twig:
{{ staticFournisseur.getName() }}
or even
{{ staticFournisseur.name }}

Related

Drupal block which filter content type by taxonomy

I am using Drupal 9. I want to give the ability to the admin to place a block and select from the block a taxonomy term in which will filter a content type.
I did the above by creating a custom block with the taxonomy "Sponsor Type" as you can see the screenshot bellow.
Also I use views_embed_view to pass the taxonomy as an argument and filter the data using Contextual filters
Custom block code:
<?php
namespace Drupal\aek\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Provides a 'SponsorsBlock' block.
*
* #Block(
* id = "sponsors_block",
* admin_label = #Translation("Sponsors"),
* )
*/
class SponsorsBlock extends BlockBase {
/**
* {#inheritdoc}
*/
public function defaultConfiguration() {
return [
"max_items" => 5,
] + parent::defaultConfiguration();
}
public function blockForm($form, FormStateInterface $form_state) {
$sponsors = \Drupal::entityTypeManager()
->getStorage('taxonomy_term')
->loadTree("horigoi");
$sponsorsOptions = [];
foreach ($sponsors as $sponsor) {
$sponsorsOptions[$sponsor->tid] = $sponsor->name;
}
$form['sponsor_types'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Sponsor Type'),
'#description' => $this->t('Select from which sponsor type you want to get'),
'#options' => $sponsorsOptions,
'#default_value' => $this->configuration['sponsor_types'],
'#weight' => '0',
];
$form['max_items'] = [
'#type' => 'number',
'#title' => $this->t('Max items to display'),
'#description' => $this->t('Max Items'),
'#default_value' => $this->configuration['max_items'],
'#weight' => '0',
];
return $form;
}
/**
* {#inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
$this->configuration['sponsor_types'] = $form_state->getValue('sponsor_types');
$this->configuration['max_items'] = $form_state->getValue('max_items');
}
/**
* {#inheritdoc}
*/
public function build() {
$selectedSponsorTypes = $this->configuration['sponsor_types'];
$cnxFilter = '';
foreach ($selectedSponsorTypes as $type) {
if ($type !== 0) {
$cnxFilter .= $type . ",";
}
}
return views_embed_view('embed_sponsors', 'default', $cnxFilter);
}
}
My issue now is how to limit the results. If you look above I have added an option "Max items to display" but using the Contextual filters I can't find any way to pass that argument to handle this.
If you use views_embed_view(), you will not be able to access the view object.
Load your view manually then you can set any properties before executing it:
use Drupal\views\Views;
public function build() {
$selectedSponsorTypes = $this->configuration['sponsor_types'];
$cnxFilter = '';
foreach ($selectedSponsorTypes as $type) {
if ($type !== 0) {
$cnxFilter .= $type . ",";
}
}
$view = Views::getView('embed_sponsors');
$display_id = 'default';
$view->setDisplay($display_id);
$view->setArguments([$cnxFilter]);
$view->setItemsPerPage($this->configuration['max_items']);
$view->execute();
return $view->buildRenderable($display_id);
}

PDF document creation EasyAdmin symfony 5

I have this configuration which allows me to create a pdf document in the CRUD, is there a way to add this code in the CRUD easyAdmin or link the CRUD of my EasyAdmin documentos to the CRUD of symfony.
I have problems creating the document in the EasyAdmin table
DocumentController.php
<?php
namespace App\Controller;
use App\Entity\Document;
use App\Form\DocumentType;
use App\Repository\DocumentRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Service\FileUploader;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
/**
* #IsGranted("ROLE_USER")
* #Route("/documents")
*/
class DocumentController extends AbstractController
{
/**
* #Route("/", name="document_index", methods={"GET"})
*/
public function index(DocumentRepository $documentRepository): Response
{
return $this->render('document/index.html.twig', [
'documents' => $documentRepository->findAll([], ['created_at' => 'desc']),
]);
}
/**
* #Route("/new", name="document_new", methods={"GET","POST"})
*/
public function new(Request $request, FileUploader $fileUploader): Response
{
$document = new Document();
$document->setCreatedAt(new \DateTime('now'));
$form = $this->createForm(DocumentType::class, $document);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$file = $form['fileDocument']->getData();
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
// this is needed to safely include the file name as part of the URL
$fileName = transliterator_transliterate('Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()', $originalFilename);
$fileName = md5(uniqid()) . '.' . $file->guessExtension();
$file->move(
$this->getParameter('brochures_directory'),
$fileName
);
$document->setFileDocument($fileName);
$entityManager->persist($document);
$entityManager->flush();
return $this->redirectToRoute('document_index', array('id' => $document->getId()));
}
return $this->render('document/new.html.twig', [
// 'document' => $document,
'form' => $form->createView(),
]);
}
/**
* #Route("/{id}", name="document_show", methods={"GET"})
*/
public function show(Document $document): Response
{
return $this->render('document/show.html.twig', [
'document' => $document,
]);
}
/**
* #Route("/{id}/edit", name="document_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Document $document): Response
{
$form = $this->createForm(DocumentType::class, $document);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$file = $form['fileDocument']->getData();
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
// this is needed to safely include the file name as part of the URL
$fileName = transliterator_transliterate('Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()', $originalFilename);
$fileName = md5(uniqid()) . '.' . $file->guessExtension();
$file->move(
$this->getParameter('brochures_directory'),
$fileName
);
$document->setFileDocument($fileName);
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('document_index');
}
return $this->render('document/edit.html.twig', [
'document' => $document,
'form' => $form->createView(),
]);
}
/**
* #Route("/{id}", name="document_delete", methods={"DELETE"})
*/
public function delete(Request $request, Document $document): Response
{
if ($this->isCsrfTokenValid('delete' . $document->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($document);
$entityManager->flush();
}
return $this->redirectToRoute('document_index');
}
}
DocumentCrudController Easy Admin
<?php
namespace App\Controller\Admin;
use App\Entity\Document;
use App\Entity\Publication;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Constraints\File;
class DocumentCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Document::class;
}
public function configureCrud(Crud $crud): Crud
{
return $crud
->setPageTitle(Crud::PAGE_INDEX, 'Liste de Documents')
;
}
public function configureFields(string $pageName): iterable
{
ImageField::new('fileDocument', 'Document PDF')->setFormType(FileType::class)
->setBasePath('docs');
return [
IdField::new('id')->onlyOnIndex(),
TextField::new('nomDocument', 'Titre'),
DateTimeField::new('created_at', 'Date de création'),
TextField::new('fileDocument', 'Document PDF')
->hideOnIndex()
->setFormType(FileType::class, [
'constraints' => [
new File([
'maxSize' => '1024k',
'mimeTypes' => [
'application/pdf',
'application/x-pdf',
],
'mimeTypesMessage' => 'Veuillez télécharger un document PDF valide',
])
],
]),
];
}
public function configureActions(Actions $actions): Actions
{
return $actions
->add(Crud::PAGE_INDEX, Action::DETAIL);
}
}
I don't know how I can implement the same configuration in easy admin.
Look Here this is what happens when i create a document from table EasyAdmin.
Thank you.
That's a little weird but you need to use the ImageField (https://symfony.com/bundles/EasyAdminBundle/current/fields/ImageField.html)
And in you CrudController:
public function configureFields(string $pageName): iterable{
return [
ImageField::new('pdf', 'Your PDF')
->setFormType(FileUploadType::class)
->setBasePath('documents/') //see documentation about ImageField to understand the difference beetwen setBasePath and setUploadDir
->setUploadDir('public/documents/')
->setColumns(6)
->hideOnIndex()
->setFormTypeOptions(['attr' => [
'accept' => 'application/pdf'
]
]),
];
}
See documentation about ImageField to understand the difference beetwen setBasePath and setUploadDir
----- EDIT ----
In your index page of CRUD, you can create a link for your file like this:
public function configureFields(string $pageName): iterable{
return [
ImageField::new('pdf', 'Your PDF')
->setFormType(FileUploadType::class)
->setBasePath('documents/') //see documentation about ImageField to understand the difference beetwen setBasePath and setUploadDir
->setUploadDir('public/documents/')
->setColumns(6)
->hideOnIndex()
->setFormTypeOptions(['attr' => [
'accept' => 'application/pdf'
]
]),
TextField::new('pdf')->setTemplatePath('admin/fields/document_link.html.twig')->onlyOnIndex(),
];
}
Your templates/admin/fields/document_link.html.twig :
{% if field.value %}
Download file
{% else %}
--
{% endif %}

Symfony2 Doctrine combining three queries

I'm building a simple task planner. This is a fragment from the file TaskController.php. How can I combine these 3 queries (tasks, notcompleted, completed) to make it work? Should I use DQL?
/**
* Lists all task entities.
*
* #Route("/", name="task_index")
* #Method("GET")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$tasks = $em->getRepository('TaskBundle:Task')->findByUser($this->getUser()); // all tasks of a specific user
$notcompleted = $em->getRepository('TaskBundle:Task')->findByCompleted(false); //tasks that are not completed
$completed = $em->getRepository('TaskBundle:Task')->findByCompleted(true); // all completed tasks
return $this->render('task/index.html.twig', array(
'notcompleted' => $notcompleted,
'completed' => $completed,
'tasks' => $tasks,
));
}
You can use Doctrine's \Doctrine\Common\Collections\Collection::partition() to split the tasks:
$em = $this->getDoctrine()->getManager();
$tasks = $em->getRepository('TaskBundle:Task')->findByUser($this->getUser());
$collection = new ArrayCollection($tasks);
list($completed, $notcompleted) = $collection->partition(function ($key, Task $task) {
return $task->isCompleted();
});
return $this->render('task/index.html.twig', array(
'notcompleted' => $notcompleted,
'completed' => $completed,
'tasks' => $tasks,
));
The simplest solution could be to filter tasks in the controller:
$em = $this->getDoctrine()->getManager();
$tasks = $em->getRepository('TaskBundle:Task')->findByUser($this->getUser());
$notcompleted = $completed = [];
foreach ($tasks as $task) {
if ($task->isCompleted()) {
$completed[] = $tasK;
} else {
$notcompleted[] = $task;
}
}
return $this->render('task/index.html.twig', array(
'notcompleted' => $notcompleted,
'completed' => $completed,
'tasks' => $tasks,
));
In this solution you are doing only one DB query, instead of three queries.

Symfony2 - Dynamic generated form not working while editing form

Based on documentation: http://symfony.com/doc/2.8/form/dynamic_form_modification.html#form-events-submitted-data
I prepared dynamic generated form. And everything works properly but only when I use form for adding new data (/new) when I use the same form for editing existing data - not working
Simple form for "Appointment". It should work like that: User select client and then second "select" is filling proper data - depends on each client from first select. And this works ok but only when I try add new Appointment. When I try edit no.
class AppointmentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('client', EntityType::class, array(
'class' => 'SystemAdminBundle:Client',
'placeholder' => '',
));
$formModifier = function(\Symfony\Component\Form\FormInterface $form, Client $client)
{
$diseases = array();
if($client !== null) {
$diseases = $client->getDiseases();
}
$form->add('disease', EntityType::class, array(
'class' => 'SystemAdminBundle:Disease',
'placeholder' => '',
'choices' => $diseases,
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$data = $event->getData();
$formModifier($event->getForm(), $data->getClient());
}
);
$builder->get('client')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$client = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $client);
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'System\AdminBundle\Entity\Appointment'
));
}
}
Appointment controller - here is function for add new appointment and edit. For "new" my code works, for "edit" no.
public function newAction(Request $request)
{
$appointment = new Appointment();
$form = $this->createForm(AppointmentType::class, $appointment);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $request->request->get('appointment');
if(array_key_exists('name', $data)) {
$em = $this->getDoctrine()->getManager();
$em->persist($appointment);
$em->flush();
return $this->redirectToRoute('appointment_show', array('id' => $appointment->getId()));
}
}
return $this->render('appointment/new.html.twig', array(
'appointment' => $appointment,
'form' => $form->createView(),
));
}
public function editAction(Request $request, Appointment $appointment)
{
$deleteForm = $this->createDeleteForm($appointment);
$appointment = new Appointment();
$editForm = $this->createForm('System\AdminBundle\Form\AppointmentType', $appointment);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$data = $request->request->get('appointment');
if(array_key_exists('name', $data)) {
$em = $this->getDoctrine()->getManager();
$em->persist($appointment);
$em->flush();
return $this->redirectToRoute('appointment_show', array('id' => $appointment->getId()));
}
return $this->redirectToRoute('appointment_edit', array('id' => $appointment->getId()));
}
return $this->render('appointment/edit.html.twig', array(
'appointment' => $appointment,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
View for "new" appointment
{% block content %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
window.onload = function() {
var $sport = $('#appointment_client');
$sport.change(function() {
var $form = $(this).closest('form');
var data = {};
data[$sport.attr('name')] = $sport.val();
data['appointment[_token]'] = $('#appointment__token').val();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
$('#appointment_disease').replaceWith(
$(html).find('#appointment_disease')
);
}
});
});
};
{% endblock %}
View for "edit" appointment - it's almost the same as for "new" appointment
{% block content %}
{{ form_start(edit_form) }}
{{ form_widget(edit_form) }}
{{ form_end(edit_form) }}
window.onload = function() {
var $sport = $('#appointment_client');
$sport.change(function() {
var $form = $(this).closest('form');
var data = {};
data[$sport.attr('name')] = $sport.val();
data['appointment[_token]'] = $('#appointment__token').val();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
$('#appointment_disease').replaceWith(
$(html).find('#appointment_disease')
);
}
});
});
};
{% endblock %}
You create a new Appointment in your editAction and then persist it. You should take the one that's in your function parameters, handle the request and just flush, since your object is already persisted.
So remove these lines :
$appointment = new Appointment();
// ...
$em->persist($appointment);

jsmPayment etsPaymentOgone gives me an error The controller must return a response

I'm trying to implement JSMPayment and EtsPaymentOgoneBundle without success.
I get the error : "The controller must return a response". I'm agree with that but it's so written in the documentation. So am I something wrong or is it a bug/error in the documentation.
The error may be this but it's so written in doc...
return array(
'form' => $form->createView()
);
Now, if I change this line and return to a twig template, I only get one radio button. Why ?
Any help will very help me because, I'm really lost.
My all controller
/**
*
*/
class PaymentController extends Controller
{
/** #DI\Inject */
private $request;
/** #DI\Inject */
private $router;
/** #DI\Inject("doctrine.orm.entity_manager") */
private $em;
/** #DI\Inject("payment.plugin_controller") */
private $ppc;
/**
*
* #param \CTC\Bundle\OrderBundle\Controller\Order $order
* #return RedirectResponse
*/
public function detailsAction(Order $order, Request $request)
{
$form = $this->getFormFactory()->create('jms_choose_payment_method', null, array(
'amount' => $order->getPackage()->getAmount(),
'currency' => 'EUR',
'default_method' => 'ogone_gateway', // Optional
'predefined_data' => array(
'ogone_gateway' => array(
'tp' => '', // Optional
'PM' => $pm, // Optional - Example value: "CreditCard" - Note: You can consult the list of PM values on Ogone documentation
'BRAND' => $brand, // Optional - Example value: "VISA" - Note: If you send the BRAND field without sending a value in the PM field (‘CreditCard’ or ‘Purchasing Card’), the BRAND value will not be taken into account.
'CN' => $billingAddress->getFullName(), // Optional
'EMAIL' => $this->getUser()->getEmail(), // Optional
'OWNERZIP' => $billingAddress->getPostalCode(), // Optional
'OWNERADDRESS' => $billingAddress->getStreetLine(), // Optional
'OWNERCTY' => $billingAddress->getCountry()->getName(), // Optional
'OWNERTOWN' => $billingAddress->getCity(), // Optional
'OWNERTELNO' => $billingAddress->getPhoneNumber(), // Optional
'lang' => $request->getLocale(), // 5 characters maximum, for e.g: fr_FR
'ORDERID' => '123456', // Optional, 30 characters maximum
),
),
));
if ('POST' === $this->request->getMethod()) {
$form->bindRequest($this->request);
if ($form->isValid()) {
$this->ppc->createPaymentInstruction($instruction = $form->getData());
$order->setPaymentInstruction($instruction);
$this->em->persist($order);
$this->em->flush($order);
return new RedirectResponse($this->router->generate('payment_complete', array(
'orderNumber' => $order->getOrderNumber(),
)));
}
}
return array(
'form' => $form->createView()
);
}
/**
*
*/
public function completeAction(Order $order)
{
$instruction = $order->getPaymentInstruction();
if (null === $pendingTransaction = $instruction->getPendingTransaction()) {
$payment = $this->ppc->createPayment($instruction->getId(), $instruction->getAmount() - $instruction->getDepositedAmount());
} else {
$payment = $pendingTransaction->getPayment();
}
$result = $this->ppc->approveAndDeposit($payment->getId(), $payment->getTargetAmount());
if (Result::STATUS_PENDING === $result->getStatus()) {
$ex = $result->getPluginException();
if ($ex instanceof ActionRequiredException) {
$action = $ex->getAction();
if ($action instanceof VisitUrl) {
return new RedirectResponse($action->getUrl());
}
throw $ex;
}
} else if (Result::STATUS_SUCCESS !== $result->getStatus()) {
throw new \RuntimeException('Transaction was not successful: '.$result->getReasonCode());
}
// payment was successful, do something interesting with the order
}
public function cancelAction(Order $order)
{
die('cancel the payment');
}
/** #DI\LookupMethod("form.factory") */
protected function getFormFactory() { }
}
if you use
return array(
'form' => $form->createView()
);
at the controller, then you should add #Template annotation to the controller action
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class PaymentController extends Controller
{
...
/**
*
* #param \CTC\Bundle\OrderBundle\Controller\Order $order
* #Template()
* #return RedirectResponse
*/
public function detailsAction(Order $order, Request $request)
or you should return "render" with a template
return $this->render('MyAppSomeBundle:Payment:details.html.twig', array( 'form' => $form->createView());

Resources