I use KnpDoctrineBehaviors (Sluggable,Translatable, etc ). Field that I use for slug, I have only in MyClassTranslations. So when I add Sluggable for my translations class, I have for each i18n entry different slug. How to solve this? Thank you!
You can override the getter for title in your entity, and just call the translate method from KnpDoctrineBehaviors on your entity. It will try to get the title translation in your current locale, or fallback to default locale translation.
<?php
namespace AppBundle\Entity;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use AppBundle\Entity\AppTrait\TranslatableEntity;
class SomeEntity
{
use ORMBehaviors\Translatable\Translatable;
use ORMBehaviors\Sluggable\Sluggable;
public function getSluggableFields()
{
return ['title'];
}
public function getTitle()
{
return $this->translate(null,true)->getTitle();
}
This implies that the slug might be updated often if you update the title with different locale, you might want to avoid this, and just use english title for slug generation:
public function getTitle()
{
return $this->translate('en')->getTitle();
}
Related
So I've been playing around with Symfony forms and I want to change the form action.
I've followed this guide but I don't understand what it means by "target_route". As such, I was getting an error message (see below)
I have the code below and I'm pretty sure the route I used in setAction is valid since I can browse it using my browser.
Any ideas? Thank you
my code:
<?php
// src/AppBundle/Controller/DirectoryController.php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class DirectoryController extends Controller {
/**
* #Route("/directory/form")
*/
public function formAction() {
$form = $this->get("form.factory")
->createNamedBuilder("form", "form")
->setAction($this->generateUrl("/directory/search"))
->setMethod("get")
->add("search", "submit", array("label" => "Search"))
->add("reset", "reset", array("label" => "Reset"))
->getForm();
return $this->render(
"directory/form.html.twig",
array("form" => $form->createView()
,
)
);
}
/**
* #Route("/directory/search")
*/
public function searchAction() {
return $this->render(
"directory/view.html.twig"
);
}
}
error message:
Unable to generate a URL for the named route "/directory/search" as such route does not exist.
In the example, target_route is the name of a route, not its url. For example, you might define an action like this:
/**
* #Route("/directory/search", name="directory_search")
*/
public function searchAction() {
In that case, your route would have a name of directory_search. You would then use $this->generateUrl('directory_search') to have the router turn the name into a url.
The reason you do it this way (as opposed to using urls directly) is that this allows you to change a url without having to change every place in your code that references it.
->setAction($this->generateUrl("/directory/search"))
setAction() expects a url. So you while you can give it '/directory/search', best practice would be to it $this->generateUrl('directory_search').
I have a function in my controller like this:
<?php
namespace GradeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use GradeBundle\Entity\User;
use GradeBundle\Entity\SchoolClass;
class MainController extends Controller
{
/**
* #Route("/", name="index_page")
*/
public function index()
{
return $this->render('GradeBundle:Default:index.html.twig');
}
It renders the twig template correctly. However when I use other function:
/**
* #Route("/adminNew", name="add_admin")
*/
public function addAdmin()
{
$session = new Session();
if($session->get('loggedIn') == null)
return $this->redirect($this->generateUrl('index_page'));
else
return $this->render('GradeBundle:Add:newAdmin.html.twig');
}
I have the following error:
Unable to find template "GradeBundle:Default:index.twig.html".
Does anybody have any idea what might be wrong?
It's a typo somewhere you call template:
GradeBundle:Default:index.twig.html
But you have only GradeBundle:Default:index.html.twig template.
Note the difference: html.twig twig.html
I suspect that you extend it in GradeBundle:Add:newAdmin.html.twig by:
{% extends 'GradeBundle:Default:index.twig.html' %}
but should be:
{% extends 'GradeBundle:Default:index.html.twig' %}
Have you made sure to use the correct namespace for the Controller you're using? And are you including the correct files? Also I'm not sure I understand the question correctly - are you saying if you add another function with a different twig file render, the first one no longer renders? Could I see your class names and the namespaces / use statements?
Usually in these instances, it's that the templates are in the wrong place or the correct file is not included in order to find it.
Michael
When creating a custom field in Symfony, there is a method we define getParent
We define our class by extending from AbstractType class, then return a parent type using getParent method. instead of extending from parent class.
I want to know the philosophy behind this approach.
Is it possible to define my custom type like:
class ImageType extends FileType
{
public function getName()
{
return 'image';
}
}
instead of this :
class ImageType extends AbstractType
{
public function getParent()
{
return 'file';
}
public function getName()
{
return 'image';
}
}
If can, then what is the difference between these two approach?
Thanks!
There are two main differences:
The first one is about FormTypeExtensions. These extensions modify certain form types (e.g: they could change/add some default options, or even add a field).
Using the first approach (e.g. Inheritance), all extensions for the FileType type will be applied to the ImageType, but using the second approach (e.g. getParent), they won't, thus you have more control over your structure.
The second difference is about modifying the behaviour of the parent form inside child form, using buildForm and buildView.
Using the first approach (e.g. Inheritance), will override the base class's methods if you provide them in child, but the second approach (e.g. getParent) will add the child's logic to that of parent.
Consider the following example:
// FileType
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('name', 'text');
}
// ImageType
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('email', 'email');
}
Inheritance:
form fields: [email]
getParent
form fields: [name] [email]
No, you need to extend using AbstractType. This is used for displaying and building a form and is not a simple entity that you are extending. The base type, FileType in your case, relates to an file with specific methods and you will be allowed to easily override them but extending through AbstractType and can add new fields. If you extended FileType, I do not think Symfony2 would load any new functions properly.
I think the first method is more compact and would like to use it, but I think this would cause problems if you are adjusting the buildView or setDefaultOptions, or adding another method that was not part of the base type.
I've made it simpler (apologies for the complicated question which I've left at the bottom).
I want to have a twig template render another controller as a sub-part.
Here's the parent twig (Resources/views/Default/testRenderParent.html.twig):
<p>Look! I am your father!</p>
<p>But look, I am not your
{{ render(controller("SarelTestBundle:Default:testRenderChild")) }}</p>
Here's the child twig (Resources/views/Default/testRenderChild.html.twig):
KID
The controller (Controller/DefaultController.php):
<?php
namespace Sarel\Test\TestBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
/**
* #Template()
**/
class DefaultController extends Controller
{
/**
* #Route("/testRenderParent")
*/
public function testRenderParentAction()
{
return array();
}
/**
* #Route("/testRenderChild")
*/
public function testRenderChildAction() {
return array();
}
}
When you run this, with the following URL /testRenderChild you should get "KID" echoed.
When you run this, with the URL /testRenderParent (notice the "Parent" part), you should get echoed:
Look! I am your father!
But look, I am your KID
However, instead you get this echoed, and the error below it:
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
Look! I am your father!
But look, I am not your
FatalErrorException: Error: Maximum function nesting level of '250' reached, aborting! in /Users/sarel/www/playpen/app/cache/dev/classes.php line 6134
Thus you can see, it's rendering "Look! I am your father! But look, I am your "... and then instead of rendering the child controller with it's twig template, it re-renders the parent, ending in an endless loop, which is arrested by the exception.
--- copy before I changed it ---
--- copy before I changed it ---
--- copy before I changed it ---
So I'm trying to embed a controller (and ultimately the template that the action renders) in my symfony2 project using the guidelines in enter link description here.
My Controller is defined below:
<?php
namespace OTS\CoreBundle\Controller;
/**
* #Template()
*/
class EmergencyContactsController extends Controller
{
public function addEmergencyContactAction(Request $request, $id) {
return array();
}
}
I have a twig template attached to that, which right now just have "hello world" in the form of a twig file called addEmergencyContact.html.twig.
When I go to the URL for this, which is something like localhost/my_route_to_it it works perfectly fine and I see "hello world" on the screen.
Now, according to this I merely have to put the following twig command in:
{{ render(controller('OTSCoreBundle:EmergencyContacts:addEmergencyContact', {'id': 15})) }}
When I do this and I load the holding-route it appears to be trying to load the main route, and then load the main route again inside the spot where I render the child-route. I know this because it's telling me there's variables missing - variables that I'm only using in the main twig file.
Yet, when I:
Don't have the {{ render... }} in there, it works fine - i.e. it's not other code that's giving me the exception of missing variable
Render only the child-route I get a nice "hello world" back - i.e. it's not the child twig or child controller that's buggy
Hmmm. The question is a bit confusing but:
A. Like all controller actions, your addEmergencyContact needs to return a response, not an array. So:
class EmergencyContactsController extends Controller
{
public function addEmergencyContactAction(Request $request, $id)
{
$tplData = array();
$tplData['id'] = $id;
return $this->render('CoreBundle::emergency_contact.html.twig', $tplData);
}
}
B. You need two template files. Something like:
class HelloWorldController extends Controller
{
public function helloWorldAction(Request $request, $id)
{
$tplData = array();
$tplData['id'] = $id;
return $this->render('CoreBundle::hello_world.html.twig', $tplData);
}
}
C. The render line then goes in the hello_world.html.twig file.
{{ render(controller('OTSCoreBundle:EmergencyContacts:addEmergencyContact', {'id': 15})) }}
D. Note that your emergency_contact template will only have access to values passed into it by the emergency contact action. It will not "inherit" the values that hello_world has.
So why is my code formatting messed up? Did not like numbered lists.
This turns out to be a bug in the way annotations work. When I change the controller from being globally #Template() enabled to moving that old-school back to each action individually, it works. Here's the updated controller, look at where the #Template() now sits:
<?php
namespace Sarel\Test\TestBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DefaultController extends Controller
{
/**
* #Route("/testRenderParent")
* #Template()
*/
public function testRenderParentAction()
{
return array();
}
/**
* #Route("/testRenderChild")
* #Template()
*/
public function testRenderChildAction() {
return array();
}
}
I'm using Symfony's FormBuilder to create a form and render it via Twig.
I use this as my Type:
<?php
namespace Vendor\AppBundle\Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\AbstractType;
class RequestType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
$builder->add('email', 'email');
$builder->add('question', 'textarea');
}
public function getDefaultOptions(array $options)
{
return array('data_class' => 'Vendor\\AppBundle\\App\\Request');
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'request';
}
}
When I render my form (with form_widget(form.field)) everything looks great, except for the name field, that doesn't output any input field. If I change to something like "email", it works perfectly.
I'm using Sf2.3 BETA 1. Any thoughts on why does this happen with text fields only? It's woth noting that the labels, fieldsets, and everything is outputted, except the actual <input> tag.
EDIT 1: This is the Controller Code, in case you need it.
EDIT 2: It's worth noticing that this is an update from a Sf2.1 app to Sf2.3 BETA 1. The code has been updated, but perhaps something's wrong with that?
In this case, it was something that had to do with the fact that this code is a refactor of really old (+2 years) code.
The issue was that the form widget was being replaced with another one, and that "other one" was messing with the output, since Twig's functions aren't the same, nor the structure.