I'm trying to create a Cart under Symfony 6.1.2
I want to add my product in my cart but i have this error message : Warning: Undefined variable $session
public function get()
{
//return $this->session->get('cart');
return $session->get('cart');
}
i've commented a line because i was using SessionInterface but this is not used anymore on Symfony 6.1.
I don't get where is my error so i'm there to have some help.
This is my Cart.php (with some commented lines from SessionInterface)
<?php
namespace App\Classe;
use Symfony\Component\HttpFoundation\RequestStack;
//use Symfony\Component\HttpFoundation\Session\SessionInterface;
class Cart
{
//private $session;
private $requestStack;
//public function __construct(SessionInterface $session)
public function __construct(RequestStack $requestStack)
{
//$this->session = $session;
$this->requestStack = $requestStack;
}
public function add($id)
{
$session = $this->requestStack->getSession();
$cart = $session->get('cart', []);
if (!empty($cart[$id])) {
$cart[$id]++;
} else {
$cart[$id] = 1;
}
$session->set('cart',$cart);
/* $cart = $this->session->get('cart', []);
if (!empty($cart[$id])) {
$cart[$id]++;
} else {
$cart[$id] = 1;
}
$this->session->set('cart', $cart); */
}
public function get()
{
//return $this->session->get('cart');
return $session->get('cart');
}
public function remove()
{
//return $this->session->remove('cart');
return $session->remove('cart');
}
}
and this is my CartController.php
<?php
namespace App\Controller;
use App\Classe\Cart;
use App\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class CartController extends AbstractController
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* #Route("/mon-panier", name="cart")
*/
public function index(Cart $cart)
{
$cartComplete = [];
foreach ($cart->get() as $id => $quantity){
$cartComplete[] = [
'product' => $this->entityManager->getRepository(Product::class)-
>findOneById($id),
'quantity' => $quantity
];
}
return $this->render('cart/index.html.twig', [
'cart' => $cartComplete
]);
}
/**
* #Route("/cart/add/{id}", name="add_to_cart")
*/
public function add(Cart $cart, $id)
{
$cart->add($id);
return $this->redirectToRoute('cart');
}
/**
* #Route("/cart/remove/", name="remove_my_cart")
*/
public function remove(Cart $cart)
{
$cart->remove();
return $this->redirectToRoute('products');
}
}
If i miss something it would be kind to show me where is the mistake.
Thank you ;)
i found the solution.
With ResquestStack, i was wrong doing this :
public function get()
{
return $session->get('cart');
}
public function remove()
{
return $session->remove('cart');
}
I've changed my returns with :
public function get()
{
return $this->requestStack->getSession()->get('cart');
}
public function remove()
{
return $this->requestStack->getSession()->remove('cart');
}
}
Now everything is ok, in case of someone was block in this kind of situation
Related
I'm new to UnitTest and trying to integrate it into my Laravel application, but I'm getting the below error:
Call to a member function findOne() on null
at app/Services/User/UserService.php:32
28▕ $this->userWebsiteRepository = $userWebsiteRepository;
29▕ }
30▕
31▕ public function findOne($data = []){
➜ 32▕ return $this->userRepository->findOne($data);
33▕ }
34▕
This is my code.
AuthController.php
class AuthController extends Controller {
private $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function show($id){
return $this->userService->findOne(['id' => $id]);
}
}
UserService.php
class UserService
{
public $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
}
UserRepositoryInterface.php
interface UserRepositoryInterface
{
public function findOne($data);
}
UserRepository.php
use App\Models\User;
class UserRepository implements UserRepositoryInterface
{
private $model;
public function __construct(User $user)
{
$this->model = $user;
}
public function findOne($data)
{
if (empty($data)) return false;
$query = $this->model->with(['userWebsites', 'userWebsites.website', 'role']);
if(!empty($data['id'])) $query = $query->where('id', $data['id']);
return $query->first();
}
}
RepositoryServiceProvider.php
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
}
AuthControllerTest.php
class AuthControllerTest extends TestCase
{
public $authController;
public $userRepositoryInterfaceMockery;
public $userServiceMokery;
public function setUp(): void{
$this->afterApplicationCreated(function (){
$this->userRepositoryInterfaceMockery = Mockery::mock(UserRepositoryInterface::class)->makePartial();
$this->userServiceMokery = Mockery::mock((new UserService(
$this->app->instance(UserRepositoryInterface::class, $this->userRepositoryInterfaceMockery)
))::class)->makePartial();
$this->authController = new AuthController(
$this->app->instance(UserService::class, $this->userServiceMokery)
);
}
}
public function test_abc_function(){
$res = $this->authController->abc(1);
}
}
I was still able to instantiate the AuthController and it ran to the UserService. but it can't get the UserRepositoryInterface argument. I think the problem is that I passed the Interface in the constructor of the UserService. .What happened, please help me, thanks
I don't know where $userService comes from to your controller's constructor, but it seems like it comes from nowhere. You need to pass it as argument, so Laravel can resolve its instance in service container.
class AuthController extends Controller {
private $userService;
public function __construct(
private AuthService $authService,
UserRepositoryInterface $userRepository
) {
$this->userService = new UserService($userRepository);
}
public function show($id)
{
return $this->userService->findOne(['id' => $id]);
}
}
Also there is literally no findOne method in UserService. You need one there.
class UserService
{
public function __construct(private UserRepositoryInterface $userRepository)
{
}
public function findOne(array $data)
{
return $this->userRepository->findOne($data);
}
}
Update
In that case you need this in service provider:
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
$this->app->bind(UserService::class, function ($app) {
return new UserService($app->make(UserRepositoryInterface::class));
});
Im using system where it is using $user->is_admin and $user->is_employee and $user->is_customer there is no column is_admin or is_employee or is_customer in database. I know that it takes it from user model. but is_admin or is_employee is not defined anywhere. and dumping gives me true or false.
I want add new checking like is_manager. but cant find where I can add this..
Debugbar isnt showing any query for is_admin column..
Where it can be located?
example I have observer:
use App\Helper\SearchLog;
use App\User;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
class UserObserver
{
public function roleAttached(User $user, $role, $team)
{
if (!$user->is_admin) {
$type = 'Employee';
$route = 'admin.employee.edit';
if ($user->is_customer) {
$type = 'Customer';
$route = 'admin.customers.show';
}
SearchLog::createSearchEntry($user->id, $type, $user->name, $route);
SearchLog::createSearchEntry($user->id, $type, $user->email, $route);
}
}
I dont understand how it knows is_admin if it is not in database column?
My user model:
namespace App;
use App\Observers\UserObserver;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laratrust\Traits\LaratrustUserTrait;
class User extends Authenticatable
{
//------------------------------------ Traits ---------------------------
use LaratrustUserTrait;
use Notifiable;
//------------------------------------ Attributes ---------------------------
protected static function boot() {
parent::boot();
static::observe(UserObserver::class);
static::laratrustObserve(UserObserver::class);
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
protected $appends = [
'user_image_url', 'mobile_with_code', 'formatted_mobile'
];
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = ['deleted_at'];
//------------------------------------ Relations ----------------------------
public function employeeGroup() {
return $this->belongsTo(EmployeeGroup::class, 'group_id');
}
public function todoItems() {
return $this->hasMany(TodoItem::class);
}
public function completedBookings() {
return $this->hasMany(Booking::class, 'user_id')->where('bookings.status', 'completed');
}
public function booking() {
return $this->belongsToMany(Booking::class);
}
public function services() {
return $this->belongsToMany(BusinessService::class);
}
public function leave()
{
return $this->hasMany('App\Leave', 'employee_id', 'id');
}
public function role()
{
return $this->belongsToMany(Role::class);
}
public function employeeSchedule()
{
return $this->hasMany('App\EmployeeSchedules', 'employee_id', 'id');
}
//------------------------------------ Scopes -------------------------------
public function scopeAllAdministrators() {
return $this->whereHas('roles', function ($query) {
$query->where('name', 'administrator');
});
}
public function scopeAllCustomers() {
return $this->whereHas('roles', function ($query) {
$query->where('name', 'customer')->withoutGlobalScopes();
});
}
public function scopeOtherThanCustomers() {
return $this->whereHas('roles', function ($query) {
$query->where('name', '<>', 'customer');
});
}
public function scopeAllEmployees() {
return $this->whereHas('roles', function ($query) {
$query->where('name', 'employee');
});
}
//------------------------------------ Accessors ----------------------------
public function getUserImageUrlAttribute() {
if (is_null($this->image)) {
return asset('img/default-avatar-user.png');
}
return asset_url('avatar/' . $this->image);
}
public function getRoleAttribute() {
return $this->roles->first();
}
public function getMobileWithCodeAttribute() {
return substr($this->calling_code, 1).$this->mobile;
}
public function getFormattedMobileAttribute() {
if (!$this->calling_code) {
return $this->mobile;
}
return $this->calling_code.'-'.$this->mobile;
}
public function routeNotificationForNexmo($notification) {
return $this->mobile_with_code;
}
public function getIsAdminAttribute() {
return $this->hasRole('administrator');
}
public function getIsEmployeeAttribute() {
return $this->hasRole('employee');
}
public function getIsCustomerAttribute() {
if ($this->roles()->withoutGlobalScopes()->where('roles.name', 'customer')->count() > 0) {
return true;
}
return false;
}
//------------------------------------ Mutators -----------------------------
public function setPasswordAttribute($value) {
$this->attributes['password'] = bcrypt($value);
}
//------------------------------------ Formats -----------------------------
public function userBookingCount($date) {
return Booking::whereNull('deal_id')->where('user_id', $this->id)->whereDate('created_at', $date)->get()->count();
}
} /* end of class */
LoginController looks like this where is authenticated class:
protected function authenticated(Request $request, $user)
{
if ($user->is_admin || $user->is_employee) {
return redirect()->route('admin.dashboard');
}
if(!$user->is_admin && !$user->is_employee && Cookie::get('bookingDetails')!==null && Cookie::get('products')!==null && $this->checkUserBooking($user->id)>$this->settings->booking_per_day){
return redirect(route('front.index'))->withCookie(Cookie::forget('bookingDetails'))->withCookie(Cookie::forget('products'))->withCookie(Cookie::forget('couponData'));
}
return redirect(session()->get('url.encoded'));
}
You can make another accessor that will check if role is associated with current user entity.
public function getIsManagerAttribute() {
return $this->hasRole('manager');// presuming you have created manager role
}
Then you can check easily with
// $user = User::find(1);
// $user->is_manager;// true || false
So my code is pretty straightforward, I have a login form, an authenticator, and a login method in the controller.
In my authenticator class, when user credentials are wrong, I store the email used in the session. See below ( specifically the getCredentials method ) :
<?php
namespace AppBundle\Security;
use Psr\Log\LoggerInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use AppBundle\Form\LoginFormType;
class LoginFormAuthenticator extends AbstractGuardAuthenticator
{
private $passwordEncoder;
private $logger;
private $router;
private $formFactory;
public function __construct(FormFactoryInterface $formFactory, LoggerInterface $logger,UserPasswordEncoderInterface $passwordEncoder, RouterInterface $router)
{
$this->formFactory = $formFactory;
$this->router = $router;
$this->logger = $logger;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return ($request->getPathInfo() == '/login' && $request->isMethod('POST'));
}
public function getCredentials(Request $request)
{
$form = $this->formFactory->create(LoginFormType::class);
$form->handleRequest($request);
$data = $form->getData();
**$request->getSession()->set(
Security::LAST_USERNAME,
$data['email']
);**
$test = $request->getSession()->get(Security::LAST_USERNAME);
$this->logger->info('email : '.$test);
return $data;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$email = $credentials['email'];
$this->logger->info('email getUser : '.$email);
if (null === $email) {
return;
}
return $userProvider->loadUserByUsername($email);
}
public function checkCredentials($credentials, UserInterface $user)
{
$plainPassword = $credentials['password'];
$encoder = $this->passwordEncoder;
if(!$encoder->isPasswordValid($user, $plainPassword)) {
return new Response('Password Invalid');
}
// return true to cause authentication success
return true;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
return new Response("<html><head></head><body>SUCCESS</body></html>");
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
$request->getSession()->set(Security::LAST_USERNAME, $request->get('email'));
$response = new RedirectResponse($this->router->generate('security_login'));
}
/**
* Called when authentication is needed, but it's not sent
*/
public function start(Request $request, AuthenticationException $authException = null)
{
return new Response('Authentication Required');
}
public function supportsRememberMe()
{
return false;
}
}
So far so good, the email is stored in the session. ( See the getCredentials method ).
However, the same value stored in the session is empty when accessed from the login controller below :
/**
* #Route("/login", name="security_login")
*/
public function loginAction(Request $request, AuthenticationUtils $authUtils)
{
$error = $authUtils->getLastAuthenticationError();
$last_username = $authUtils->getLastUsername();
$logger->info('email in SESSION : '.$last_username);
$form = $this->createForm(LoginFormType::class,[
'email' => $last_username
]);
return $this->render('security/login.html.twig', [
'loginForm' => $form->createView(),
'error'=> $error
]);
}
It's just empty, so I'm not sure what's happening here or what I'm doing wrong.
Please advise.
Thanks!
I tried to create an authenticator for my login form, but I always am unlogged for some unclear reason.
[2016-10-05 18:54:53] security.INFO: Guard authentication successful! {"token":"[object] (Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken: PostAuthenticationGuardToken(user=\"test#test.test\", authenticated=true, roles=\"ROLE_USER\"))","authenticator":"AppBundle\\Security\\Authenticator\\FormLoginAuthenticator"} []
[2016-10-05 18:54:54] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationExpiredException(code: 0): at /space/products/insurance/vendor/symfony/symfony/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php:86)"} []
[2016-10-05 18:54:54] security.INFO: The security token was removed due to an AccountStatusException. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationExpiredException(code: 0): at /space/products/insurance/vendor/symfony/symfony/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php:86)"} []
I don't understand this "AuthenticationExpiredException" as I have nothing stateless, nor any expiration in any way nowhere in my app.
Does this issue speak to anyone?
Edit 1
After a bunch of hours, it looks like I am unlogged because of the {{ is_granted('ROLE_USER') }} in Twig. Don't see why anyway.
Edit 2
If I dump() my security token on the onAuthenticationSuccess authenticator's method, authenticated = true.
But, If I dump() my security token after a redirect or when accessing a new page, 'authenticated' = false.
Why the hell my authentication isn't stored.
app/config/security.yml
security:
encoders:
AppBundle\Security\User\Member:
algorithm: bcrypt
cost: 12
providers:
members:
id: app.provider.member
role_hierarchy:
ROLE_ADMIN: "ROLE_USER"
firewalls:
dev:
pattern: "^/(_(profiler|wdt|error)|css|images|js)/"
security: false
main:
pattern: "^/"
anonymous: ~
logout: ~
guard:
authenticators:
- app.authenticator.form_login
access_control:
- { path: "^/connect", role: "IS_AUTHENTICATED_ANONYMOUSLY" }
- { path: "^/register", role: "IS_AUTHENTICATED_ANONYMOUSLY" }
- { path: "^/admin", role: "ROLE_ADMIN" }
- { path: "^/user", role: "ROLE_USER" }
- { path: "^/logout", role: "ROLE_USER" }
AppBundle/Controller/SecurityController.php
<?php
namespace AppBundle\Controller;
use AppBundle\Base\BaseController;
use AppBundle\Form\Type\ConnectType;
use AppBundle\Security\User\Member;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
class SecurityController extends BaseController
{
/**
* #Route("/connect", name="security_connect")
* #Template()
*/
public function connectAction(Request $request)
{
$connectForm = $this
->createForm(ConnectType::class)
->handleRequest($request)
;
return [
'connect' => $connectForm->createView(),
];
}
}
AppBundle/Form/Type/ConnectType.php
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Validator\Constraints;
use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaType;
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\IsTrue as RecaptchaTrue;
class ConnectType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', Type\EmailType::class, [
'label' => 'Your email',
'required' => true,
'constraints' => [
new Constraints\Length(['min' => 8])
],
])
->add('password', Type\PasswordType::class, [
'label' => 'Your password',
'constraints' => new Constraints\Length(['min' => 8, 'max' => 4096]), /* CVE-2013-5750 */
])
->add('recaptcha', EWZRecaptchaType::class, [
'label' => 'Please tick the checkbox below',
'constraints' => [
new RecaptchaTrue()
],
])
->add('submit', Type\SubmitType::class, [
'label' => 'Connect',
])
;
}
}
AppBundle/Security/Authenticator/FormLoginAuthenticator.php
<?php
namespace AppBundle\Security\Authenticator;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use AppBundle\Form\Type\ConnectType;
class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
private $container; // ¯\_(ツ)_/¯
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getCredentials(Request $request)
{
if ($request->getPathInfo() !== '/connect') {
return null;
}
$connectForm = $this
->container
->get('form.factory')
->create(ConnectType::class)
->handleRequest($request)
;
if ($connectForm->isValid()) {
$data = $connectForm->getData();
return [
'username' => $data['email'],
'password' => $data['password'],
];
}
return null;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
return $userProvider->loadUserByUsername($credentials['username']);
}
public function checkCredentials($credentials, UserInterface $user)
{
$isValid = $this
->container
->get('security.password_encoder')
->isPasswordValid($user, $credentials['password'])
;
if (!$isValid) {
throw new BadCredentialsException();
}
return true;
}
protected function getLoginUrl()
{
return $this
->container
->get('router')
->generate('security_connect')
;
}
protected function getDefaultSuccessRedirectUrl()
{
return $this
->container
->get('router')
->generate('home')
;
}
}
AppBundle/Security/Provider/MemberProvider.php
<?php
namespace AppBundle\Security\Provider;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use AppBundle\Security\User\Member;
use Api\Gateway\RequestResponse\RequestResponseHandlerInterface;
use Api\Business\InsuranceWebsite\Action\GetInsuranceMember\GetInsuranceMemberRequest;
use Api\Gateway\Exception\NoResultException;
class MemberProvider implements UserProviderInterface
{
protected $gateway;
public function __construct(RequestResponseHandlerInterface $gateway)
{
$this->gateway = $gateway;
}
public function loadUserByUsername($username)
{
try {
$response = $this->gateway->handle(
new GetInsuranceMemberRequest($username)
);
} catch (NoResultException $ex) {
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
$member = new Member();
$member->setId($response->getId());
$member->setUsername($response->getEmail());
$member->setPassword($response->getPassword());
$member->setCompanyId($response->getCompanyId());
$member->setFirstname($response->getFirstname());
$member->setLastname($response->getLastname());
$member->setIsManager($response->isManager());
$member->setIsEnabled($response->isEnabled());
return $member;
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof Member) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === Member::class;
}
}
AppBundle/Security/User/Member.php
<?php
namespace AppBundle\Security\User;
use Symfony\Component\Security\Core\User\UserInterface;
class Member implements UserInterface
{
private $id;
private $username;
private $password;
private $companyId;
private $firstname;
private $lastname;
private $isManager;
private $isEnabled;
private $roles = ['ROLE_USER'];
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
return $this;
}
public function getUsername()
{
return $this->username;
}
public function setUsername($username)
{
$this->username = $username;
return $this;
}
public function getPassword()
{
return $this->password;
}
public function setPassword($password)
{
$this->password = $password;
return $this;
}
public function getCompanyId()
{
return $this->companyId;
}
public function setCompanyId($companyId)
{
$this->companyId = $companyId;
return $this;
}
public function getFirstname()
{
return $this->firstname;
}
public function setFirstname($firstname)
{
$this->firstname = $firstname;
return $this;
}
public function getLastname()
{
return $this->lastname;
}
public function setLastname($lastname)
{
$this->lastname = $lastname;
return $this;
}
public function isManager()
{
return $this->isManager;
}
public function setIsManager($isManager)
{
$this->isManager = $isManager;
return $this;
}
public function IsEnabled()
{
return $this->isEnabled;
}
public function setIsEnabled($isEnabled)
{
$this->isEnabled = $isEnabled;
return $this;
}
public function eraseCredentials()
{
$this->password = null;
}
public function hasRole($role)
{
return in_array($role, $this->roles);
}
public function getRoles()
{
return $this->roles;
}
public function addRole($role)
{
if (!$this->hasRole($role)) {
$this->roles[] = $role;
}
return $this;
}
public function removeRole($role)
{
$index = array_search($role, $this->roles);
if ($index !== false) {
unset($this->roles[$index]);
$this->roles = array_values($this->roles);
}
return $this;
}
public function getSalt()
{
return null;
}
}
src/AppBundle/Resources/config/services.yml
imports:
parameters:
app.provider.member.class: AppBundle\Security\Provider\MemberProvider
app.authenticator.form_login.class: AppBundle\Security\Authenticator\FormLoginAuthenticator
services:
app.provider.member:
class: %app.provider.member.class%
arguments: ['#gateway']
app.authenticator.form_login:
class: %app.authenticator.form_login.class%
arguments: ["#service_container"]
I found my bug, after 8 hours of hard work. I promise, I'll drink a bulk of beers after this comment!
I located my issue in the Symfony\Component\Security\Core\Authentication\Token\AbstractToken::hasUserChanged() method, which compares user stored in the session, and the one returned by the refreshUser of your provider.
My user entity was considered changed because of this condition:
if ($this->user->getPassword() !== $user->getPassword()) {
return true;
}
In fact, before being stored in the session, the eraseCredentials() method is called on your user entity so the password is removed. But the password exists in the user the provider returns.
That's why in documentations, they show plainPassword and password properties... They keep password in the session, and eraseCredentials just cleans up `plainPassword. Kind of tricky.
Se we have 2 solutions:
having eraseCredentials not touching password, can be useful if you want to unauthent your member when he changes his password somehow.
implementing EquatableInterface in our user entity, because the following test is called before the one above.
if ($this->user instanceof EquatableInterface) {
return !(bool) $this->user->isEqualTo($user);
}
I decided to implement EquatableInterface in my user entity, and I'll never forget to do it in the future.
<?php
namespace AppBundle\Security\User;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
class Member implements UserInterface, EquatableInterface
{
// (...)
public function isEqualTo(UserInterface $user)
{
return $user->getId() === $this->getId();
}
}
I have 2 bundles, 1 works with the validation.yml file and one does not.
Both bundles are set up exactly the same, i have googled high and low and i cannot seem to understand why.
I have created a form type here:
<?php
namespace Brs\UserBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class Usertype extends AbstractType
{
protected $fname;
protected $lname;
protected $email;
protected $mobile;
protected $active;
protected $mentor;
protected $initialized;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('fname','text',array('label'=>'First Name'))
->add('lname','text',array('label'=>'Last Name'))
->add('email','email',array('label'=>'Email'))
->add('mobile','text',array('label'=>'Mobile'))
->add('active','choice',array(
'label'=>'Active?',
'choices'=>array('0'=>'No','1'=>'Yes'),
'expanded'=>true,
'multiple'=>false
))
->add('mentor','choice',array(
'label'=>'Mentor?',
'choices'=>array('0'=>'No','1'=>'Yes'),
'expanded'=>true,
'multiple'=>false
))
->add('Add Player?','submit');
}
public function getName()
{
return 'user';
}
public function setFname($fname)
{
$this->fname = $fname;
return $this;
}
public function getFname()
{
return $this->fname;
}
public function setLname($lname)
{
$this->lname = $lname;
return $this;
}
public function getLname()
{
return $this->lname;
}
public function setEmail($email)
{
$this->email = $email;
return $this;
}
public function getEmail()
{
return $this->email;
}
public function setMobile($mobile)
{
$this->mobile = $mobile;
return $this;
}
public function getMobile()
{
return $this->mobile;
}
public function setActive($active)
{
$this->active = $active;
return $this;
}
public function getActive()
{
return $this->active;
}
public function setMentor($mentor)
{
$this->mentor = $mentor;
return $this;
}
public function getMentor()
{
return $this->mentor;
}
public function setInitialized($initialized)
{
$this->initialized = $initialized;
return $this;
}
public function getInitialized()
{
return $this->initialized;
}
}
This is my validation.yml in bundle/Resources/config:
Brs\UserBundle\Form\Type\UserType:
properties:
fname:
- NotBlank: ~
- Length:
min: 3
lname:
- NotBlank: ~
- Length:
min: 3
email:
- NotBlank: ~
- Length:
min: 3
This is my controller that builds the form from the class and renders it renders fine:
<?php
namespace Brs\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
// use Symfony\Component\HttpFoundation\Response;
// use Brs\UserBundle\Entity\User;
use Brs\UserBundle\Form\Type\UserType;
class UserController extends Controller{
public function indexAction(Request $request){
$user = new UserType();
$form = $this->createForm(new UserType(),$user);
$form->handleRequest($request);
if($form->isValid()){
echo 'yes';
}
//print_r($user);
return $this->render(
'BrsUserBundle:User:userForm.html.twig',
array(
'title'=>"Add Player",
'form'=>$form->createView()
));
}
}
?>
In app/config/config.yml i have these params set for validation:
validation: { enabled: true, enable_annotations: false }
Now when I submit the form with no data the request hits the controller and the method
$form->isValid();
is called, this returns true.
This should return false as my constraints in my validation.yml file do not allow blank fields to be processed and should trigger the form to render the field errors within the template.
I am clearly missing something here, Any help would be greatly appreciated.
Thanks
Adam
You should not validate your UserType, but the User object itself. Also the second argument of createForm() needs to be a User object.
$user = new User();
$form = $this->createForm(new UserType(),$user);
validation.yml:
Brs\UserBundle\Entity\User:
properties:
# constraint list