Undefined method 'encodePassword'. - error in Apiplateform security encoder undefined - api

I have a problem in my symfony security api in the service PasswordService. It can't find the encoder
I can't guess what should I do.
This is my security.yaaml file:
This is my code:
<?php
namespace App\Services;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class PasswordService
{
/**
* #var PasswordService
*/
private $userPasswordEncoder;
/**
* #param UserPasswordEncoderInterface $userPasswordEncoder
*/
public function __construct(UserPasswordEncoderInterface $userPasswordEncoder)
{
$this->userPasswordEncoder = $userPasswordEncoder;
}
/**
* #param object $entity
* #param string $password
* #return string
*/
public function encode(object $entity, string $password): string
{
return $this->userPasswordEncoder->encodePassword($entity, $password);
}
/**
* #param string $password
* #return int
*/
public function formatRequirement(string $password)
{
return preg_match('#^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W)#', $password);
}
/**
* #param object $entity
* #param string $password
* #return bool
*/
public function isValid(object $entity, string $password): bool
{
return $this->userPasswordEncoder->isPasswordValid($entity, $password);
}
}

There is no real error you just have a wrong annotation here:
/**
* #var PasswordService <========
*/
private $userPasswordEncoder;
If you remove it, it should be fine. (Or replace it with UserPasswordEncoderInterface)

Related

add a new default route to Route::resource for each resource controller

I modify "controller.stub" file in stubs directory and i add a new method "details" for each resource controllers
<?php
namespace {{ namespace }};
use {{ rootNamespace }}Http\Controllers\Controller;
use Illuminate\Http\Request;
class {{ class }} extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
public function details()
{
//
}
}
but now when i use "Route::resource('foo', foo::class)" method in web.php file,
there is not any registered route for "details".
how can i modify default routes of Route::resource('foo', foo::class) for my new function in resource controller?

Avoiding getters and setters in PHP 7.4

As PHP 7.4 supports typed class properties: https://www.php.net/manual/en/migration74.new-features.php#migration74.new-features.core.typed-properties. Looks like a lot of code could be eliminated, in particular getters and setters that in entities and DTOs that was responsible for controlling properties types. For example such snippet:
class Foo implements BarInterface
{
/**
* #var int
*/
protected $id;
/**
* #var int|null
*/
protected $type;
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #param int $id
* #return $this
*/
public function setId(int $id)
{
$this->id = $id;
return $this;
}
/**
* #return int|null
*/
public function getType(): ?int
{
return $this->type;
}
/**
* #param int|null $type
* #return $this
*/
public function setType(?int $type)
{
$this->type = $type;
return $this;
}
}
Can be refactored to:
class Foo implements BarInterface
{
public int $id;
public ?int $type;
}
Am I right that this is good idea? What should I take into consideration while making such refactoring?

Symfony API with FOSRestBundle : circular reference has been detected

