these are my first steps with Symfony. I try to implement a simple user management with Easyadmin Bundle in Symfony 4.4. I followed the Tutorial on symfony.com and most of it is working correctly (Sign up form, backend login, backend security, backend listing of users from database).
My Problem is the creation and updating of a user in the Easyadmin backend. When I try to create a new user, I see the correct fields, I do enter some data and if I click "Save changes" it throws the following error:
An exception occurred while executing 'INSERT INTO app_users (username, email, roles, password, is_active) VALUES (?, ?, ?, ?, ?)' with params ["testname", "test@example.com", "a:1:{i:0;s:9:\"ROLE_USER\";}", null, 1]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'password' cannot be null
Column 'password' cannot be null is pretty clear: I need to provide it with some encoded password string.
I think the data in the plain password field I enter is not encoded and/or not processed by the setPassword() method in my User entity.
As far as I understand some SO answers and the Symfony documentation it should work automagically!? I don't know. I tried to create an AdminController that extends EasyAdminController and hook it in somewhere in the persisting of the user entity, but I couldn't get it to work. (Something like this: https://stackoverflow.com/a/54749433)
How do I process/encode the plainpassword that it is saved to the password field in database?
User entity:
// /src/Entity/User.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
/**
* @ORM\Table(name="app_users")
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
* @UniqueEntity("username")
* @UniqueEntity("email")
*/
class User implements AdvancedUserInterface, \Serializable
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=254, unique=true)
* @Assert\NotBlank(groups={"edit"})
*/
private $username;
/**
* @ORM\Column(type="string", length=254, unique=true)
* @Assert\NotBlank()
* @Assert\Email(groups={"edit"})
*/
private $email;
/**
* @ORM\Column(type="array")
*/
private $roles;
/**
* @Assert\Length(max=4096)
*/
private $plainPassword;
/**
* @ORM\Column(type="string", length=64)
*/
private $password;
/**
* @ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
public function __construct(){
$this->roles = array('ROLE_USER');
$this->isActive = true;
}
public function getId(){
return $this->id;
}
public function getUsername(){
return $this->username;
}
public function setUsername($username){
$this->username = $username;
}
public function getEmail(){
return $this->email;
}
public function setEmail($email){
$this->email = $email;
}
public function getIsActive(){
return $this->isActive;
}
public function setIsActive($is_active){
$this->isActive = $is_active;
}
public function getRoles(){
return $this->roles;
}
public function setRoles($roles){
$roles[] = 'ROLE_USER';
$this->roles = $roles;
}
public function getPlainPassword(){
return $this->plainPassword;
}
public function setPlainPassword($password){
$this->plainPassword = $password;
}
public function getPassword()
{
return $this->password;
}
public function setPassword($password){
$this->password = $password;
}
public function getSalt(){
return null;
}
public function eraseCredentials(){}
public function isAccountNonExpired(){
return true;
}
public function isAccountNonLocked(){
return true;
}
public function isCredentialsNonExpired(){
return true;
}
public function isEnabled(){
return $this->isActive;
}
/** @see \Serializable::serialize() */
public function serialize(){
return serialize(array(
$this->id,
$this->username,
$this->email,
$this->password,
$this->isActive,
));
}
/** @see \Serializable::unserialize() */
public function unserialize($serialized){
list (
$this->id,
$this->username,
$this->email,
$this->password,
$this->isActive,
) = unserialize($serialized, array('allowed_classes' => false));
}
}
Security.yaml:
# /config/packages/security.yaml
security:
encoders:
App\Entity\User:
algorithm: bcrypt
providers:
users_in_memory: { memory: null }
our_db_provider:
entity:
class: App\Entity\User
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
pattern: ^/
provider: our_db_provider
form_login:
login_path: login
check_path: login
default_target_path: account
always_use_default_target_path: true
csrf_token_generator: security.csrf.token_manager
logout:
path: /logout
target: /login
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/account, roles: ROLE_USER }
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Easyadmin.yaml:
# /config/packages/easy_admin.yaml
easy_admin:
design:
menu:
- { entity: User, label: 'Benutzerverwaltung', icon: 'user' }
entities:
User:
class: App\Entity\User
label: 'Benutzer'
password_encoding: { algorithm: 'bcrypt', cost: 12 }
form:
form_options: { validation_groups: ['Default'] }
fields:
- { type: 'group', icon: 'address-card', label: 'Informationen', css_class: 'col-lg-6' }
- username
- email
- { type: 'group', icon: 'user-shield', label: 'Rechteverwaltung', css_class: 'col-lg-6' }
- { property: 'is_active', type: 'checkbox' }
- { property: 'roles', type: 'choice', type_options: { multiple: true, choices: { 'ROLE_USER': 'ROLE_USER', 'ROLE_ADMIN': 'ROLE_ADMIN' } } }
- { type: 'group', icon: 'user-lock', label: 'Passwort', css_class: 'col-lg-6' }
- { property: 'plainPassword', type: 'text', type_options: { required: false } }