Symfony3 EasyAdmin Custom non-auto ID column - symfony

I have setup a database table in which the ID values will be created by my application and NOT the database.
/**
* #ORM\Column(type="bigint", precision=14, options={"unsigned":true})
* #ORM\Id()
* #ORM\GeneratedValue("NONE")
*/
private $id;
This works fine in symfony, but I am trying to edit the table using EasyAdmin and EasyAdmin simply omits the 'id' column.
I found out that I can manipulate edit/new views configuration from EasyAdmin documentation.
Now I have the following configuration (the mentioned id is for Product):
easy_admin:
entities:
- AppBundle\Entity\Category
- AppBundle\Entity\Product
Question:
1- How do I setup the YAML configuration so id field will also appear? I found out that this partially works:
easy_admin:
entities:
Product:
class: AppBundle\Entity\Product
form:
fields:
- 'id'
But this shows only 'id', is there a way to tell that I want 'id' in addition to all the other fields so I don't have to list them manually?
2- My original config is using a list of entities with dash (-) in the YAML file. I am a YAML noob, when I make a Product: key I am not able to use the dash anymore, is there a way to keep using dash list and just make an exception for 'Product? For example the code below does NOT work, it says it is not valid YAML.
easy_admin:
entities:
- AppBundle\Entity\Category
Product:
class: AppBundle\Entity\Product
form:
fields:
- 'id'
Well, for now I solved the problem like this and abandoned the dash notation altogether:
easy_admin:
entities:
Category:
class: AppBundle\Entity\Category
Store:
class: AppBundle\Entity\Store
Product:
class: AppBundle\Entity\Product
edit:
fields:
- { property: 'stores', label: 'Stores', type_options: { by_reference: false } }
form:
fields:
- 'id'
- 'name'
- 'category'
- 'stores'

Q1: you can use customization based on entity controllers. See doc here: https://symfony.com/doc/master/bundles/EasyAdminBundle/book/complex-dynamic-backends.html#customization-based-on-entity-controllers
app/config/config.yml
User:
class: AppBundle\Entity\User
controller: UserBundle\Controller\Admin\UserController
And then in your UserController you can have something like this. Pay attention you must use the exact entity name in method signature: createUserEntityFormBuilder in your case
protected function createUserEntityFormBuilder($entity, $view)
{
$form = parent::createEntityFormBuilder($entity, $view);
$form->add('Anyfield', TextType::class, [
'label' => 'id' // feel free to add other options
]); // add fieldlike you would do in FormType
$form->remove('anyField');
return $form;
}
Q2: I can't answer to this question for sure. I do not use "Dashed" notation.
Maybe take a look at doc here: https://symfony.com/doc/current/components/yaml/yaml_format.html#collections

Related

OroPlatform: add custom field on core Entity

I'm currently working on an OroPlatform project and I need to add a custom field on the BusinessUnit core entity.
I have read the Oro documentation section about the way to extend core entities : https://doc.oroinc.com/backend/entities/extend-entities/#id1
<?php
namespace MyBundle\Bundle\AppBundle\Migrations\Schema\v1_0;
use Doctrine\DBAL\Schema\Schema;
use Oro\Bundle\EntityExtendBundle\EntityConfig\ExtendScope;
use Oro\Bundle\MigrationBundle\Migration\Migration;
use Oro\Bundle\MigrationBundle\Migration\QueryBag;
class AddColumnsToBusinessUnit implements Migration
{
public function up(Schema $schema, QueryBag $queries)
{
$table = $schema->getTable('oro_business_unit');
$table->addColumn('siret', 'string', [
'oro_options' => [
'extend' => ['owner' => ExtendScope::OWNER_CUSTOM],
'entity' => ['label' => 'siret'],
],
]);
}
}
When I run the command symfony console oro:migration:load --force, it works and the migration is applied to my database.
Now, I want a required field. I have seen the instruction 'notnull' => true to setup a non nullable field on the database.
Everything works well, but my field hasn't any JavaScript validation on the organization/business_unit/create route. Any ideas ?
You can validate the new field by extending the validation metadata that is already defined for the core entity you are extending.
To do this, please follow the official Symfony documentation and use the YML format:
https://symfony.com/doc/4.4/validation.html#constraint-configuration
The constraint that you can use for the field is "not blank."
Here is an example:
# src/<YourBundlePath>/Resources/config/validation.yml
Oro\Bundle\OrganizationBundle\Entity\BusinessUnit:
properties:
siret:
- NotBlank: ~

Sylius Resource and Doctrine Filter