I'm working on a symfony project to build a rest API, I have 4 entities related to each other like that :
I've installed FOSRestBundle to build just a GET web service, when i want to get a resource for example :
http://evaluation.dev/app_dev.php/api/families
I got this error :
message: "A circular reference has been detected (configured
limit:1).",
this is my controller :
<?php
namespace API\APIBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\Annotations as Rest;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Serializer;
class CartographyController extends Controller
{
/**
* #Rest\View()
* #Rest\Get("/posts")
* #param Request $request
* #return Response
*/
public function getPostsAction(Request $request)
{
$encoder = new JsonEncoder();
$normalizer = new GetSetMethodNormalizer();
$serializer = new Serializer(array($normalizer), array($encoder));
$posts = $this->get('doctrine.orm.entity_manager')
->getRepository('EvalBundle:Post')
->findAll();
return new Response($serializer->serialize($posts, 'json'));
}
/**
* #Rest\View()
* #Rest\Get("/employments")
* #param Request $request
* #return Response
*/
public function geEmploymentAction(Request $request)
{
$encoder = new JsonEncoder();
$normalizer = new GetSetMethodNormalizer();
$serializer = new Serializer(array($normalizer), array($encoder));
$employments = $this->get('doctrine.orm.entity_manager')
->getRepository('EvalBundle:Employment')
->findAll();
return new Response($serializer->serialize($employments, 'json'));
}
/**
* #Rest\View()
* #Rest\Get("/professions")
* #param Request $request
* #return Response
*/
public function geProfessionsAction(Request $request)
{
$encoder = new JsonEncoder();
$normalizer = new GetSetMethodNormalizer();
$serializer = new Serializer(array($normalizer), array($encoder));
$professions = $this->get('doctrine.orm.entity_manager')
->getRepository('EvalBundle:Profession')
->findAll();
return new Response($serializer->serialize($professions, 'json')); }
/**
* #Rest\View()
* #Rest\Get("/families")
* #param Request $request
* #return Response
*/
public function geFamiliesAction(Request $request)
{
$encoder = new JsonEncoder();
$normalizer = new GetSetMethodNormalizer();
$serializer = new Serializer(array($normalizer), array($encoder));
$families = $this->get('doctrine.orm.entity_manager')
->getRepository('EvalBundle:Family')
->findAll();
return new Response($serializer->serialize($families, 'json'));
}
}
Family entity :
<?php
namespace EvalBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
/**
* Family
*
* #ORM\Table(name="family")
* #ORM\Entity(repositoryClass="EvalBundle\Repository\FamilyRepository")
*/
class Family
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* One Family has Many Professions.
* #ORM\OneToMany(targetEntity="Profession", mappedBy="family",orphanRemoval=true,cascade={"persist", "remove"},fetch="EAGER")
*/
protected $professions;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Family
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #return mixed
*/
public function getProfessions()
{
return $this->professions;
}
/**
* #param mixed $professions
*/
public function setProfessions($professions)
{
$this->professions = $professions;
}
public function __toString() {
return $this->name;
}
}
Profession entity :
<?php
namespace EvalBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Profession
*
* #ORM\Table(name="profession")
* #ORM\Entity(repositoryClass="EvalBundle\Repository\ProfessionRepository")
*/
class Profession
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* Many professions have One Family.
* #ORM\ManyToOne(targetEntity="Family", inversedBy="professions",cascade={"persist", "remove"})
*/
public $family;
/**
* One Profession has Many Employment.
* #ORM\OneToMany(targetEntity="Employment", mappedBy="profession",cascade={"persist", "remove"}, orphanRemoval=true,fetch="EAGER")
*/
private $employments;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Profession
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #return mixed
*/
public function getEmployments()
{
return $this->employments;
}
/**
* #param mixed $employments
*/
public function setEmployments($employments)
{
$this->employments = $employments;
}
/**
* #return mixed
*/
public function getFamily()
{
return $this->family;
}
/**
* #param mixed $family
*/
public function setFamily($family)
{
$this->family = $family;
}
public function __toString() {
return $this->name;
}
}
Post entity
<?php
namespace EvalBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Post
*
* #ORM\Table(name="post")
* #ORM\Entity(repositoryClass="EvalBundle\Repository\PostRepository")
*/
class Post
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* Many Posts have One Employment.
* #ORM\ManyToOne(targetEntity="Employment", inversedBy="posts", fetch="EAGER")
* #ORM\JoinColumn(name="employment_id", referencedColumnName="id",nullable=false)
*/
public $employment;
/**
* One Post has Many LevelRequired.
* #ORM\OneToMany(targetEntity="RequiredLevel", mappedBy="post")
*/
private $requiredLevels;
/**
* One Post has Many PostEvaluation.
* #ORM\OneToMany(targetEntity="PostEvaluation", mappedBy="post")
*/
private $postEvaluations;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Post
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #return mixed
*/
public function getEmployment()
{
return $this->employment;
}
public function getProfession(){
return $this->employment->profession;
}
public function getFamily(){
return $this->employment->profession->family;
}
/**
* #param mixed $employment
*/
public function setEmployment($employment)
{
$this->employment = $employment;
}
public function __toString() {
return $this->name;
}
}
employment entity
<?php
namespace EvalBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Employment
*
* #ORM\Table(name="employment")
* #ORM\Entity(repositoryClass="EvalBundle\Repository\EmploymentRepository")
*/
class Employment
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* Many Employments have One Profession.
* #ORM\ManyToOne(targetEntity="Profession", inversedBy="employments",fetch="EAGER")
*/
public $profession;
/**
* One Employment has Many post.
* #ORM\OneToMany(targetEntity="Post", mappedBy="employment",cascade={"persist", "remove"}, orphanRemoval=true,cascade={"persist", "remove"})
*/
private $posts;
/**
* One Employment has One Grid.
* #ORM\OneToOne(targetEntity="Grid", mappedBy="employment")
*/
private $grid;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Employment
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #return mixed
*/
public function getProfession()
{
return $this->profession;
}
/**
* #param mixed $profession
*/
public function setProfession($profession)
{
$this->profession = $profession;
}
/**
* #return mixed
*/
public function getPosts()
{
return $this->posts;
}
/**
* #param mixed $posts
*/
public function setPosts($posts)
{
$this->posts = $posts;
}
/**
* #return mixed
*/
public function getGrid()
{
return $this->grid;
}
/**
* #param mixed $grid
*/
public function setGrid($grid)
{
$this->grid = $grid;
}
public function __toString() {
return $this->name;
}
}
any solution please ?
For you example, you can avoid the CircularReference like this
$normalizer = new ObjectNormalizer();
$normalizer->setCircularReferenceLimit(1);
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getName();
});
$serializer = new Serializer(array($normalizer), array(new JsonEncoder()));
var_dump($serializer->serialize($org, 'json'));
But in your example, you don't use the FOSRestBundle for the view in your controller. The FOSRestController give you a handleView() and a view() method. Like this
class CartographyController extends FOSRestController
{
public function getPostsAction(Request $request)
{
$posts = $this->get('doctrine.orm.entity_manager')
->getRepository('EvalBundle:Post')
->findAll();
$view = $this->view($posts, 200);
return $this->handleView($view);
}
In this case, the serialiser is a service, this service is activated in config.yml :
In your app/config/config.yml
framework:
serializer: { enabled: true }
In order to avoid circularReference, you can do this.
In your app/config/services.yml
circular_reference_handler:
public: false
class: callback
factory: [AppBundle\Serializer\CircularHandlerFactory, getId]
serializer.normalizer.object:
class: Symfony\Component\Serializer\Normalizer\ObjectNormalizer
arguments: ["#serializer.mapping.class_metadata_factory", null, "#serializer.property_accessor"]
public: false
tags: [serializer.normalizer]
calls:
- method: setCircularReferenceLimit
arguments: [1]
- method: setCircularReferenceHandler
arguments: ["#circular_reference_handler"]
The factory can be like this:
namespace AppBundle\Serializer;
class CircularHandlerFactory
{
/**
* #return \Closure
*/
public static function getId()
{
return function ($object) {
return $object->getId();
};
}
}
Another idea is to use the GROUPS for the serializer. There is an annotation given by FosRestBundle :
#Rest\View(serializerGroups={"user"})
More information here:
https://symfony.com/doc/current/serializer.html#using-serialization-groups-annotations
Symfony2, FOSRestBundle. How to use group with JMSSerializerBundle?

Symfony2 User Entity change class variables

simple question but i don't know how to do it.
As an example we have User Entity for login (class below), how can i change $password to $accountPass ? Ofcourse it means that all relationships must be applied as it is $password, and all symfony2 classes must understand that variable (old) $password now is (changed to) $accountPass.
Question is about "names of variables"... Anyone know how to deal with it?
User Entity :
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity()
* #ORM\Table(name="_account")
* #UniqueEntity("username")
*/
class User implements UserInterface
{
public function __construct()
{
$this->salt = md5(uniqid(null, true));
$this->isActive = true;
}
/**
* Get roles
*
* #return string
*/
public function getRoles()
{
return array('ROLE_USER');
}
/**
*
*
* #return
*/
public function eraseCredentials()
{
}
/**
* Get equals
*
* #return boolean
*/
public function equals(UserInterface $user)
{
return $user->getUsername() == $this->getUsername();
}
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=255, unique=true)
*/
protected $username;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=255)
*/
protected $password;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255)
*/
protected $email;
/**
* #var string
*
* #ORM\Column(name="salt", type="string", length=255)
*/
protected $salt;
/**
* #var boolean
* #ORM\Column(name="isActive", type="boolean")
*/
protected $isActive;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* #param string $username
* #return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set password
*
* #param string $password
* #return User
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* #return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Set email
*
* #param string $email
* #return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set salt
*
* #param string $salt
* #return User
*/
public function setSalt($salt)
{
$this->salt = $salt;
return $this;
}
/**
* Get salt
*
* #return string
*/
public function getSalt()
{
return $this->salt;
}
/**
* Set isActive
*
* #param string $isActive
* #return User
*/
public function setIsActive($isActive)
{
$this->isActive = $isActive;
return $this;
}
/**
* Get isActive
*
* #return string
*/
public function getIsActive()
{
return $this->isActive;
}
}
Check this answer: https://stackoverflow.com/a/12147185/927636
You have to map all fields in your Entity class and name them as you want to.
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=255)
*/
protected $accountPass;
public function setPassword($password)
{
$this->accountPass = $password;
return $this;
}
/**
* Get password
*
* #return string
*/
public function getPassword()
{
return $this->accountPass;
}
It should be obvious of course that when you change the method name, that other classes have no way of knowing this!
All occurrences of the old method name should be changed to!
But I don't really see why you would this?

