How can I make my html Button
(like <button type="button" class="btn btn-warning btn-xs">delete</button>)
call a Controller Action like deleteAction($project)
from within my twig code?(or with java script)
In twig template
Delete
On your controller
/**
* #param User $entity
*
* #Route("/{id}/entity-remove", requirements={"id" = "\d+"}, name="delete_route_name")
* #return RedirectResponse
*
*/
public function deleteActionName(User $entity)
...
see http://symfony.com/doc/current/book/templating.html#linking-to-pages
Home
Related
After add functionnality upload file or many files thanks the bundle "vich", i would download the file who uploaded. My files are saved into a upload folder created to the root folder.
I've this code but error saying "file not found"..
<a download class="btn btn-info btn-sm" href="{{'upload/' ~ document.image }}"><i class="fas fa-file-download"></i> {{ document.image }} </a>
To download a file when you use Vich uploader bundle, you have to create a function inside your controller class and call it from your template.
For example:
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Vich\UploaderBundle\Handler\DownloadHandler;
class MyController extends AbstractController
{
/**
* #Route(...)
*
* #param Document $document The document to download
* #param DownloadHandler $downloadHandler Handler
*
* #return Response
*/
public function downloadDocument(Document $document, DownloadHandler $downloadHandler): Response
{
return $downloadHandler->downloadObject($document, 'documentFile');
}
}
Form more information, see VichUploaderBundle serving_files_with_a_controller
i'm making an app to make appointments with doctors, and in the template of the patient I need to use the id of the entity doctor in the path because I use it in the code of my controller, and I still can't get the Id of the entity doctor because when i do {{ doctor.id }} nothing appears on my screen, the content is empty.
As a solution I used the email of the doctor in the URL but it is quite ugly.
This is the code of the controller
/**
* #Route("/patient/ajouter-medecin-favoris/{id}", name="meet_my_doc_ajouter_medecin_favoris")
*/
public function ajouterMedecinFavoris(MedecinRepository $repoMedecin, ObjectManager $manager, $id)
{
$patient = $this->getUser();
$medecin = $repoMedecin->findOneById($id);
$patient->addMedecinsFavori($medecin);
$manager->persist($patient);
$manager->flush();
return $this->RedirectToRoute('accueil');
}
here's the code of the element I use to click on it to redirect on the controller previously
<fieldset>
<h4><i class="fa fa-star"></i> Dr. {{ medecin.nom }} {{ medecin.prenom }}</h4>
</fieldset>
I expected to be able to use the id of the doctor in the URL but I think when you're logged as an entity you can't get the ID (not the id used to log in) of other users and the content of the variable is empty. But I would know if there's a solution to use the ID because passing the email into the url isn't the solution I want, and I had the same problem on other piece of code where the of other entity is empty.
Here's the code of the controller that send the datas to the view
/**
* #Route("/patient/medecins-favoris", name="meet_my_doc_afficher_medecin_favoris")
*/
public function afficherMedecinFavoris()
{
$patient = $this->getUser();
$medecins = $this->getUser()->getMedecinsFavoris();
return $this->Render('meet_my_doc/afficherLesMedecinsFavoris.html.twig', ['medecins' => $medecins]);
}
try this
{{path('meet_my_doc_ajouter_medecin_favoris',{(id): medecin.id})}}
I would do something like this, first controller to receive Medicine Object like this, in this case you dont need to use $medecin = $repoMedecin->findOneById($id);
/**
* #Route("/patient/ajouter-medecin-favoris/{id}", name="meet_my_doc_ajouter_medecin_favoris")
*/
public function ajouterMedecinFavoris(MedecinRepository $repoMedecin, ObjectManager $manager, Medecin $medecin)
{
$patient = $this->getUser();
$patient->addMedecinsFavori($medecin);
$manager->persist($patient);
$manager->flush();
return $this->RedirectToRoute('accueil');
}
in twig in both cases you do something like this
{% for medecin in medecins %}
<fieldset>
<h4>
<i class="fa fa-star"></i>
Dr. {{ medecin.nom }} {{ medecin.prenom }}
</h4>
</fieldset>
{% endfor %}
If your code is how you've pasted it, then I think the issue lies in a typo - in the afficherMedecinFavoris() action you pass medicins to the view, and inside the view you try to access the id of medicin. So either remove the extra s in the afficherMedecinFavoris() or add that extra s to the path id parameter value.
Aside from that, I believe that this should work (under the condition that the identity field for Medecin entity is id):
/**
* #Route("/patient/ajouter-medecin-favoris/{id}", name="meet_my_doc_ajouter_medecin_favoris")
*/
public function ajouterMedecinFavoris(Medecin $medecin)
{
$patient = $this->getUser();
$patient->addMedecinsFavori($medecin);
$manager = $this->getDoctrine()->getManager();
$manager->persist($patient);
$manager->flush();
return $this->RedirectToRoute('accueil');
}
To know how the Medecin entity is available as an argument for the controller read this
I'm sorry to post the answer just now, but this how it worked for me : medecin inherit from User, so when I'm creating a medecin, it is creating also an User, both with the same Id, and if I want to use the medecin object's Id, I need to edit the getId() and replace the code by parent::getId(), this is the only way I've found to solve this problem.
Could someone please explain how I can add a search box to the homepage of my website built on Sylius?
I have tried using the SyliusSearchBundle but that seems to be very out of data and the sample config settings throw errors.
I'd be grateful for any help.
Disclaimer
Steps below work at the time I'm writing. SyliusElasticSearchBundle plugin is in a heavy development state, some of the things crash now, but will be fixed for sure.
I've created a demo repository here: https://github.com/mheki/sylius-search-demo
You need running ElasticSearch and a SyliusElasticSearchBundle plugin.
Follow installation instructions from readme: https://github.com/Lakion/SyliusElasticSearchBundle
Just bear in mind to install sylius dev-master (circular dependency...)
Import bundle's config, routing, enable it in AppKernel.
At the moment I'm writing the bundle needed filter_sets config, otherwise it crashed
So start with the simple search by product name:
lakion_sylius_elastic_search:
filter_sets:
default:
filters:
name:
type: string
Populate elastic index with:
bin/console fos:elastic:pop
Override original routing for lakion_elastic_search_shop_product_index - use filter_set: for your channel code.
lakion_elastic_search_shop_product_index:
path: /products
methods: [GET]
defaults:
_controller: lakion_sylius_elastic_search.controller.search:filterAction
_sylius:
template: "#LakionSyliusElasticSearch/Product/index.html.twig"
resource_class: "%sylius.model.product.class%"
filter_set: default
requirements:
slug: .+
Original product index page was failing for me and I had to remove
{{ form_row(form.search) }}
from it. So copied #LakionSyliusElasticSearch/Product/index.html.twig into Resources directory:
Resources\LakionSyliusElasticSearchBundle\views\Product\index.html.twig and made that change.
Now the last thing is to create a form, for example copying the file _security.html.twig from SyliusShopBundle. Add something like this:
<div class="item">
<form action="{{ path('lakion_elastic_search_shop_product_index') }}" method="get">
<div class="ui icon input">
<input type="text" placeholder="{{ 'sylius.ui.search'|trans }}..." name="filter_set[name]" />
<button type="submit" class="ui button mini">
<i class="search icon"></i>
</button>
</div>
</form>
</div>
and here we go :)
Alternatively, if you don't want to use the SyliusElasticSearchBundle plugin, you can implement a simple search on your own (which search inside the product name, description and category name) :
Create a classic html search form, for example:
<form role="search" method="get" action="{{path('app_search_results') }}">
<input type="search" id="site-search" name="q"
placeholder="{{ 'walrus.search.input.placeholder'|trans }}"
aria-label="{{ 'walrus.search.aria.label'|trans }}">
<button>{{ 'walrus.search.aria.button'|trans }}</button>
</form>
Create a controller action for the route 'app_search_results' in order to get the search request sent by your search form :
<?php
namespace AppBundle\Controller;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Locale\Context\LocaleContextInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use \Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class SearchController extends Controller
{
/**
* #var LocaleContextInterface
*/
private $locale;
/**
* #var ChannelContextInterface
*/
private $channelContext;
/**
* #var RepositoryInterface
*/
private $productRepository;
public function __construct(
LocaleContextInterface $locale,
ChannelContextInterface $channelContext,
RepositoryInterface $productRepository
)
{
$this->locale = $locale;
$this->channelContext = $channelContext;
$this->productRepository = $productRepository;
}
/**
* #Route("/search", name="app_search_results")
*/
public function searchAction(Request $request) : Response
{
$searchTerm = $request->query->get('q');
$channel = $this->channelContext->getChannel();
$localeCode = $this->locale->getLocaleCode();
$products = $this->productRepository->findByTerm($channel, $localeCode, $searchTerm);
return $this->render(
'#App/search/searchListProducts.html.twig',
[
'products' => $products
]
);
}
}
Don't forget to manually wire the dependency injected through the constructor.
Override the product repository in order to implements the findByTerm() method :
<?php
namespace AppBundle\Repository;
use Sylius\Bundle\CoreBundle\Doctrine\ORM\ProductRepository as
BaseProductRepository;
use Sylius\Component\Core\Model\ChannelInterface;
class ProductRepository extends BaseProductRepository
{
public function findByTerm(ChannelInterface $channel, string $locale, $searchTerm): array
{
$qb = $this->createQueryBuilder('p')
->addSelect('translation')
// get the translated product for the product regarding the current locale
->innerJoin('p.translations', 'translation', 'WITH', 'translation.locale = :locale')
->orWhere('translation.name LIKE :searchTerm')
->orWhere('translation.description LIKE :searchTerm')
// get the taxons of the product
->innerJoin('p.productTaxons', 'productTaxon')
->innerJoin('productTaxon.taxon', 'taxon')
// get the translated taxon
->innerJoin('taxon.translations', 'taxonTranslation', 'WITH', 'taxonTranslation.locale = :locale')
->orWhere('taxonTranslation.name LIKE :searchTerm')
->andWhere(':channel MEMBER OF p.channels')
->andWhere('p.enabled = true')
->setParameter('searchTerm', '%'.$searchTerm.'%')
->setParameter('locale', $locale)
->setParameter('channel', $channel)
->getQuery();
return $qb->getResult();
}
}
You just need now to create the page rendering the list of product (the #App/search/searchListProducts.html.twig). And to tell Sylius to use your custom HomepageController instead of the original one. Same goes for your Product Repository. This can be done inside the services.yml file of you app folder :
services:
sylius.controller.shop.homepage:
public: true
class: AppBundle\Controller\Shop\HomepageController
arguments:
- '#templating'
- '#sylius.context.locale'
- '#sylius.repository.taxon'
sylius_product:
resources:
product:
classes:
repository: AppBundle\Repository\ProductRepository
I have a News entity with the next properties:
text
start_date
expire_date
Here's part of the class:
//News.php
/**
* #ORM\Column(type="string", length=200)
*/
private $text;
/**
* #ORM\Column(type="datetime")
*/
private $start_date;
/**
* #ORM\Column(type="datetime")
*/
private $expire_date;
I want to show all the news in a list in a twig template, this is how I'm doing that:
<div class="list-group">
{%for news in news%}
<div class="panel panel-default">
<div class="panel-heading">{{ news.start_date|date('Y-m-d') }}</div>
<div class="panel-body">
{{ news.text }}
</div>
</div>
{%endfor%}
</div>
The fact is that I get the following error:
Neither the property "start_date" nor one of the methods "start_date()", "getstart_date()"/"isstart_date()" or "__call()" exist and have public access in class "AppBundle\Entity\News".
But If I try to render only the text property, I am able to access it.
Why is that?
Your attribute is private. you can add a getter
public fucntion getStartDate() {
return $this->start_date;
}
and in twig
{{ news.startDate|date('Y-m-d') }}
Bundle docs explain how to load tagging of a simple object:
$this->tagManager->loadTagging($article);
But I need to load a list (ArrayCollection from doctrine query) of taggable resources with their tags. And later iterate over a collection in twig and print:
Object: tag1, tag2, tag..n
Old post, but hopefully this answer will help someone, as I ran into the same issue trying to implement the tagging bundle. The problem is that your entity will have a private or protected property for tags, but the way the documentation reads on the bundle, there is no association mapping for this property, and it's not an actual field (column). So trying to access the tags property or use the getTags method on your entity won't work, either in your controller or in Twig. I feel like the documentation on the bundle may be missing some mapping annotations on the tags property, but I haven't been able to narrow down exactly what it should be.
I ended up taking the approach a couple others recommended by looping thru my entities in the controller, and loading the tagging using the tagmanager for each entity. What I also did which turned out to be helpful was to add a setTags method to the entity that accepts an ArrayCollection, that way when looping thru the entities in your controller, you can set the Tags on each one, then access them in twig like you want to do. For example:
Add this setTags method to your entity:
/**
* #param ArrayCollection $tags
* #return $this
*/
public function setTags(ArrayCollection $tags)
{
$this->tags = $tags;
return $this;
}
This will allow you to set the tags property from your controller.
Then in your controller:
/**
* #param Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$posts = $em->getRepository('ContentBundle:Post')->findAll();
// here's the goods... loop thru each entity and set the tags
foreach ($posts as $post) {
$post->setTags($this->getTags($post));
}
// replace this example code with whatever you need
return $this->render('AppBundle::index.html.twig',array(
'posts' => $posts
));
}
/**
* #param Post $post
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getTags(Post $post) {
$tagManager = $this->get('fpn_tag.tag_manager');
$tagManager->loadTagging($post);
return $post->getTags();
}
The getTags method in this controller simply takes your entity and uses the tagmanager to find and return it's tags. You'll see the loop in the index method that adds the tags to each entity.
Then in Twig you can access your tags on each post in the loop:
{% for post in posts %}
<h2>{{ post.title }}</h2>
{% for tag in post.tags %}
{{ tag.name }}
{% endfor %}
{% endfor %}
You could iterate over the collection in your controller, like this:
foreach($articles as $article){
$this->tagManager->loadTagging($article);
}