I'm new in Sylius and trying to extend it for my business. I'm currently facing an issue on admin part that I don't know how to solve.
I've an Basket entity which is One-To-One related with the Sylius Product entity:
/**
* #ORM\Entity
* #ORM\Table(name="app_basket")
*/
class Basket implements ResourceInterface, BasketInterface
{
/**
* #ORM\OneToOne(targetEntity="App\Entity\Product\Product", inversedBy="basket", cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $product;
}
I created this relation to be able to deal with Order Management of Sylius much easier. I don't want to mix Basket and Product objects in my business, so I created a Doctrine filter to exclude Basket items from Products:
<?php
namespace App\Doctrine\Filter;
use App\Entity\Product\Product;
use Doctrine\ORM\Mapping\ClassMetadata;
use \Doctrine\ORM\Query\Filter\SQLFilter;
class ProductFilter extends SQLFilter
{
/**
* #inheritDoc
*/
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
if($targetEntity->getName() !== Product::class) {
return '';
}
return "$targetTableAlias.id not in (select product_id from app_basket)";
}
}
On the admin products page, everything is great, I don't have the baskets. But, if I go the the Basket admin index page, I have the following error:
An exception has been thrown during the rendering of a template
("Entity of type 'App\Entity\Product\Product' for IDs id(4) was not
found").
This is because of the grid I use. I want to display the name of the product included in the basket:
sylius_grid:
grids:
app_admin_basket:
driver:
name: doctrine/orm
options:
class: App\Entity\Basket\Basket
fields:
id:
type: string
label: sylius.ui.id
product.name:
type: string
label: sylius.ui.name
To retrieve the basket.product.name, the generated query is querying directly to the product table instead of the basket one:
SELECT t0.code AS code_1, t0.created_at AS created_at_2, t0.updated_at AS updated_at_3, t0.enabled AS enabled_4, t0.id AS id_5, t0.variant_selection_method AS variant_selection_method_6, t0.average_rating AS average_rating_7, t0.main_taxon_id AS main_taxon_id_8, t9.id AS id_10, t9.product_id AS product_id_11
--problem here
FROM sylius_product t0
LEFT JOIN app_basket t9 ON t9.product_id = t0.id
WHERE t0.id = 4
--Doctrine SQL FIlter
AND ((t0.id not in (select product_id from app_basket)));
I've also the same behavior if a get this in a twig template :
{{ basket.product.name }}
With a fetch="EAGER" annotation I don't have the error but the targeted entity still not reflect what I want.
Is there a way to force Sylius Resource to pass through basket entity first and not directly to the embedded entity?
Try this
sylius_grid:
grids:
app_admin_basket:
driver:
name: doctrine/orm
options:
class: App\Entity\Basket\Basket
fields:
id:
type: string
label: sylius.ui.id
product.name:
type: twig
label: sylius.ui.name
path: .
options:
template: thetemplate.html.twig
The path: . property gives you access to the whole entity instead of a specific property. You should then be able to access it using data.product.name in the twig template.
You could also try this, altho I haven't tested it:
sylius_grid:
grids:
app_admin_basket:
driver:
name: doctrine/orm
options:
class: App\Entity\Basket\Basket
fields:
id:
type: string
label: sylius.ui.id
product.name:
type: string
label: sylius.ui.name
path: product.name
Your filter will always prevent fetching the basket's product.
You can try to disable it at least for this request: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/filters.html#disabling-enabling-filters-and-setting-parameters

How to add item_permission on delete action in easyadmin?

I use EasyadminBundle for the Backend of a Symfony application.
Two type of users have access to the back-end and I'd like to keep the right to delete to a small number of persons granted with ROLE_ADMIN.
I'd like to use item_permission parameter as for the other actions (such as show or list) :
Lieu:
class: App\Entity\Lieu
list:
item_permission: ROLE_ENCADRANT
delete:
item_permission: ROLE_ADMIN
But it's not working and I can still delete user when I'm logged with ROLE_ENCADRANT. Is there another solution ?
I currently accomplish it with:
Lieu:
class: App\Entity\Lieu
list:
item_permission: ROLE_ENCADRANT
action: ['-delete']
help: "the delete button is accessible in <b>Edit</b> view"
form:
item_permission: ROLE_ADMIN
I'm just looking for a 100% configuration solution, more elegant than mine.
Take a look at adding an action in the docs. The action can be tied to a route, which allows specifying what role may perform the action. The downside is that the list view button is present regardless of role. You can add a flash message to advise the user whether they have permission.
Here's an example from a project. Not quite what you're looking for but may get you started:
easyadmin.yaml:
Admin:
class: App\Entity\Admin
disabled_actions: ['new', 'edit']
list:
actions:
-
name: 'admin_enabler'
type: 'route'
label: 'Enable/Disable'
controller:
/**
* #Route("/enabler", name = "admin_enabler")
*/
public function enabler(Request $request)
{
$em = $this->getDoctrine()->getManager();
$id = $request->query->get('id');
$admin = $em->getRepository(Admin::class)->find($id);
$enabled = $admin->isEnabled();
if (!$admin->isActivator() && !$admin->hasRole('ROLE_SUPER_ADMIN')) {
$admin->setEnabled(!$enabled);
$em->persist($admin);
$em->flush();
} else {
$this->addFlash('danger', $admin->getFullName() . ' cannot be disabled');
}
return $this->redirectToRoute('easyadmin', array(
'action' => 'list',
'entity' => $request->query->get('entity'),
));
}

No Entity Manager in Custom Class and ContextErrorException

I'm trying to create custom Form in Sonata-Admin and I want to get data from database to choices box.
When I'm trying to get data via getEntityManager() I got error
No entity manager defined for class \Admin\AdminBundle\Entity\Category
I tried to add entity manager to first argument in service.yml [code below]
services:
sonata.admin.category:
class: Admin\AdminBundle\Admin\Category
tags:
- {name: sonata.admin, manager_type: orm, group: "Content", label: "Kategoria"}
arguments:
- #doctrine.orm.default_entity_manager
- Admin\AdminBundle\Entity\Category
- ~
calls:
- [ setTranslationDomain, [AdminAdminBundle]]
After i Add default entity manager I'm having error:
ContextErrorException in RoutesCache.php line 47:
Warning: md5() expects parameter 1 to be string, object given
I'm also adding my ConfigureFormFields() function:
protected function configureFormFields(FormMapper $formMapper){
$em = $this->modelManager->getEntityManager('\Admin\AdminBundle\Entity\Category');
$query = $em->createQueryBuilder('c')
->select('c')
->from('AdminBundle:Category', 'c')
->where('c.parent IS NOT NULL')
->orderBy('c.root, c.lft', 'ASC');
$formMapper
->add ('name', 'text', array('label' => 'Nazwa Kategorii'))
->add ('alias', 'text', array('label' => 'Alias'))
->add('parent_id', 'sonata_type_model', array(
'required' => true,
'query' => $query
));
Can somebody help me fix that error ?
Thanks for answers,
best regards !
You get error because add manager in wrong place.
First argument of admin service should be set as
the admin service’s code (defaults to the service’s name).
Admin class pharse this string and build some logic based on. You put there manager so you get error.
If you want to add something to your admin class you can simply add as fourth argument (or fifth, sixth ....) like:
services:
sonata.admin.category:
class: Admin\AdminBundle\Admin\Category
tags:
- {name: sonata.admin, manager_type: orm, group: "Content", label: "Kategoria"}
arguments:
- ~
- Admin\AdminBundle\Entity\Category
- ~
- #doctrine.orm.default_entity_manager
calls:
- [ setTranslationDomain, [AdminAdminBundle]]
And then in your admin class you have to update override constructor, like :
public function __construct($code, $class, $baseControllerName, $yourManager)
{
parent::_construct($code, $class, $baseControllerName);
$this->yourManager = $yourManager
}

how to include an entity join in sonata bundle admin list view

related code:
in services.yml
sonata.admin.domain:
class: MyBundle\AdminBundle\Admin\MyAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "Domains", label: "Domains" }
arguments:
- ~
- MyBundle\ServiceBundle\Entity\MyEntity
- ~
calls:
- [ setTranslationDomain, [MyOtherBundle]]
in my admin controller:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('domain')
->add('user.email')
->add('_action', 'actions', array(
'actions' => array(
'show' => array())));
}
which errors in:
Notice: Undefined index: user
to describe the problem further, i have a table that has a user_id column, and i want to be able to include the users email address (using fos user bundle) in that same list with that table. i've tried custom query with no luck also. thanks ahead of time
here is official documentation about list view definition :
http://sonata-project.org/bundles/admin/master/doc/reference/action_list.html
and
http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/list_field_definition.html
if you have a user_id within you entity, i guess your entity is an override of fosUserBundle, right ?
so normally you directly access from the list field definition like this :
->add('user.email') // user is you entity object
otherwise if it s a standalone entity with a user_id, you might have a relationship between this entity and the entity which owns your fosuserbundle object, and like in the above list field definition , you should normally access the object email.

Resources