findAll gives no output for a ManyToMany [duplicate] - symfony

This question already has answers here:
What is the difference between fetch="EAGER" and fetch="LAZY" in doctrine
(2 answers)
Closed 1 year ago.
I recently started using Symfony and I don't understand why statuses(ManyToMany) don't give any output on a findAll query.
I need there the last/current value that was entered in the database.
App\Entity\Service {#752 ▼
-id: 5
-name: "Helpdesk"
-description: null
-url: null
-serviceGroup: App\Entity\ServiceGroup {#728 ▼
-id: 2
-name: "Webserver 2"
-description: null
-services: Doctrine\ORM\PersistentCollection {#729 ▶}
-order_id: 2
}
-order_id: 3
-statuses: Doctrine\ORM\PersistentCollection {#753 ▼
-snapshot: []
-owner: App\Entity\Service {#752}
-association: array:16 [ …16]
-em: Doctrine\ORM\EntityManager {#383 …11}
-backRefFieldName: "services"
-typeClass: Doctrine\ORM\Mapping\ClassMetadata {#675 …}
-isDirty: false
#collection: Doctrine\Common\Collections\ArrayCollection {#754 ▶}
#initialized: false
}
}
//Edit
for easyadmin I have already added a function in the Entity/Service.php, can't I just use this for the twig tempalte?
public function getLastStatus()
{
return $this->getStatuses()->last();
}

You should try to modify your class Service in your property "statuses" inside #ORM\ManyToMany() by adding : fetch="EAGER" (it should give the all object and not just the proxy).
Or you can also create a function findStatuses(Service $service) in your ServiceRepository that get all the statuses using the query builder. You will find exemples of it in your ServiceRepository.

Related

Is there a way to get allowed roles for a given URL?

I have some rules in security.yml that basically tell symfony which roles should be alowed to access some route/url.
Is there a way to determine in the code for a given request which roles are allowed?
I am intending to use this in an event listener.
You can use AccessMap from use Symfony\Component\Security\Http\AccessMapInterface;
AccessMap contain the mapping of your access_control configuration.
You can auto wire the service easily in your listener:
private AccessMapInterface $accessMap;
public function __construct(AccessMapInterface $accessMap)
{
$this->accessMap = $accessMap;
}
Don't forget to register the service :
#services.yaml
services:
#...
Symfony\Component\Security\Http\AccessMapInterface: '#security.access_map'
Then you can use AccessMap to match your request using the method $this->accessMap->getPatterns($request) and access each configuration.
Example from one of my projet:
Symfony\Component\Security\Http\AccessMap {#8567 ▼
-map: array:7 [▼
0 => array:3 [▼
0 => Symfony\Component\HttpFoundation\RequestMatcher {#8547 ▼
-path: "^/login"
-host: null
-port: null
-methods: []
-ips: []
-attributes: []
-schemes: []
}
1 => array:1 [▼
0 => "PUBLIC_ACCESS"
]
2 => null
]
1 => array:3 [▶]
2 => array:3 [▶]
3 => array:3 [▶]
4 => array:3 [▶]
5 => array:3 [▶]
6 => array:3 [▶]
]
}
Let's try to see what role is required in my login page:
//$request is from my login page
dump($this->accessMap->getPatterns($request));
array:2 [▼
0 => array:1 [▼
0 => "PUBLIC_ACCESS"
]
1 => null
]
So it should be easy to match your request in your listener, and use the result of getPatterns which contains the required roles for your request.
If you want to access a specific route configuration that is not your current request, you could do something like:
$this->accessMap->getPatterns(Request::create('/login', 'GET'));

AclVoter denies access to 'LIST'

As soon as I set sonata_admin.security.handler to sonata.admin.security.handler.acl the only user who has access is the one with ROLE_SUPER_ADMIN.
I think I configured everything right, obviously not.
I tried:
to give the user the real role ROLE_VIP_CONTACT_ADMIN instead of assigning by a fos_group, no success.
all options forsecurity.access_decision_manager.strategy: affirmative, consensus and unanimous
to delete all acl tables, acl:init, sonata:admin:setup-acl, with and without sonata:admin:generate-object-acl and cleared the cache every time.
With no success.
# Acme\MyBundle\Controller\CRUDController.php
$securityContext->getAdminPermissions();
# -> ["CREATE", "LIST", "DELETE", "UNDELETE", "EXPORT", "OPERATOR", "MASTER"]
dump($this->admin->getSecurityInformation());
/* -> array:3 [▼
"GUEST" => array:2 [▼
0 => "VIEW"
1 => "LIST"
]
"STAFF" => array:3 [▼
0 => "EDIT"
1 => "LIST"
2 => "CREATE"
]
"ADMIN" => array:3 [▼
0 => "MASTER"
1 => "OPERATOR"
2 => "EXPORT"
]
] */
dump($this->getUser()->getRoles());
/* -> array:15 [▼
0 => "ROLE_ADMIN"
1 => "ROLE_VIP_CONTACT_GUEST"
2 => "ROLE_VIP_CONTACT_STAFF"
3 => "ROLE_VIP_CONTACT_ADMIN" # <--- I gave him everything!
[...]
9 => "ROLE_ALLOWED_TO_SWITCH"
[...]
16 => "ROLE_USER"
] */
Now I open my browser and go to app_dev.php/my-path-to/vip/contact/list, resulting in an AccessDeniedException.
/edit: It's the same problem as here ACL + SonataAdminBundle + SonataUserBundle.
On Symphony >3.1 you should use this:
services:
security.acl.permission.map:
class: Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap
instead
parameters:
security.acl.permission.map.class: Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap
After hours of debugging, the result is to let ACL know about the LIST permission by using Sonata's AdminPermissionMap.
See SonataAdminBundle 5. Security and Documentation » Admin (Ctrl+F: security.acl.permission.map.class)
parameters:
security.acl.permission.map.class: Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap
You might already know this.
To make a long story short: Configuration is not only done by writing some config files, but also to import the right ones.

Accessing nested parameters in Symfony ParameterBag

Have a request that looks like this
ParameterBag {#362 ▼
#parameters: array:1 [▼
"form" => array:5 [▼
"titre" => "new b"
"prix" => "4444"
"slug" => "with-different-slug"
"publier" => "unpub"
"Modifier" => ""
]
]
}
How can I use the
$post = Request::createFromGlobals();
$post->request->has() on those nested properties?
ParameterBag's has function does not support deep check. It is just an array_key_exists call.
You could use get with $deep parameter set to true.
E.g.:
$post = Request::createFromGlobals();
$post->request->get('form[titre]', null, true);
It will return null (the second parameter), if the value does not exist.
EDIT:
This function however deprecated in 2.8.
Using paths to find deeper items in get is deprecated since version 2.8 and will be removed in 3.0. Filter the returned value in your own code instead.

isGranted returns FALSE with User extending FOSUserBundle

For the simplicity of the problem I am not using role_hierarchy on my security.yml.
I have a logged user. If I do this on my controller:
dump($this->get('security.token_storage')->getToken()->getUser()->getRoles());
This is what I get:
array:3 [▼
0 => "ROLE_SUPER_ADMIN"
1 => "ROLE_ADMIN"
2 => "ROLE_USER"
]
But then if I ask for isGranted, I just get true on 'ROLE_USER', and false with all the rest:
dump($this->get('security.authorization_checker')->isGranted('ROLE_USER'));
dump($this->get('security.authorization_checker')->isGranted('ROLE_ADMIN'));
dump($this->get('security.authorization_checker')->isGranted('ROLE_SUPER_ADMIN'));
gives me:
true
false
false
I am using FOSUserBundle and my user extends their BaseUser (which on turn implements UserInterface) and I am not touching any method of it on my User entity.
Can you spot the problem? Is that I can not use the security.checker with FOSUSerBundle?
UPDATE:
If I dump($this->getUser()) this is what I get:
Usuario {#2290 ▼
#id: 3
#username: "u1"
#usernameCanonical: "u1"
#email: "u1"
#emailCanonical: "u1"
#enabled: true
#salt: "8wqvgv5t24g0ssck44gw4008c04g8sg"
#password: "zfDmozi78wrglXx3SUaCiz7490o4ZzKYEukcbdlCQ5FAWpA4jgLFQT6BXNbo3tzTyhdPDOCC/h4ZDs32SKlGEw=="
#plainPassword: null
#lastLogin: DateTime {#2288 ▶}
#confirmationToken: null
#passwordRequestedAt: null
#groups: null
#locked: false
#expired: false
#expiresAt: null
#roles: array:2 [▼
0 => "ROLE_SUPER_ADMIN"
1 => "ROLE_ADMIN"
]
#credentialsExpired: false
#credentialsExpireAt: null
}
As you can see, FSOS just add the 'ROLE_USER' in getRoles() method since it is not present in the actual array of Roles.
Logging out and back in again will resolve the issue.

Twig rendering of a mapped objects

I am spinning my wheel to render an object in a twig template. I have 3 entities user >> customer >> account each one mapped to the next with a bi-directionnal one-to-many relationship. I want to fetch all accounts for a specific customer using this controller
//...
public function showAction($customerref)
{
$customer=$this->getDoctrine()->getRepository('AcmeCustomerBundle:Customer')
->find($customerref);
$accounts = $customer->getAccounts();
return $this->render('mytemplate.html.twig', array('accounts'=>$accounts));
}
I try to retrieve the information related to the "accounts" object in twig using
{% for account in accounts %}
{{ account.id }}
{{ account.number}}
{% endfor %}
I get the error "Notice: undefined index:customer". I cannot make sense of this error. When does the "customer" index need to be defined? This is what I have when I dump the "accounts" object.
PersistentCollection {#1061 ▼
-snapshot: []
-owner: Customer {#1060 ▼
-id: 11
-name: "nameofthecustomer"
+user: User {#947 ▼
-id: 1
-username: "tom"
#customers: PersistentCollection {#968 ▶}
}
#accounts: PersistentCollection {#1061}
}
-association: array:15 [ …15]
-em: EntityManager {#151 …10}
-backRefFieldName: "customer"
-typeClass: ClassMetadata {#948 …}
-isDirty: false
-initialized: false
-coll: ArrayCollection {#1062 ▼
-_elements: []
}
}
Could anyone give me some guidance on why I get this error? I have used a similar code many times (e.g. to display all customer for one specific user and it worked perfectly well)? Thanks.
I left some typos indeed (i just corrected them). I happen to have found the solution. I had issues with the way my entities were mapped. This is where I found some useful tips http://obtao.com/blog/symfony2-issues-you-do-not-understand/

Resources