Sulu media display in list - symfony

I created an Entity, PlayerInfo. Inside of that, I have photo field and defined MediaInterface, and use it with that. In adminUI everything is shown OK, in Frontend too, but when I got an idea to show thumbnail in list, I get empty field, and error in console that says:
Invalid type given: "number". "object" is needed. (TRANSFORMER ERROR)
Here is my list XML property code:
<property name="avatar" visibility="always" translation="sulu_admin.avatar" sortable="false">
<field-name>id</field-name>
<entity-name>SuluMediaBundle:Media</entity-name>
<joins>
<join>
<entity-name>SuluMediaBundle:Media</entity-name>
<field-name>App\Entity\PlayerInfo.photo</field-name>
</join>
</joins>
<transformer type="thumbnails"/>
</property>
What can be the problem?

The table adapter of the Sulu list view uses a transformer to determine what should be rendered inside of the cell based on the data returned by your API.
You have used the thumbnails transformer in your code. If you look at the ThumbnailFieldTransformer implementation, you see that the transformer expects data in a format like this:
{
"sulu-40x40":"/uploads/media/sulu-40x40/02/2-isle.jpg?v=1-0",
}
I suspect that you have used the ListBuilder component of Sulu to gather that list data in the controller that implements your API (like the sulu-demo project). The ListBuilder component uses optimized queries to load the requested data directly from the database.
Unfortunately, the ListBuilder component returns only the ID of the associated media entity and does not transform the data into the format that is expected by the ThumbnailFieldTransformer automatically. You need to construct and set the object that contains the thumbnail urls in your controller using the MediaManagerInterface::getFormatUrls method.
As an example, you can have a look at how the organization logo is handled in the AccountController that implements the API for the built-in organization list of Sulu:
$ids = \array_filter(\array_column($accounts, 'logo'));
$logos = $this->mediaManager->getFormatUrls($ids, $locale);
foreach ($accounts as $key => $account) {
if (\array_key_exists('logo', $account) && $account['logo'] && \array_key_exists($account['logo'], $logos)) {
$accounts[$key]['logo'] = $logos[$account['logo']];
}
}

You have to set the Image in your Entity.
Let's take a "User" Entity for example.
I think you have some kind of property like "avatar".
/**
* #var MediaInterface|null
*/
protected $avatar;
The error occurs because you have only saved the ID.
The solution is to set the avatar in the Entity before.
e.g. in the controller you call for the list.
$media = $this->container->get('sulu.repository.media')->findMediaById($user->getAvatar()->getId());
$user->setAvatar($media);

Related

Filter Entity Reference View with dynamic arguments from Reference Field

I need to filter an "Entity Reference View" autocomplete widget by passing arguments from a "Reference Field" in my content type.
I researched on this and found that PHP Code type Contextual Filter is the most suggested way to achieving this but as PHP Code has now been removed from Drupal 8 Core, what are the alternatives to this common use case? (an earlier suggestion to use PHP Code: Drupal 7: how to filter view content (with entity reference field) based on current page content)
While editing the reference field, it seems that only hard-coded values be mentioned in "View arguments" field and there is no dynamical way of achieving this (e.g. from URL/query string etc).
It's hacky, but you can use a hook_form_alter. Here's an example passing the current NID as an argument:
/**
* Implements hook_form_alter().
*/
function MYMODULE_form_alter(&$form, FormStateInterface $form_state, $form_id)
{
if ($form_id == 'node_NODETYPE_edit_form') {
$node = $form_state->getFormObject()->getEntity();
$form['field_MY_REF_FIELD']['widget'][0]['target_id']['#selection_settings']['view']['arguments'][0] = $node->id();
}
}
For example.com/path?id=55
[current-page:query:id]
For example.com/path/55
[current-page:url:args:last]
For example.com/path/alias
[current-page:url:unaliased:args:last]

Set up non-persistent relation in Doctrine 2

