I'm trying to create a new tempate in my project in symfony to put a climbing converter. But it doesn't work. I have the error:
App\Entity\Site object not found by the #ParamConverter annotation
I put the function in the entity "site" as following :
/**
* #Route("/site")
*/
class SiteController extends AbstractController
{
public function upload( KernelInterface $kernel): Response
{
$imagesDir = $kernel->getProjectDir().'/public/uploads'; // équivalent à $this->getParameter('images_directory')
dump($imagesDir) ;
return $this->render('site/show.html.twig');
}
/**
* #Route("/", name="site_index", methods={"GET"})
*/
public function index(SiteRepository $siteRepository): Response
{
return $this->render('site/index.html.twig', [
'sites' => $siteRepository->findAll(),
]);
}
/**
* #Route("/new", name="site_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$site = new Site();
$form = $this->createForm(SiteType::class, $site);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
//on recupère les medias transmises
$media = $form->get('site')->getData();
//on boucle sur les medias
foreach($media as $medi){
//on génère un nouveau nom de fichier
$fichier = md5(uniqid()) . '.' . $medi->guessExtension();
//on copie le fichier dans le dossier img
$medi->move(
$this->getParameter('images_directory'),
$fichier
);
//on stocke l'image dans la bdd
$img = new Media();
$img->setNom($fichier);
$site->addMedium($img);
}
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($site);
$entityManager->flush();
return $this->redirectToRoute('site_index');
}
return $this->render('site/new.html.twig', [
'site' => $site,
'form' => $form->createView(),
]);
}
/**
* #Route("/{id}", name="site_show", methods={"GET"})
*/
public function show(Site $site, MediaRepository $mediarepository, $id): Response
{
$media = $mediarepository->findBy(
['site'=>$id]
);
return $this->render('site/show.html.twig', [
'site' => $site,
'media' => $media,
]);
}
/**
* #Route("/{id}/edit", name="site_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Site $site): Response
{
$form = $this->createForm(SiteType::class, $site);//j'appelle le form
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
//on recupère les medias transmises
$media = $form->get('site')->getData();
//on boucle sur les medias
foreach($media as $medi){
//on génère un nouveau nom de fichier
$fichier = md5(uniqid()) . '.' . $medi->guessExtension();
//on copie le fichier dans le dossier img
$medi->move(
$this->getParameter('images_directory'),
$fichier
);
//on stocke l'image dans la bdd
$img = new Media();
$img->setNom($fichier);
$site->addMedium($img);
}
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('site_index');
}
return $this->render('site/edit.html.twig', [
'site' => $site,
'form' => $form->createView(),
]);
}
/**
* #Route("/{id}", name="site_delete", methods={"POST"})
*/
public function delete(Request $request, Site $site): Response
{
if ($this->isCsrfTokenValid('delete'.$site->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($site);
$entityManager->flush();
}
return $this->redirectToRoute('site_index');
}
/**
* #Route("/conv", name="site_converter")
*/
public function converter():Response
{
return $this->render('site/converter.html.twig');
}
}
I checked others answers about this problem, but I still can't find out the solution. Do you have any ideas?
I put some more code so that it would be easier to understand. I hope this would be usefull. It's the route for converter that makes me problem. Thanks
This happens because you have a route called /conv, you should declare it before declaring /{id} route, instead Symfony searches for a Site object with id: conv which is not found.
Move converter route and method declaration before your show route and method declaration.
Related
hello I have two entity Patient and Appointement I work with Api platform and the relation between Appointement and Patient is ManyToOne when I try to get Appointement I get only the id of patient not the whole objet
My function get
/**
* #Route("/appointement", methods={"GET"})
*/
public function findAppointement(AppointementRepository $appointementRepository,SerializerInterface $serializer)
{
//AVOIR AU MOINS LE ROLE_SECRETAIRE POUR RECUPERER LES APPOINTEMENT
$this->denyAccessUnlessGranted('ROLE_SECRETAIRE',null,"Accès non autorisé");
$appointement= $appointementRepository->findAll();
$data=$serializer->serialize($appointement,"json", [
'circular_reference_handler' => function ($object) {
return $object->getId();
}
]);
return new JsonResponse($data,Response::HTTP_OK,[],true);
}
My Patient entity
/**
* #ORM\OneToMany(targetEntity="App\Entity\Appointement", mappedBy="patient")
*/
private $appointements;
/**
* #ORM\OneToMany(targetEntity="App\Entity\PatientData", mappedBy="patient")
*/
private $patientData;
public function __construct()
{
$this->appointements = new ArrayCollection();
$this->patientData = new ArrayCollection();
}
My Appointement entity
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Patient", inversedBy="appointements")
* #ORM\JoinColumn(nullable=false)
*/
private $patient;
thank you
You are only getting the id because you defined your circular_reference_handler to only get the id. You can modify it and get more information from your patient.
$data=$serializer->serialize($appointement,"json", [
'circular_reference_handler' => function ($object) {
if($object instanceof Patient){
return ['value1' => $object->getValue1(), 'value2' => $object->getValue2()]
}
return $object->getId();
}
]);
I have a problem on symfony 3.
I'm trying to manage my roles from a page I created.
The role system I use is the same as the one used by FOSUserBundle.
/**
* #ORM\Column(type="array")
*/
protected $roles = [];
/**
* Constructor
*/
public function __construct()
{
$this->setIsActif(true);
$this->roles = array();
}
/**
* {#inheritdoc}
*/
public function addRole($role)
{
$role = strtoupper($role);
if ($role === ['ROLE_USER']) {
return $this;
}
if (!in_array($role, $this->roles, true)) {
$this->roles[] = $role;
}
return $this;
}
/**
* {#inheritdoc}
* #return array
*/
public function getRoles()
{
return array_unique(array_merge(['ROLE_USER'], $this->roles));
}
/**
* Vérifie si l'utilisateur possède le rôle passé en paramètre
* {#inheritdoc}
*
* #param string
* #return bool
*/
public function hasRole($role)
{
return in_array(strtoupper($role), $this->getRoles(), true);
}
/**
* Supprimer un rôle
* {#inheritdoc}
*
* #return UserCas
*/
public function removeRole($role)
{
if (false !== $key = array_search(strtoupper($role), $this->roles, true)) {
unset($this->roles[$key]);
$this->roles = array_values($this->roles);
}
return $this;
}
/**
* Set roles
* {#inheritdoc}
*
* #return UserCas
*/
public function setRoles(array $roles)
{
$this->roles = array();
foreach ($roles as $role) {
$this->addRole($role);
}
return $this;
}
/**
* Réinitialise les rôles de l'utilisateur
*/
public function resetRoles()
{
$this->roles = [];
}
When I was in a "PREPROD" environment, everything was working, my roles were changing well. But since I switched to "PROD", when my user does not have a role (so it is automatically ROLE_USER), well 9 times out of 10, I can not assign any other role. But if he has a role other than ROLE_USER, then I can assign him any role. Why does not it work in preprod? I do not know...
On twig, I have my list of users with a list option where I choose the new role. Then it updates the page. My request retrieves the label of the new role and is assigned
Twig:
<form action="{{path('user_role_change', {'username': unUser.username })}}" method="POST">
<select id="role" name="role" onChange="this.form.submit();">
{% for unRole in listeRoles %}
<option value="{{unRole}}" {% if unRole == 'User' %} selected {% endif %}>{{unRole}}</option>
{% endfor %}
</select>
</form>
Controller:
/**
* Change le rôle d'un utilisateur lorsque l'on change l'option dans l'option list des rôles d'un utilisateur
*
* #Route("/changeRole/{username}", name="user_role_change")
* #Method("GET")
*/
public function changeRoleAction(Request $request, $username)
{
$em = $this->getDoctrine()->getManager();
$idRole=$request->get('role');
$user = $em->getRepository('PagesBundle:UserCas')->findOneByUsername($username); // On cherche si c'est un UserCas (user académique)
if($user == null)
{
$user = $em->getRepository('PagesBundle:User')->findOneByUsername($username); // On cherche si c'est un User externe
$nouveauRole = $this->getNouveauRole($idRole);
$user->setRoles($nouveauRole);
$em->persist($user);
$em->flush();
return $this->redirectToRoute('roles_index'); //redirection vers la page de gestion des Informations
}
/**
* Méthode inverse de $this->switchRole()
* Elle renvoi le rôle en type array de sorte à ce qu'elle soit injectable dans l'attribut roles de l'utilisateur ( ex: "Admin" => "ROLE_ADMIN")
*
* #param int $nomRole
* #return array
*/
public function getNouveauRole($nomRole)
{
switch($nomRole)
{
case "Admin":
$role = ['ROLE_ADMIN'];
break;
case "Packages":
$role = ['ROLE_PACKAGES'];
break;
case "Infos":
$role = ['ROLE_INFOS'];
break;
default:
$role = [];
break;
}
return $role;
}
Can someone help me please ?
Try to fix your addRole() method like the following:
/**
* {#inheritdoc}
*/
public function addRole($role)
{
$role = strtoupper($role);
if ($role === 'ROLE_USER') {
return $this;
}
if (!in_array($role, $this->roles, true)) {
$this->roles[] = $role;
}
return $this;
}
I'm using Symfony workflow on my project. I can pass the first transition and see that the next transitions are enabled with $workflow->getEnabledTransitions($entity);. When passing to another route which introduce the next transition (part of the enabled transitions) it seems that the workflow has initialized back itself when checking the enabled transitions.
Here is my workflow.yaml configuration file :
framework:
workflows:
produit_selection:
type: 'workflow' # or 'state_machine'
audit_trail:
enabled: true
marking_store:
type: 'single_state'
arguments:
- 'currentPlace'
supports:
- App\Entity\Produit
initial_place: initiale
places:
- initiale
- commande
- selectionne
- invalide_selection
transitions:
commander:
from: initiale
to: commande
selectionner:
from: commande
to: selectionne
invalider_selection:
from: commande
to: invalide_selection
Here is my commandeProduit controller action :
/**
* #Route("/produit/commande/{id<\d+>}", name="produit_commande")
* #param Request $request
* #param $id
* #param ProduitRequestCommandeUpdateHandler $updateHandler
* #return \Symfony\Component\HttpFoundation\Response
* #Security("has_role('ROLE_MARKETING')")
*/
public function commandeProduit(
Request $request,
$id,
ProduitRequestCommandeUpdateHandler $updateHandler,
Registry $workflows
) {
$repository = $this->getDoctrine()->getRepository(Produit::class);
/** #var Produit $produit */
$produit = $repository->find($id);
$produitRequest = ProduitRequest::createFromProduit($produit);
$form = $this->createForm(ProduitCommandeType::class, $produitRequest)->handleRequest($request);
$box = $produit->getBox();
if ($form->isSubmitted() AND $form->isValid()) {
$produit = $updateHandler->handle($produitRequest, $produit, $box);
if (null === $produit) {
$this->addFlash(
'error',
"La commande a été annulée car elle dépasse le budget."
);
} elseif ($produit->getCommande()) {
$workflow = $workflows->get($produit, 'produit_selection');
//$workflow->getMarking($produit);
if ($workflow->can($produit, 'commander')) {
try {
$workflow->apply($produit, 'commander');
} catch (TransitionException $exception) {
// ... if the transition is not allowed
}
}
$transitions = $workflow->getEnabledTransitions($produit);
/** #var Transition $transition */
foreach($transitions as $transition) {
$this->addFlash(
'error',
$transition->getName()
);
}
$this->addFlash(
'notice',
"La commande du produit a bien été prise en compte avec la quantité " . $produit->getQuantite() . "."
);
} else {
$this->addFlash(
'warning',
"Le produit n'est pas disponible."
);
}
return $this->redirectToRoute("produits_commande");
}
$fournisseur = $produit->getFournisseur();
return $this->render('produits/commande_produit.html.twig', [
'box' => $box,
'fournisseur' => $fournisseur,
'form' => $form->createView()
]);
}
And here is my selectionProduit controller action :
/**
* #Route("/produit/selection/{id<\d+>}", name="produit_selection")
* #param Request $request
* #param $id
* #param ProduitRequestUpdateHandler $updateHandler
* #param Registry $workflows
* #return \Symfony\Component\HttpFoundation\Response
* #Security("has_role('ROLE_MARKETING')")
*/
public function selectionProduit(
Request $request,
$id,
ProduitRequestUpdateHandler $updateHandler,
Registry $workflows
) {
$repository = $this->getDoctrine()->getRepository(Produit::class);
/** #var Produit $produit */
$produit = $repository->find($id);
$produitRequest = ProduitRequest::createFromProduit($produit);
$form = $this->createForm(ProduitSelectionType::class, $produitRequest)->handleRequest($request);
if($form->isSubmitted() AND $form->isValid()) {
$produit = $updateHandler->handle($produitRequest, $produit);
if ($produit->getSelectionne()) {
$workflow = $workflows->get($produit, 'produit_selection');
//$workflow->getMarking($produit);
$workflow->can($produit, 'selectionner');
try {
$workflow->apply($produit, 'selectionner');
} catch (TransitionException $exception) {
// ... if the transition is not allowed
}
$transitions = $workflow->getEnabledTransitions($produit);
/** #var Transition $transition */
foreach($transitions as $transition) {
$this->addFlash(
'error',
$transition->getName()
);
}
$this->addFlash(
'notice',
"Le produit a bien été sélectionné avec la quantité " . $produit->getQuantite() . ".");
} else {
$workflow = $workflows->get($produit, 'produit_selection');
//$workflow->getMarking($produit);
if ($workflow->can($produit, 'invalider_selection')) {
try {
$workflow->apply($produit, 'invalider_selection');
} catch (TransitionException $exception) {
// ... if the transition is not allowed
}
}
$transitions = $workflow->getEnabledTransitions($produit);
$this->addFlash(
'warning',
"Le produit n'a pas été sélectionné.");
}
return $this->redirectToRoute("produits_selection");
}
$box = $produit->getBox();
$fournisseur = $produit->getFournisseur();
return $this->render('produits/selection_produit.html.twig', [
'box' => $box,
'fournisseur' => $fournisseur,
'form' => $form->createView()
]);
}
Why the workflow doesn't transit to the next place after changing route ? How to fix that ? Thanks for help.
I found it. We have to flush the entity to store the current place :
$workflow->apply($produit, 'selectionner');
$this->getDoctrine()->getManager()->flush();
And in the entity we have a field defined like this :
/**
* #ORM\Column(type="string", length=100)
*/
public $currentPlace;
On symfony 4.1
if I copy/paste http://mysite/sdff453212f/newPassword/{code} in my browser it shows a Flash Message as expected.
but if I send this url by mail (or copy in word document...) and I Click the link it doesn't show any flash message ( but if intercept_redirects: true, it's work...)
Do you have any ideas?
my controller:
/**
* #Route("/newPassword/{code}", name="newPassword")
*/
public function newPassword(Request $request, UserPasswordEncoderInterface $encoder, $code)
{
//....
$this->addFlash('error', 'Le code n\'existe pas ou n\'est plus valable');
return $this->redirectToRoute('security_forgot_Password');
}
/**
* #Route("forgotPassword", name="security_forgot_Password")
*/
public function forgotPassword(Request $request, UtilityManager $utility, MailManager $mailManager)
{
$form = $this->createForm(ForgotPasswordType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
//.....
}
return $this->render('security/forgotPassword.html.twig', array(
'form' => $form->createView()
));
}
I have a problem with the typical form to change the password in which I first put you to put your current password.
The theory is very simple and is explained in the symfony doc but it gives me an error like the current password is incorrect
My Model:
namespace BackendBundle\Form\Model;
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;
class ChangePassword
{
/**
* #SecurityAssert\UserPassword(
* message = "Error al poner la contraseña actual"
* )
*/
protected $oldPassword;
/**
* #Assert\Length(
* min = 6,
* minMessage = "El password tiene que tener al menos 6 caracteres"
* )
*/
protected $password;
/////
public function getOldPassword() {
return $this->oldPassword;
}
public function setOldPassword($oldPassword) {
$this->oldPassword = $oldPassword;
}
/////
public function getPassword() {
return $this->oldPassword;
}
public function setPassword($oldPassword) {
$this->oldPassword = $oldPassword;
}
}
The fomType:
->add('oldPassword', PasswordType::class, array(
'label' => 'Ponga su password actual',
'mapped' => false,
))
->add('password', RepeatedType::class, array(
"required" => "required",
'type' => PasswordType::class,
'invalid_message' => 'Los dos password deben coincidir',
'first_options' => array('label' => 'Password nuevo', "attr"
=> array("class" => "form-password form-control")),
'second_options' => array('label' => 'Repita el Password nuevo', "attr" => array("class" => "form-password form-control"))
)
)
And little else must be done (I think) in addition to the controler create the view with the form and then collect the data of the new password, etc, but as I say, I sent error of not valid field that checks the password and I do not know if it's because the password I keep it encrypted
My security.yml I have it as
encoders:
BackendBundle\Entity\Users:
algorithm: bcrypt
cost: 6
My action Controller:
public function passAction(Request $request) {
$changePasswordModel = new ChangePassword();
$form = $this->createForm(ChangePasswordType::class, $changePasswordModel);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
$password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
$user->setPassword($password);
$em->persist($user);
$flush = $em->flush();
if ($flush === null) {
$this->session->getFlashBag()->add('success', 'El usuario se ha editado correctamente');
return $this->redirectToRoute("others_show"); //redirigimos la pagina si se incluido correctamete
} else {
$this->session->getFlashBag()->add('warning', 'Error al editar el password');
}
} else {
dump($form->getErrors());
$this->session->getFlashBag()->add('warning', 'El password no se ha editado por un error en el formulario !');
}
}
return $this->render('BackendBundle:Others:editPass.html.twig', array(
'form' => $form->createView(),
));
}
It tells me that the form is not correct because the old password is incorrect. What could be wrong?
You don't need to check the validity of the old password yourself. Symfony does this for you, when you call form->isValid(). So you can drop this:
$currentPassword = $form->get("oldPassword")->getData();
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
$isValid = $encoder->isPasswordValid($user->getPassword(), $currentPassword, $user->getSalt());
$encoderService = $this->container->get('security.password_encoder');
$match = $encoderService->isPasswordValid($user, $currentPassword);
dump($match);
Instead, start your Controller like this:
public function passAction(Request $request) {
$changePasswordModel = new PasswordChange();
$form = $this->createForm(PasswordChangeType::class, $changePasswordModel);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { // will check if old password was valid
$user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
$password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
$user->setPassword($password);
// go on with saving $user to database
Thank you very much #Spunc for your help, I've finally gotten it to work correctly ;-)
I put the correct complete code in case there are other users with problems. Thanks again
passControler
namespace BackendBundle\Controller;
use BackendBundle\Entity\Users;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
class PassController extends Controller {
public function passAction(Request $request) {
$changePasswordModel = new ChangePassword();
$form = $this->createForm(ChangePasswordType::class, $changePasswordModel);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
$password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
$user->setPassword($password);
$em->persist($user);
$flush = $em->flush();
if ($flush === null) {
$this->session->getFlashBag()->add('success', 'El usuario se ha editado correctamente');
return $this->redirectToRoute("others_show"); //redirigimos la pagina si se incluido correctamete
} else {
$this->session->getFlashBag()->add('warning', 'Error al editar el password');
}
} else {
// dump($form->getErrors());
$this->session->getFlashBag()->add('warning', 'El password no se ha editado por un error en el formulario !');
}
}
return $this->render('BackendBundle:Others:editPass.html.twig', array(
'form' => $form->createView(),
));
}
}
model ChangePassword
namespace BackendBundle\Form\Model;
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;
class ChangePassword {
/**
* #SecurityAssert\UserPassword(
* message = "Error al poner la contraseña actual"
* )
*/
protected $oldPassword;
/**
* #Assert\Length(
* min = 6,
* minMessage = "El password tiene que tener al menos 6 caracteres"
* )
*/
protected $password;
public function getOldPassword() {
return $this->oldPassword;
}
public function setOldPassword($oldPassword) {
$this->oldPassword = $oldPassword;
return $this;
}
public function getPassword() {
return $this->password;
}
public function setPassword($password) {
$this->password = $password;
return $this;
}
}
ChangePasswordType
namespace BackendBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
class ChangePasswordType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('oldPassword', PasswordType::class, array(
'label' => 'Ponga su password actual',
))
->add('password', RepeatedType::class, array(
"required" => "required",
'type' => PasswordType::class,
'invalid_message' => 'Los dos password deben coincidir',
'first_options' => array('label' => 'Password nuevo', "attr" => array("class" => "form-password form-control")),
'second_options' => array('label' => 'Repita el Password nuevo', "attr" => array("class" => "form-password form-control"))
)
)
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\UserBundle\Form\Model\ChangePassword',
));
}
public function getName()
{
return 'change_passwd';
}
}
I had the same problem with the "#SecurityAssert\UserPassword" assertion. I startet in my form with
"mapped" => false
That fixed my issue. Thank's a lot. Just one remark for the future visitors of the problem. The signiture of for the password encoder has changed.
In Symfony 4.4 a setup like this will encode the new password correctly
$user->setPassword(
$passwordEncoder->encodePassword( $user,
$changePasswordModel->getPassword()
) );