Related
I have made login form with Security Guide. When I try to login I have logs like below:
2019-06-10 10:16:56] security.INFO: User has been authenticated successfully. {"username":"user#example.com"} []
[2019-06-10 10:16:56] security.DEBUG: Stored the security token in the session. {"key":"_security_main"} []
[2019-06-10 10:16:56] request.INFO: Matched route "app_user_dashboard". {"route":"app_user_dashboard","route_parameters":{"_route":"app_user_dashboard","_controller":"App\\Controller\\User\\UserController::dashboard"},"request_uri":"https://127.0.0.1:8001/app/dashboard","method":"GET"} []
[2019-06-10 10:16:56] security.DEBUG: Read existing security token from the session. {"key":"_security_main","token_class":"Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken"} []
[2019-06-10 10:16:57] doctrine.DEBUG: SELECT t0.id AS id_1, t0.password AS password_2, t0.email AS email_3, t0.first_name AS first_name_4, t0.last_name AS last_name_5, t0.username AS username_6, t0.referral_code AS referral_code_7, t0.referred_by_code AS referred_by_code_8, t0.roles AS roles_9, t0.active_to AS active_to_10, t0.created_at AS created_at_11, t0.updated_at AS updated_at_12 FROM users t0 WHERE t0.id = ? [15] []
[2019-06-10 10:16:57] security.DEBUG: Cannot refresh token because user has changed. {"username":"user#example.com","provider":"Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider"} []
[2019-06-10 10:16:57] security.DEBUG: Token was deauthenticated after trying to refresh it. [] []
and also I use EquatableInterface. My User.php code:
namespace App\Entity\User;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Exception;
use Serializable;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Class User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="App\Repository\User\UserRepository")
* #ORM\HasLifecycleCallbacks
*
* #ORM\Entity
* #UniqueEntity(fields="username", message="username taken")
* #UniqueEntity(fields="email", message="email taken")
*/
class User implements UserInterface, Serializable, EquatableInterface
{
/**
* #var int
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="string", length=256)
*/
private $password;
/**
* #var string
*
* #ORM\Column(type="string", length=64, unique=true)
*/
private $email;
/**
* #var string|null
*
* #ORM\Column(type="string", length=64, nullable=true)
*/
private $firstName;
/**
* #var string|null
*
* #ORM\Column(type="string", length=64, nullable=true)
*/
private $lastName;
/**
* #var string
*
* #ORM\Column(type="string", length=64, unique=true)
*/
private $username;
/**
* #var string
*
* #ORM\Column(type="string", length=64, unique=true)
*/
private $referralCode;
/**
* #var string|null
*
* #ORM\Column(type="string", length=64, nullable=true)
*/
private $referredByCode;
/**
* #var array
*
* #ORM\Column(type="array", length=64)
*/
private $roles;
/**
* #var DateTime
*
* #ORM\Column(type="datetime")
*/
private $activeTo;
/**
* #var DateTime
*
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #var DateTime
*
* #ORM\Column(type="datetime", nullable=true)
*/
private $updatedAt;
/**
* User constructor.
*
* #throws Exception
*/
public function __construct()
{
$this->createdAt = new DateTime();
$this->updatedAt = new DateTime();
$this->activeTo = new DateTime('now + 14 days');
$this->referralCode = substr(hash('sha256', uniqid()), 0, 5);
}
/**
* #return string
*/
public function __toString()
{
return $this->getUsername();
}
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #param string $username
*/
public function setUsername(string $username): void
{
$this->username = $username;
}
/**
* #return string
*/
public function getUsername(): ?string
{
return $this->username;
}
/**
* #return null|string
*/
public function getSalt(): ?string
{
// you *may* need a real salt depending on your encoder
// see section on salt below
return null;
}
/**
* #return string
*/
public function getPassword(): ?string
{
return $this->password;
}
/**
* #param string $password
*/
public function setPassword(string $password)
{
$this->password = $password;
}
/**
* #return array
*/
public function getRoles(): array
{
// return $this->roles;
return ['ROLE_USER', 'ROLE_API_USER'];
}
/**
*
*/
public function eraseCredentials()
{
}
/**
* #see Serializable::serialize()
*/
public function serialize()
{
return serialize(array($this->id, $this->email));
}
/**
* #see Serializable::unserialize()
*
* #param $serialized
*/
public function unserialize($serialized)
{
list ($this->id, $this->email) = unserialize($serialized, array('allowed_classes' => false));
}
/**
* #return string
*/
public function getEmail(): ?string
{
return $this->email;
}
/**
* #param string $email
*/
public function setEmail(string $email): void
{
$this->email = $email;
}
/**
* #return DateTime
*/
public function getCreatedAt(): DateTime
{
return $this->createdAt;
}
/**
* #ORM\PrePersist
*
* #throws Exception
*/
public function setCreatedAt(): void
{
$this->createdAt = new DateTime();
}
/**
* #return DateTime
*/
public function getUpdatedAt(): DateTime
{
return $this->updatedAt;
}
/**
* #ORM\PreUpdate
*
* #throws Exception
*/
public function setUpdatedAt(): void
{
$this->updatedAt = new DateTime();
}
/**
* #return DateTime
*/
public function getActiveTo(): DateTime
{
return $this->activeTo;
}
/**
* #param DateTime $activeTo
*/
public function setActiveTo(DateTime $activeTo): void
{
$this->activeTo = $activeTo;
}
/**
* #return string
*/
public function getReferralCode(): string
{
return $this->referralCode;
}
/**
* #param string $referralCode
*/
public function setReferralCode(string $referralCode): void
{
$this->referralCode = $referralCode;
}
/**
* #return string|null
*/
public function getReferredByCode():? string
{
return $this->referredByCode;
}
/**
* #param string|null $referredByCode
*/
public function setReferredByCode(?string $referredByCode): void
{
$this->referredByCode = $referredByCode;
}
/**
* #return string|null
*/
public function getFirstName(): ?string
{
return $this->firstName;
}
/**
* #param string|null $firstName
*/
public function setFirstName(?string $firstName): void
{
$this->firstName = $firstName;
}
/**
* #return string|null
*/
public function getLastName(): ?string
{
return $this->lastName;
}
/**
* #param string|null $lastName
*/
public function setLastName(?string $lastName): void
{
$this->lastName = $lastName;
}
/**
* #param array $roles
*/
public function setRoles(array $roles): void
{
$this->roles = $roles;
}
/**
* The equality comparison should neither be done by referential equality
* nor by comparing identities (i.e. getId() === getId()).
*
* However, you do not need to compare every attribute, but only those that
* are relevant for assessing whether re-authentication is required.
*
* #param UserInterface $user
*
* #return bool
*/
public function isEqualTo(UserInterface $user)
{
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
}
and security.yaml
encoders:
App\Entity\User\User:
algorithm: auto
providers:
user_provider:
entity:
class: App\Entity\User\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
http_basic: ~
anonymous: true
# logout_on_user_change: true
provider: user_provider
form_login:
login_path: app_user_login
check_path: app_user_login
default_target_path: app_user_dashboard
csrf_token_generator: security.csrf.token_manager
logout:
path: /app/logout
target: /app/login
# activate different ways to authenticate
# http_basic: true
# https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/app/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/app/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/app, roles: IS_AUTHENTICATED_FULLY }
I have red this post: Token was deauthenticated after trying to refresh it and that solution does not work for me. Any ideas?
You've got 2 options here:
Make your firewall stateless or
update your serialization in you User
I'm referring to https://symfony.com/doc/current/security/user_provider.html#understanding-how-users-are-refreshed-from-the-session btw, as I had the same issue.
First solution:
firewalls:
# ...
main:
http_basic: ~
anonymous: true
stateless: true
This should make Symfony ignore your serialization and just reload the whole entity from database.
Second solution:
class User implements UserInterface, Serializable, EquatableInterface
{
public function serialize()
{
return serialize(array(
$this->id,
$this->password,
$this->email,
$this->username,
$this->activeTo,
));
}
public function unserialize($serialized)
{
list (
$this->id,
$this->password,
$this->email,
$this->username,
$this->activeTo,
) = unserialize($serialized, array('allowed_classes' => false));
}
}
You should keep any information that Symfony might need in any of your user_checker classes (or the default ones).
I am using symfony 3 and trying to get the categories translated with mysql db. That's why I am using KnpLabs/DoctrineBehaviors, which should be the best for symfony.
I have done all like it is discribed in the documentation.
Category:
/**
* MdCategories
*
* #ORM\Table(name="md_category")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category implements ORMBehaviors\Tree\NodeInterface, \ArrayAccess
{
use ORMBehaviors\Translatable\Translatable,
ORMBehaviors\Sortable\Sortable,
ORMBehaviors\Tree\Node;
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="NONE")
*/
protected $id;
CategoryTranslation:
/**
* #ORM\Table(name="md_category_translation")
* #ORM\Entity
*/
class CategoryTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* #var name
* #ORM\Column(type="string", length=120, nullable=false)
*/
protected $name;
/**
* #var route
*
* #ORM\Column(type="string", length=150)
*/
protected $route;
/**
* #var metaKey
*
* #ORM\Column(type="string", length=255)
*/
protected $metaKey;
/**
* #var metaTitle
*
* #ORM\Column(type="string", length=100)
*/
protected $metaTitle;
/**
* #var metaDescription
*
* #ORM\Column(type="string", length=120)
*/
protected $metaDescription;
/**
* #return name
*/
public function getName()
{
return $this->name;
}
/**
* #param name $name
* #return Categories
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* #return route
*/
public function getRoute()
{
return $this->route;
}
/**
* #param route $route
* #return Categories
*/
public function setRoute($route)
{
$this->route = $route;
return $this;
}
/**
* #return metaKey
*/
public function getMetaKey()
{
return $this->metaKey;
}
/**
* #param metaKey $metaKey
* #return Categories
*/
public function setMetaKey($metaKey)
{
$this->metaKey = $metaKey;
return $this;
}
/**
* #return metaTitle
*/
public function getMetaTitle()
{
return $this->metaTitle;
}
/**
* #param metaTitle $metaTitle
* #return Categories
*/
public function setMetaTitle($metaTitle)
{
$this->metaTitle = $metaTitle;
return $this;
}
/**
* #return metaDescription
*/
public function getMetaDescription()
{
return $this->metaDescription;
}
public function setMetaDescription($metaDescription)
{
$this->metaDescription = $metaDescription;
return $this;
}
public function __call($method, $arguments)
{
return $this->proxyCurrentLocaleTranslation($method, $arguments);
}
}
CategoryRepository:
class CategoryRepository extends EntityRepository
{
use ORMBehaviors\Tree\Tree;
}
config.yml:
knp_doctrine_behaviors:
translatable: true
tree: true
sortable: true
# All others behaviors are disabled
and registering the bundle
new Knp\DoctrineBehaviors\Bundle\DoctrineBehaviorsBundle(),
The databases are generated correctly
But how do I fill the categoryTranslation Data with the right local ?
$category = new Category;
$category->setCurrentLocale('de');
$category->setId(1); // tree nodes need an id to construct path.
$category->setName('Foobar');
$em->persist($category);
$em->flush();
This did not work !
I am surprised, that there is no KNP Translationsubscriber is listened in the subcribed events of symfony
Here is the solution.
$category = new Category;
$category->translate('de')->setName('Foobar');
$em->persist($category);
$category->mergeNewTranslations();
$em->flush();
I'm trying to make a login form without FOSuser, as I need to override a lot in the entity User. I tried to find a lot of informations with the cookbook, and on several sites, but the mere informations were for SF2, which is quite annoying as the code may be different.
I managed to make a registration form, which records the User on the db, but my login form doesn't want to work whatever I can do. I have only one error message, "Invalid credential". I thought it could be because of a bad algorithm, but I changed it three or four times (bcrypt, sha512, none...), no success.
Here's my security.yml (I know that there's a lot a useless code but I don't want to remove anything that could be useful):
security:
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
# http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
providers:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
our_db_provider:
entity:
class: FrontBundle:User
property: username
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login$
security: false
login:
pattern: ^/register$
security: false
main:
anonymous: false
pattern: ^/
form_login:
login_path: login
check_path: login_check
logout:
path: /logout
target: /
# activate different ways to authenticate
# http_basic: ~
# http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate
# form_login: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
access_control:
- { path: ^/register$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_ADMIN }
Here's my entity User (excuse my french, it's a school project :) ):
<?php
namespace FrontBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="FrontBundle\Repository\UserRepository")
*/
class User implements UserInterface
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=255)
*/
private $nom;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=255, unique=true)
*/
private $username;
/**
* #var string
*
* #ORM\Column(name="prenom", type="string", length=255)
*/
private $prenom;
/**
* #var string
*
* #ORM\Column(name="mail", type="string", length=255, unique=true)
*/
private $mail;
/**
* #Assert\NotBlank()
* #Assert\Length(max=4096)
*/
private $plainPassword;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=255)
*/
private $password;
/**
* #var string
*
* #ORM\Column(name="salt", type="string", length=255, nullable=true)
*/
private $salt;
/**
* #var string
*
* #ORM\Column(name="photo", type="string", length=255, nullable=true)
*/
private $photo;
/**
* #var string
*
* #ORM\Column(name="ville", type="string", length=255, nullable=true)
*/
private $ville;
/**
* #var array
*
* #ORM\Column(type="array", nullable=false)
*/
protected $roles;
/**
* #ORM\ManyToOne(targetEntity="Entreprise", inversedBy="users", cascade={"remove"})
* #ORM\JoinColumn(name="entreprise_id", referencedColumnName="id")
*/
protected $entreprise;
/**
* #ORM\ManyToOne(targetEntity="Promotion", inversedBy="users", cascade={"remove"})
* #ORM\JoinColumn(name="promotion_id", referencedColumnName="id")
*/
protected $promotion;
/**
* #ORM\OneToMany(targetEntity="Annonce", mappedBy="user", cascade={"remove", "persist"})
*/
protected $annonces;
/**
* #ORM\OneToMany(targetEntity="Commentaire", mappedBy="user", cascade={"remove", "persist"})
*/
protected $commentaires;
/**
* #ORM\OneToMany(targetEntity="Article", mappedBy="user", cascade={"remove", "persist"})
*/
protected $articles;
/**
* #ORM\OneToMany(targetEntity="Evenement", mappedBy="user", cascade={"remove", "persist"})
*/
protected $evenements;
/**
* #ORM\ManyToMany(targetEntity="Evenement", inversedBy="users")
* #ORM\JoinTable(name="evenement_user")
*/
private $participe;
/**
* #ORM\ManyToMany(targetEntity="Groupe", inversedBy="users")
* #ORM\JoinTable(name="groupe_user")
*/
private $groupes;
public function __construct() {
$this->participe = new \Doctrine\Common\Collections\ArrayCollection();
$this->groupes = new \Doctrine\Common\Collections\ArrayCollection();
$this->roles = array("ROLE_USER");
$this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set nom
*
* #param string $nom
*
* #return User
*/
public function setNom($nom)
{
$this->nom = $nom;
return $this;
}
/**
* Get nom
*
* #return string
*/
public function getNom()
{
return $this->nom;
}
/**
* Set prenom
*
* #param string $prenom
*
* #return User
*/
public function setPrenom($prenom)
{
$this->prenom = $prenom;
return $this;
}
/**
* Get prenom
*
* #return string
*/
public function getPrenom()
{
return $this->prenom;
}
/**
* Set mail
*
* #param string $mail
*
* #return User
*/
public function setMail($mail)
{
$this->mail = $mail;
return $this;
}
/**
* Get mail
*
* #return string
*/
public function getMail()
{
return $this->mail;
}
/**
* 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 photo
*
* #param string $photo
*
* #return User
*/
public function setPhoto($photo)
{
$this->photo = $photo;
return $this;
}
/**
* Get photo
*
* #return string
*/
public function getPhoto()
{
return $this->photo;
}
/**
* Set ville
*
* #param string $ville
*
* #return User
*/
public function setVille($ville)
{
$this->ville = $ville;
return $this;
}
/**
* Get ville
*
* #return string
*/
public function getVille()
{
return $this->ville;
}
/**
* Set entreprise
*
* #param \FrontBundle\Entity\Entreprise $entreprise
*
* #return User
*/
public function setEntreprise(\FrontBundle\Entity\Entreprise $entreprise = null)
{
$this->entreprise = $entreprise;
return $this;
}
/**
* Get entreprise
*
* #return \FrontBundle\Entity\Entreprise
*/
public function getEntreprise()
{
return $this->entreprise;
}
/**
* Set promotion
*
* #param \FrontBundle\Entity\Promotion $promotion
*
* #return User
*/
public function setPromotion(\FrontBundle\Entity\Promotion $promotion = null)
{
$this->promotion = $promotion;
return $this;
}
/**
* Get promotion
*
* #return \FrontBundle\Entity\Promotion
*/
public function getPromotion()
{
return $this->promotion;
}
/**
* Add annonce
*
* #param \FrontBundle\Entity\Annonce $annonce
*
* #return User
*/
public function addAnnonce(\FrontBundle\Entity\Annonce $annonce)
{
$this->annonces[] = $annonce;
return $this;
}
/**
* Remove annonce
*
* #param \FrontBundle\Entity\Annonce $annonce
*/
public function removeAnnonce(\FrontBundle\Entity\Annonce $annonce)
{
$this->annonces->removeElement($annonce);
}
/**
* Get annonces
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAnnonces()
{
return $this->annonces;
}
/**
* Add commentaire
*
* #param \FrontBundle\Entity\Commentaire $commentaire
*
* #return User
*/
public function addCommentaire(\FrontBundle\Entity\Commentaire $commentaire)
{
$this->commentaires[] = $commentaire;
return $this;
}
/**
* Remove commentaire
*
* #param \FrontBundle\Entity\Commentaire $commentaire
*/
public function removeCommentaire(\FrontBundle\Entity\Commentaire $commentaire)
{
$this->commentaires->removeElement($commentaire);
}
/**
* Get commentaires
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCommentaires()
{
return $this->commentaires;
}
/**
* Add article
*
* #param \FrontBundle\Entity\Article $article
*
* #return User
*/
public function addArticle(\FrontBundle\Entity\Article $article)
{
$this->articles[] = $article;
return $this;
}
/**
* Remove article
*
* #param \FrontBundle\Entity\Article $article
*/
public function removeArticle(\FrontBundle\Entity\Article $article)
{
$this->articles->removeElement($article);
}
/**
* Get articles
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getArticles()
{
return $this->articles;
}
/**
* Add evenement
*
* #param \FrontBundle\Entity\Evenement $evenement
*
* #return User
*/
public function addEvenement(\FrontBundle\Entity\Evenement $evenement)
{
$this->evenements[] = $evenement;
return $this;
}
/**
* Remove evenement
*
* #param \FrontBundle\Entity\Evenement $evenement
*/
public function removeEvenement(\FrontBundle\Entity\Evenement $evenement)
{
$this->evenements->removeElement($evenement);
}
/**
* Get evenements
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEvenements()
{
return $this->evenements;
}
/**
* Add participe
*
* #param \FrontBundle\Entity\Evenement $participe
*
* #return User
*/
public function addParticipe(\FrontBundle\Entity\Evenement $participe)
{
$this->participe[] = $participe;
return $this;
}
/**
* Remove participe
*
* #param \FrontBundle\Entity\Evenement $participe
*/
public function removeParticipe(\FrontBundle\Entity\Evenement $participe)
{
$this->participe->removeElement($participe);
}
/**
* Get participe
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getParticipe()
{
return $this->participe;
}
/**
* Add groupe
*
* #param \FrontBundle\Entity\Groupe $groupe
*
* #return User
*/
public function addGroupe(\FrontBundle\Entity\Groupe $groupe)
{
$this->groupes[] = $groupe;
return $this;
}
/**
* Remove groupe
*
* #param \FrontBundle\Entity\Groupe $groupe
*/
public function removeGroupe(\FrontBundle\Entity\Groupe $groupe)
{
$this->groupes->removeElement($groupe);
}
/**
* Get groupes
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroupes()
{
return $this->groupes;
}
public function getRoles() {
return array($this->roles);
}
public function getUsername() {
return $this->username;
}
public function getSalt() {
return $this->salt;
}
public function eraseCredentials() {
// Ici nous n'avons rien à effacer.
// Cela aurait été le cas si nous avions un mot de passe en clair.
}
/**
* Set username
*
* #param string $username
*
* #return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Set salt
*
* #param string $salt
*
* #return User
*/
public function setSalt($salt)
{
$this->salt = $salt;
return $this;
}
/**
* Set roles
*
* #param string $roles
*
* #return User
*/
public function setRoles($roles)
{
$this->roles = $roles;
return $this;
}
public function getPlainPassword()
{
return $this->plainPassword;
}
public function setPlainPassword($password)
{
$this->plainPassword = $password;
}
}
Here's my SecurityController:
namespace FrontBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
class SecurityController extends Controller
{
/**
* #Route("/login", name="login")
* #Template()
*/
public function loginAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('FrontBundle:Security:login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
}
Here are my routes:
login:
path: /login
defaults: { _controller: FrontBundle:Security:login}
login_check:
path: /login_check
I think these are the only files needed to make it work, please tell me if you need anything else.
Thanks if you can help me :)
I need to update password with sonata admin int fos userbundle 'bcrypt' password.
This is my admin class,
<?php
namespace AdminBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
class UserAdmin extends Admin {
public function postPersist($object) {
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->findUserBy(array('id'=>$object->id));
$user->setPlainPassword('test');
$userManager->updateUser($user);
}
This is my user entity,
<?php
// src/AppBundle/Entity/User.php
namespace AdminBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="telephone", type="text", length=30, nullable=false)
*/
private $telephone;
/**
* Set nonotification
*
* #param text $telephone
* #return User
*/
public function settelephone($telephone) {
$this->telephone = $telephone;
return $this;
}
/**
* Get telephone
*
* #return text
*/
public function gettelephone() {
return $this->telephone;
}
/**
* #var string
*
* #ORM\Column(name="name", type="text", length=60, nullable=false)
*/
private $name;
/**
* Set nonotification
*
* #param text $name
* #return User
*/
public function setname($name) {
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return text
*/
public function getname() {
return $this->name;
}
/**
* #var string
*
* #ORM\Column(name="surname", type="text", length=60, nullable=false)
*/
private $surname;
/**
* Set nonotification
*
* #param text $name
* #return User
*/
public function setsurname($surname) {
$this->surname = $surname;
return $this;
}
/**
* Get surname
*
* #return text
*/
public function getsurname() {
return $this->surname;
}
public function __construct() {
parent::__construct();
// your own logic
}
}
But I'm getting this error instead,
Attempted to call an undefined method named "get" of class
"AdminBundle\Admin\UserAdmin". Did you mean to call e.g.
"getActiveSubClass", "getActiveSubclassCode", "getBaseCodeRoute",
"getBaseControllerName", "getBaseRouteName", "getBaseRoutePattern",
"getBatchActions", "getBreadcrumbs", "getChild", "getChildren",
"getClass", "getClassnameLabel", "getCode", "getConfigurationPool",
"getCurrentChild", "getCurrentChildAdmin", "getDataSourceIterator",
"getDatagrid", "getDatagridBuilder", "getExportFields",
"getExportFormats", "getExtensions", "getFilterFieldDescription",
"getFilterFieldDescriptions", "getFilterParameters", "getFilterTheme",
"getForm", "getFormBuilder", "getFormContractor",
"getFormFieldDescription", "getFormFieldDescriptions",
"getFormGroups", "getFormTabs", "getFormTheme", "getIdParameter",
"getLabel", "getLabelTranslatorStrategy", "getList", "getListBuilder",
"getListFieldDescription", "getListFieldDescriptions",
"getManagerType", "getMaxPageLinks", "getMaxPerPage",
"getMenuFactory", "getModelManager", "getNewInstance",
"getNormalizedIdentifier", "getObject", "getObjectIdentifier",
"getObjectMetadata", "getParent", "getParentAssociationMapping",
"getParentFieldDescription", "getPerPageOptions",
"getPermissionsShow", "getPersistentParameter",
"getPersistentParameters", "getRequest", "getRoot", "getRootCode",
"getRouteBuilder", "getRouteGenerator", "getRouterIdParameter",
"getRoutes", "getSecurityHandler", "getSecurityInformation",
"getShow", "getShowBuilder", "getShowFieldDescription",
"getShowFieldDescriptions", "getShowGroups", "getShowTabs",
"getSideMenu", "getSubClasses", "getSubject", "getTemplate",
"getTemplates", "getTranslationDomain", "getTranslationLabel",
"getTranslator", "getUniqid", "getUrlsafeIdentifier" or
"getValidator"?
It would be great help someone can look into it.
You cannot access the container with $this->get('service.name') from a sonata admin class. You should use:
$container = $this->getConfigurationPool()->getContainer();
$userManager = $container->get('fos_user.user_manager');
Also, I don't know if your solution would work anyway. I would use something like this:
public function postPersist($object) {
$container = $this->getConfigurationPool()->getContainer();
$entityManager = $container->get('doctrine.orm.entity_manager');
$object->setPlainPassword('test');
$entityManager->persist($user);
$entityManager->flush();
}
And do yourself a favor and respect the naming conventions (getName instead of getname, etc)
I use symfony2.4 and KNP doctrine behaviors translatable.
I have entity Site (for ID, host, enabled) and entity SiteTranslation (for translated fields: name, descriptions, …).
I use query to get results
$qb = $this->createQueryBuilder('s')
->addSelect('translation') // to eager fetch translations (optional)
->leftJoin('s.translations', 'translation') // or innerJoin ?
->orderBy('s.root', 'ASC')
->addOrderBy('s.lft', 'ASC');
I would like to print result in Twig. For ID, host and enabled fields from Site entity it's easy:
{{ item.id }}
But I can't print translated fields (name, description, …)
{{ item.name }}
It doesn't work.
Error message:
ContextErrorException: Warning: call_user_func_array() expects parameter 1 to be a valid >callback, class 'Net\ConBundle\Entity\SiteTranslation' does not have a method 'name' in >D:\Users...\vendor\knplabs\doctrine->behaviors\src\Knp\DoctrineBehaviors\Model\Translatable\TranslatableMethods.php line 140
Getters and setters for translatable fields are in SiteTranslation entity.
UPDATE:
I still didn't find a solution for an error.
Here is Site entity:
<?php
namespace Pnet\ConlocoBundle\Entity;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* #UniqueEntity("host", message="site.host.unique", groups={"edit"})
* #Gedmo\Tree(type="nested")
* #ORM\Entity(repositoryClass="Pnet\ConlocoBundle\Entity\Repository\SiteRepository")
* #ORM\Table(name="site")
*/
class Site
{
use ORMBehaviors\Translatable\Translatable; // knp translatable strategy
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=40, unique=true)
* #Assert\NotBlank(message="site.host.notBlank", groups={"edit"})
* #Assert\Length(max = "40", maxMessage = "site.host.maxLength", groups={"edit"})
*/
protected $host;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Assert\Image()
*/
protected $image;
/**
* #ORM\Column(type="boolean")
* #Assert\Choice(choices = {"1", "0"}, message = "site.isDefault.choice", groups={"edit"})
*/
protected $isDefault;
/**
* #ORM\Column(type="boolean")
* #Assert\Choice(choices = {"1", "0"}, message = "site.enabled.choice", groups={"edit"})
*/
protected $enabled;
/**
* #ORM\Column(type="string", length=64, nullable=true)
*/
protected $analytics;
/**
* #Gedmo\TreeLeft
* #ORM\Column(name="lft", type="integer")
*/
private $lft;
/**
* #Gedmo\TreeLevel
* #ORM\Column(name="lvl", type="integer")
*/
private $lvl;
/**
* #Gedmo\TreeRight
* #ORM\Column(name="rgt", type="integer")
*/
private $rgt;
/**
* #Gedmo\TreeRoot
* #ORM\Column(name="root", type="integer", nullable=true)
*/
private $root;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Site", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="Site", mappedBy="parent")
* #ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
private $file;
public $idByFilter;
public $nameByFilter;
/**
* Proxy translations (Knp/Doctrine Behaviors)
* An extra feature allows you to proxy translated fields of a translatable entity.
* You can use it in the magic __call method of you translatable entity so that when
* you try to call getName (for example) it will return you the translated value
* of the name for current locale:
*/
public function __call($method, $arguments)
{
return $this->proxyCurrentLocaleTranslation($method, $arguments);
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set host
*
* #param string $host
* #return Site
*/
public function setHost($host)
{
$this->host = $host;
return $this;
}
/**
* Get host
*
* #return string
*/
public function getHost()
{
return $this->host;
}
/**
* Set isDefault
*
* #param boolean $isDefault
* #return Site
*/
public function setIsDefault($isDefault)
{
$this->isDefault = $isDefault;
return $this;
}
/**
* Get isDefault
*
* #return boolean
*/
public function getIsDefault()
{
return $this->isDefault;
}
/**
* Set enabled
*
* #param boolean $enabled
* #return Site
*/
public function setEnabled($enabled)
{
$this->enabled = $enabled;
return $this;
}
/**
* Get enabled
*
* #return boolean
*/
public function getEnabled()
{
return $this->enabled;
}
/**
* Set analytics
*
* #param string $analytics
* #return Site
*/
public function setAnalytics($analytics)
{
$this->analytics = $analytics;
return $this;
}
/**
* Get analytics
*
* #return string
*/
public function getAnalytics()
{
return $this->analytics;
}
/**
* Get ID from Filter
*
* #return string
*/
public function getIdByFilter()
{
return $this->idByFilter;
}
/**
* Get name from Filter
*
* #return string
*/
public function getNameByFilter()
{
return $this->nameByFilter;
}
/**
* Set image
*
* #param string $image
* #return Site
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return string
*/
public function getImage()
{
return $this->image;
}
/**
* Set file
*
* #param string $file
* #return Site
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Get file
*
* #return string
*/
public function getFile()
{
return $this->file;
}
/**
*
* Tree functions
*/
public function setParent(Site $parent = null)
{
$this->parent = $parent;
}
public function getParent()
{
return $this->parent;
}
public function getRoot()
{
return $this->root;
}
public function getLvl()
{
return $this->lvl;
}
public function getChildren()
{
return $this->children;
}
public function getLft()
{
return $this->lft;
}
public function getRgt()
{
return $this->rgt;
}
/**
* Add a method to the entity class that shows the name indented by nesting level
*/
public function getLeveledName()
{
return str_repeat(
html_entity_decode(' ', ENT_QUOTES, 'UTF-8'),
($this->getLvl()) * 3
) . $this->getName();
}
public function getLeveledPosition()
{
return str_repeat(
html_entity_decode(' ', ENT_QUOTES, 'UTF-8'),
($this->getLvl()) * 3
);
}
}
And here is SiteTranslation entity:
namespace Pnet\ConlocoBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* #ORM\Entity
*/
class SiteTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* #ORM\Column(type="string", length=60)
* #Assert\NotBlank(message="site.name.notBlank", groups={"edit"})
* #Assert\Length(max = "60", maxMessage = "site.name.maxLength", groups={"edit"})
*/
protected $name;
/**
* #ORM\Column(type="string", length=100)
* #Assert\NotBlank(message="site.title.notBlank", groups={"edit"})
* #Assert\Length(max = "100", maxMessage = "site.title.maxLength", groups={"edit"})
*/
protected $title;
/**
* #ORM\Column(type="string", length=200)
* #Assert\NotBlank(message="site.longTitle.notBlank", groups={"edit"})
* #Assert\Length(max = "200", maxMessage = "site.longTitle.maxLength", groups={"edit"})
*/
protected $longTitle;
/**
* #ORM\Column(type="string", length=250, nullable=true)
* #Assert\Length(max = "250", maxMessage = "site.keywords.maxLength", groups={"edit"})
*/
protected $keywords;
/**
* #ORM\Column(type="string", length=500, nullable=true)
* #Assert\Length(max = "500", maxMessage = "site.description.maxLength", groups={"edit"})
*/
protected $description;
/**
* Set name
*
* #param string $name
* #return Site
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set title
*
* #param string $title
* #return Site
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set longTitle
*
* #param string $longTitle
* #return Site
*/
public function setLongTitle($longTitle)
{
$this->longTitle = $longTitle;
return $this;
}
/**
* Get longTitle
*
* #return string
*/
public function getLongTitle()
{
return $this->longTitle;
}
/**
* Set keywords
*
* #param string $keywords
* #return Site
*/
public function setKeywords($keywords)
{
$this->keywords = $keywords;
return $this;
}
/**
* Get keywords
*
* #return string
*/
public function getKeywords()
{
return $this->keywords;
}
/**
* Set description
*
* #param string $description
* #return Site
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
}
TL;DR:
As a (probably dirty) workaround, use
{{ item.getName }}
in your Twig template instead of
{{ item.name }}
Explanation:
I came across the same issue and i think that this should be considered a bug in the Knp DoctrineBehaviors documentation when used with Twig. When you call this in your Twig template :
{{ item.name }}
This is what Twig does behind the scenes to get the name property :
try to get the name public property of the item object
if not found, checks for the name public method of the item object
if not found, checks for the getName() public method of the "item" object
if not found, checks for the __call() magic method (and calls it with the name parameter)
The problem here is step 4. The magic __call() method that you defined (as recommended by the official DoctrineBehaviors documentation) is called with the name parameter instead of getName. It then calls the proxyCurrentLocaleTranslation() method who tries to call the name public method of your translation class. Of course, it doesn't exist because you only have a getName() method.
See this issue in Twig : https://github.com/twigphp/Twig/issues/342
By using directly the {{ item.getName }} code in Twig, the proper method name will be called.
This work for me:
public function __call($method, $arguments)
{
try {
return $this->proxyCurrentLocaleTranslation($method, $arguments);
} catch (\Symfony\Component\Debug\Exception\ContextErrorException $e) {
return $this->proxyCurrentLocaleTranslation('get' . ucfirst($method), $arguments);
}
}
You haven't moved all the translatable properties/methods to your <Name>Translation class.
The exception clearly states that there is no name/getName method in your SiteTranslation class.
Please read my answer over here to see how Knp\DoctrineBehaviors's magic translation proxy is used correctly.