I have an object $user that has a one to many relation with $establishment. I can use:
$user->getEstablishments();
The user can select a stablishment to work on. I have this method that I call in the controller:
$user->setCurrentEstablishment($establishment);
And this one that I call in the view:
$establishment = $user->getCurrentEstablishment();
I want to be able to call:
$user->setCurrentEstablishmentBy Slug($establishment_slug);
where the slug is a string, and let the user object look for the establishment.
Doctrine discourages the practice of accessing the Entity Manager inside the Entity object, but I think that using it in the controller is even worse.
I suspect that some special Doctrine annotation exists that takes care of non persistent relations like this, or some method other than serving the Entity Manager through a service should be used here. Some easy way of referencing other entities from inside the model.
¿Is there any? ¿How could I do that?
There is no Annotation in Doctrine which could convert slug into object.
What can help You is ParamConverter, with it you can automatically convert slug from query into object. But it still must be used in Controller.
Example usage:
/**
* #Route("/some-route/{slug}")
* #ParamConverter("object", class="AppBundle:Establishment", options={"id" = "slug", "repository_method" = "findEstablishmentBySlug"})
*/
public function slugAction(Establishment $object)
{
...
Docs about param converter: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html

add a variable session in entity?

i create an entity "Products".
in this entity, i get the price like
public function getPrice()
{
return $this->price;
}
Indeed, i would like to add in this method a session variable for convert currency like this :
public function getPrix()
{
$devise = $this->session->get('CurencyToConvert');
$json = json_decode(file_get_contents('http://api.fixer.io/latest?symbols='.$devise));
$rates = $json->rates->CHF;
return $this->prix * $rates;
}
but i think this is the wrong solution.
i don't know how to do to get an automatic conversion when i get the price!!
do I create a service for my checkout and a twig filter for my views?
thank you
The Products class is a POPO (Playing Old PHP Object) it's really required to keep it simple which means this class must have only attributes like price and getters and setters for those attributes,
You can create a service to handle Currency conversion, and you can also inject it into a twig filter so you gonna have one piece of code implementing this functionality

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

Return a value from entity to view file in symfony

I want to return a value from entity to view file. Below is my entity function
public function getVisitorName($id)
{
$repository = $this->getDoctrine()->getRepository('SystemVmsBundle:VisitorsDetails');
$product = $repository->findOneBy(array('id' =>$id));
$name=$product->getFirstname();
return $name;
}
This is the line in my view file which calls that function
{{ entity.visitorName(entity.visitorId) }}
Its not giving me any error. But only a blank page. How can i fix this?
This is my controller code
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('SystemVmsBundle:EntryDetails')->findAll();
return array(
'entities' => $entities,
);
}
I am trying to fetch the visitors name(from visitors table) corresponding to the visitor id(in entry table).How will i do it then?
you have two ways of doing it:
1) Map your SystemVmsBundle:EntryDetails entity, to SystemVmsBundle:VisitorsDetails as OntToOne by adding field details to your EntryDetails; , and then in twig template just call it via
{{ entity.details.name }}
2) instead of creating getVisitorName(), it is better to create twig function for this, with same functionality.
Your indexAction() is not returning a response object, it is just returning an array of entities. Controller actions should return a Response containing the html to be displayed (unless they are for e.g. ajax calls from javascript). If you are using twig templates you can use the controller render() method to create your response, something like this:
return $this->render('<YourBundle>:<YourViewsFolder>:<YourView>.html.twig', array(
'entities' => $entities,
));
When you've corrected that I suspect you'll get an error because $this->getDoctrine() won't work from an entity class. The code you have in the getVisitorName() method just shouldn't be in an entity class.
As #pomaxa has already suggested, I believe there should be a relationship between your EntryDetails and VisitorsDetails entities although I don't know enough about your data from the question to know what type of relationship it should be (OneToOne / ManyToOne). If your EntryDetails entity had a relationship to VisitorsDetails, the EntryDetails class would then contain a $visitorsDetails attribute and methods to get/set it. Then the line in your twig file would look like this:
{{ entity.visitorsDetails.firstName }}
There is a section on Entity Relationships / Associations in the Symfony Manual.
Also, I hope you don't mind me giving you a little advice:
Be careful when you copy and paste code as it appears you have done in getVisitorName(). You have kept the variable name '$product' although there are no products in your system. This sort of thing can cause bugs and make the code more difficult to maintain.
I recommend you avoid tacking 'Details' onto the end of entity names unless you genuinely have two separate and related entities such as Visitor + VisitorDetails and a good reason for doing so. I think the entities in your example are actually 'Visitor' and 'VistorEntry'.
Unless you are writing a re-usable component, I recommend you use specific variable names like '$visitorEntries' rather than '$entities' in your controller and twig.
In general, the more meaningful your variable names, the more readable, maintainable and bug-free your code is likely to be. Subsequently, it will also be much easier for people on SO to understand your code and give you help when you need it.

Resources