Easy admin list modification - symfony

I don't get this guys!
At this moment I still have only one entity (User). I manage my users with the FOSUserBundle.
I want to modify the fields displayed in my list. Like this right?
config.yml
easy_admin:
entities:
Users:
class: AppBundle\Entity\User
list:
fields:
- username
- email
- last_login
But I get this error when trying to do it;
An exception has been thrown during the rendering of a template
("Warning: mb_strlen() expects parameter 1 to be string, object
given") in #EasyAdmin/default/field_text.html.twig at line 4.
I've added a __toString() method in my User entity but it still doesn't work;
User.php
public function __toString()
{
return $this->getUsername();
}
I am pretty new to the whole Symfony thing, so can somebody please help me out?

This issue is fixed and will probably be available with the next stable release.
In the meantime you can fix this by manually copy paste this 5 lines into EasyAdminTwigExtention.php at line 269.
try {
$value = (string) $value;
} catch (\Exception $e) {
$value = '';
}
Look here for the same question I asked on Git. And here where the code is modified.

Related

Symfony: Handling EntityNotFoundException on Doctrine relation

When I tried to display a related object in Twig, and that relation is not present because the ID is in the parent entity, but the related entity was not in the current database, Symfony throws a 500 error
// EntityNotFoundException Twig_Error_Runtime
An exception has been thrown during the rendering of a template
("Entity of type 'App\Entity\Location' for IDs id(265) was not
found").
I'd like to be able to ignore this error and instead display something like "Related object missing".
It seemed like this could be solved by some checking in Twig, but checking if the relation is null or not defined does not work - they both still find the relation, but when a property is called on the related entity, the exception is thrown.
Has anyone solved this problem already?
You could check if the entity exists in a Twig extension
Something like:
public function isRelatedEntityDefined($entity)
{
try {
if(isset($entity->getSomeField()) return true;
} catch (EntityNotFoundException $e) {
return false;
}
}
Have a look at this subject
On delete cascade with doctrine2
Isn't the problem from your annotation ?
On your owning side the ID is still defined but the entity doesn't exist anymore.
You should do something like this :
* #JoinColumn(name="locationId", referencedColumnName="id", onDelete="set null")

How to use the User value resolver in Symfony 3.2?

I'm building a small website using symfony 3.2.
There is a page in which the user can change its profile data with a form. I used the structure seen in the official tutorial. Here is the declaration of my controller :
/** #Route("/profil", name="profil_show_user") */
public function userProfileAction(Request $request, UserInterface $user) {
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
throw $this->createAccessDeniedException();
}
//...
$user->getProfile();//and do stuff
//...
}
My problem is that if the user is disconnected for being inactive for too long, or if someone bookmark the page but is not connected, I have this ugly error coming :
Controller
"AppBundle\Controller\ProfilController::userProfileAction()" requires
that you provide a value for the "$user" argument. Either the argument
is nullable and no null value has been provided, no default value has
been provided or because there is a non optional argument after this
one. 500 Internal Server Error - RuntimeException
In the New in Symfony 3.2 changelog, there is something about the new User value resolver. I tried to change to UserInterface $user = null, and it make the page redirect to the path I set in failure_path of security.yml, which is the good behaviour.
But then if I'm connected and go to profil_show_user, I get that other error :
Error: Call to a member function getProfile() on null
I search thoroughly the symfony documentation but couldn't find anything.
Could someone explain to me what goes wrong, what I misunderstood and how can I make this work ?
EDIT :
I thought I might say that if I don't use te value resolver, everything works fine. This is an educationnal and curiosity question about a new feature which I don't manage to use. This code works :
/** #Route("/profil", name="profil_show_user") */
public function userProfileAction(Request $request) {
$user = $this->getUser();
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
throw $this->createAccessDeniedException();
}
//...
$user->getProfile();//and do stuff
//...
}

Case-insensitive user-names in Symfony2

By default, Symfony2 matches usernames case-sensitively. I want users to be able to enter johnsmith, JohnSmith, johnSMITH, or any variant of that, and have them all register as johnsmith. How do I do this?
I though the easiest way would be to always convert each username to lower-case before comparing them. This is easy to do on the one side (just throw a lower() into the SQL statement), but how do I do that for what the user types in in the login form? Since Symfony automatically takes care of the login_check route handling, I can't figure it out.
Better yet, is there some option I can set to enable case-insensitivity instead?
Just write correct loadUserByUsername function in UserRepository.
It must not be case sensitive:
public function loadUserByUsername($username)
{
$user = $this->createQueryBuilder('u')
->where('LOWER(u.email) = :username')
->setParameter('username', strtolower($username))
->getQuery()
->getOneOrNullResult();
if ($user){
return $user;
}
throw new UsernameNotFoundException('Unable to find user "' . $username . '"');
}
You already fixed it, but I will explain another solution for users with similar problems:
You have to implement your own Provider this way: http://symfony.com/doc/current/cookbook/security/entity_provider.html#authenticating-someone-with-a-custom-entity-provider
Use the following query instead in method loadUserByUsername:
$user = $this->findOneBy(array('username' => strtolower($username)));
This worked for me. (Also in Doctrine Mongo ODM)
Did you try to convert the input into lowercase using CSS ? There are actually ways to control data input before it is handed to the login_check controller, but if you want a quick fix :
p {
text-transform: lowercase;
}
In your setUsername you could just have the text changed to lowercase like..
public function setUsername($username)
{
$this->username = mb_strtolower($username);
return $this;
}
For reference, FOSUserBundle handles this by "canonicalizing" the username (to usernameCanonical) and email address (to canonicalEmail) in the updateUser call (see Doctrine\UserManager that calls the Canonicalizer) which it then uses for searches.
I feel like an idiot. All I had to do was add another lower() around the where clause in my SQL statement. Like this:
select lower(USERNAME) as USERNAME, PASSWORD, ROLES, ALL_CUSTOMER_ACCESS
from COMPANYNAME_USERS
where lower(USERNAME) = lower(:username)

How to retrieve translation of a "sub entity" using Symfony a2lix knp doctrine behaviors translatable

I'm new in symfo but I need to translate content of my site.
I'm using a2lix (last version) and KNP doctrine behaviors (Translatable).
Let's say that I have 2 entities (e.g. Articles and Categories).
As in the doc (https://github.com/KnpLabs/DoctrineBehaviors) for translations, I'm using 2 classes for Categories (Category and CategoryTranslation).
To retrieve the translations, of my category, I'm using a query with the locale. I get the locale with Request $request ($locale = $request->getLocale();). Here is an example of my controller and the query in my repository.
Controller
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$locale = $request->getLocale();
$entities = $em->getRepository('AcmeBundle:Category')->findAllByLocale($locale);
return $this->render('CTCArtworkBundle:Backend/Artwork:index.html.twig', array(
'entities' => $entities,
));
}
Repository
I'm trying to retrieve informations for the locale.
public function findAllByLocale($locale){
return $this->createQueryBuilder('a')
->join('a.translations', 'aTrans')
->where('aTrans.locale = :locale')
->setParameter("locale", $locale)
->addSelect('aTrans')
->getQuery()
->getResult()
;
}
I don't know if it's a good practice but it works for me. I retrieve fr/en categories in my Twig template like so when I change the url :
<tr>
<th>Category</th>
<td>{{ category.translations|First.name }}</td>
</tr>
My problem
For the translation of my article, I do the same. I have 3 properties
- title
- description
- category (I'm using a2lix_translatedEntity (http://a2lix.fr/bundles/translation-form/#bundle-additional))
When I try to render a record of Article, I never retrieve the translation for my category Name but well for title and description.
I also read that (https://github.com/KnpLabs/DoctrineBehaviors#guess-the-current-locale) but I don't really understand. Is that a way to always pass locale ?
What am I doing wrong ?
I'm blocked and don't find any documentation to resolve my problem. Sorry for my english ;-)
Any help would be very appreciate. Many Thanks
KNP has its own way to guess the current locale, simply by accessing current request scope. The whole "passing locale" thing is useful if you want to pull records for specific locale.
Now, for your category translation. Since you did not include your entities, I will try to show you some examples to access your translations.
In your Category entity, lets say you have a property name that would return your category name. Then you can define a simple helper method that would return that name, by current locale:
public function getName() {
if( $name == $this->translate()->getName() ) {
return $name;
}
return '';
}
So, what have we done here?
$this->translate()->getName() - this line looks for your translation entity (in this case that would be CategoryTranslation) and invokes method getName() . Then, we either return translated category name, or an empty string if no translation has been added.
And lastly, this is how you can access your category name in your twig template:
Since we defined our helper method, there is no longer any need to access .translations in your template. You can simply call:
{{ category.name }}
Hope you got the idea.
And you can also use this
{{ category.translate.name }}
With DoctrineBehaviors v2, you can add this to your Category class:
public function __call($name, $arguments)
{
return $this->proxyCurrentLocaleTranslation($name, $arguments);
}
Here's what it does. So, in your Category entity, lets say you have a property description that would hold your category description. The code above will generate a corresponding property getter: getDescription(). Which ultimately will allow you to use this property in your Twig template:
{{ category.description }}

Sonata Admin - how to set the menu.label attribute?

According to the Sonata source code, the last node in the breadcrumb is rendered this way:
# standard_layout.html.twig #
<li class="active"><span>{{ menu.label }}</span></li>
In my setup, when opening a given Admin subclass, the last node simply becomes a raw string according to the entity handled by the Admin:
Dashboard / Entity List / Acme\SomeBundle\Entity\Stuff:000000001d74ac0a00007ff2930a326f
How can I set the value of menu.label to get something more appropriate? I have tried, in my Admin subclass, to override the following:
protected function configureTabMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null) {
$this->configureSideMenu($menu, $action, $childAdmin);
}
protected function configureSideMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null) {
$menu->setLabel("Some nice label");
$menu->setName("Some nice name");
}
However, this does not change anything, even though I have verified that the methods above are called during runtime.
Finally found a good (and somewhat obvious) solution to this.
The Sonata Admin class uses an internal toString($object) method in order to get a label string for the entity it is handling. Thus, the key is to implement the __toString() method of the entity in question:
public function __toString() {
return "test";
}
The best way is to configure the $classnameLabel variable in the Admin Class :
class fooAdmin extends Admin
{
protected $classnameLabel = 'Custom Label';
}
But it have the same issue (weird name with entity path) doing it, even if it is working fine on all the others pages.
Apparently, the Sonata way of solving this is show here:
Quote:
While it’s very friendly of the SonataAdminBundle to notify the admin of a successful creation, the classname and some sort of hash aren’t really nice to read. This is the default string representation of an object in the SonataAdminBundle. You can change it by defining a toString() (note: no underscore prefix) method in the Admin class. This receives the object to transform to a string as the first parameter:
Source: https://sonata-project.org/bundles/admin/master/doc/getting_started/the_form_view.html#creating-a-blog-post

Resources