Synfony 2 File Uploader with Doctrine 2

I want to make a simple file uploader with Symfony 2 and Doctrine 2.
I've follow this tutorial :
http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html
and this one :
http://leny-bernard.com/fr/afficher/article/creer-un-site-facilement-en-symfony2-partie-4
Here is my Entity class :
namespace Luna\KBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File;
/**
* Luna\KBundle\Entity\Media
*
* #ORM\Entity
*/
class Media
{
/**
* #var integer $id
*/
private $id;
/**
* #var string $title
*/
private $title;
/**
* #var text $description
*/
private $description;
/**
* #var string $author
*/
private $author;
/**
* #var string $source
*/
private $source;
/**
* #Assert\File(maxSize="6000000")
*/
private $paths;
/**
* #var string $type
*/
private $type;
/**
* #var Luna\KBundle\Entity\object
*/
private $idobject;
/***********************************METHODS***********************************/
/**
* Set idobject
*
* #param Luna\KBundle\Entity\Object $idobject
*/
public function setIdobject(\Luna\KBundle\Entity\object $idobject)
{
$this->idObject = $idObject;
}
/**
* Get idObject
*
* #return Luna\KBundle\Entity\Object
*/
public function getIdObject()
{
return $this->idObject;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set description
*
* #param text $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* Get description
*
* #return text
*/
public function getDescription()
{
return $this->description;
}
/**
* Set author
*
* #param string $author
*/
public function setAuthor($author)
{
$this->author = $author;
}
/**
* Get author
*
* #return string
*/
public function getAuthor()
{
return $this->author;
}
/**
* Set source
*
* #param string $source
*/
public function setSource($source)
{
$this->source = $source;
}
/**
* Get source
*
* #return string
*/
public function getSource()
{
return $this->source;
}
/**
* Set paths
*
* #param string $paths
*/
public function setPaths($paths)
{
$this->paths = $paths;
}
/**
* Get paths
*
* #return string
*/
public function getPaths()
{
return $this->paths;
}
/**
* Set type
*
* #param string $type
*/
public function setType($type)
{
$this->type = $type;
}
/**
* Get type
*
* #return string
*/
public function getType()
{
return $this->type;
}
public function getAbsolutePath()
{
return null === $this->paths ? null : $this->getUploadRootDir().'/'.$this->paths;
}
public function getWebPath()
{
return null === $this->paths ? null : $this->getUploadDir().'/'.$this->paths;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
return 'uploads/mediaobject';
}
}
The fact is that #Assert\File(maxSize="6000000") is not working : I don't have a file uploader but just a simple texte field ?!
How can I make this works correctly ?
Regards Guys :)
EDIT : Here my Form builder
namespace Luna\KBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class MediaInit extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('title')
->add('description')
->add('author')
->add('source')
->add('paths')
->add('type')
->add('idObject')
;
}
}
And Here my twig template :
{% extends '::layout.html.twig' %}
{####################################### MEDIA INIT###########################}
{% block content %}
<h1>Creer un Media</h1>
Entrez les informations de votre media ici
<form action="{{ path('media_init') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<p>
<button type="submit">Creer</button>
</p>
</form>
{% endblock %}
When you want to upload a file you need to declare a path field & a virtual file field. So, your class needs to look like :
class Media
{
private $path;
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
}
And your form:
class MediaInit extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('file');
}
}
It seems that $builder variable in MediaInit class is not initialized properly (with "Media" type).