Trying Multiple User Auth, it keep saying wrong instance of argument passed - laravel-5.7

I'm getting this error while trying to log in multiple users with guards and unable to understand what instance it needs to be passed:
Argument 1 passed to
Illuminate\Auth\EloquentUserProvider::validateCredentials() must be an
instance of Illuminate\Contracts\Auth\Authenticatable, instance of
App\Employs given, called in /var/www/html/crmproject/vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php on line 379
This is my Auth Controller:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
class EmploysLoginController extends Controller
{
use AuthenticatesUsers;
protected $guard = 'Employs';
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/Employs';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function showLoginForm()
{
return view('auth.employe-login');
}
public function login(Request $request)
{
if (auth()->guard('Employs')->attempt(['email' => $request->email, 'password' => $request->password])) {
dd(auth()->guard('Employs')->user());
}
return back()->withErrors(['email' => 'Email or password are wrong.']);
}
}
This is my Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Authenticatable;
// use Illuminate\Contracts\Auth\Authenticatable as
AuthenticatableContract;
class Employs extends Model// implements AuthenticatableContract
{
protected $primaryKey = 'employ_id';
}
i tried many solution provided online/stackoverflow but i'm constantly getting this error, and if you find this question has ambiguity please ask before doing down vote i'm trying this out last time here.

You should create a model like this:
Model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Employs extends Authenticatable
{
use Notifiable;
protected $guard = 'Employs';
/**
* 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',
];
}
I hope this work for you.

Related

Symfony/ Api platorm/JWT get the current user after login

Good morning to all
Please i need help. I am using JWT Authentication and all works well.But my problem is to retreive the current user after the login. I saw in the documentation that i can create a controller to do so, but after doing that i get the error of id parameter not given.
Here is my controller related to the user entity
// api/src/Controller/GetMeAction.php
namespace App\Controller;
use App\Entity\User;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
class GetMeAction
{
/**
* #param Security
*/
private $_security;
public function __construct(Security $security)
{
$this->_security = $security;
}
/**
* #Route(
* name="get_me",
* path="get/me",
* methods={"GET"},
* defaults={
* "_api_resource_class"=User::class,
* "_api_item_operation_name"="get_me"
* }
* )
*/
public function __invoke(Request $request): User
{
return $this->_security->getUser();
}
}
Im using symfony 5.3, i wanted to use the api platform normalization and the item operation "get" to keep all the custom config, security, services, ...
So I used the forward() method in a controller :
/**
* #Route("/api/user/me", name="get_me")
*/
public function getMe(): Response
{
$router = $this->get('router')->getRouteCollection()->get('api_users_get_item');
$defaults = $router->getDefaults();
return $this->forward($router->getDefault('_controller'), array_merge($defaults, [ 'id' => $this->getUser()->getId()]));
}
Previous answer is right, but you forgot to Extend you controller from abstract one:
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class AdminController extends AbstractController
{
}
If you want to get User in the service, you can Inject Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface in your __construct()
and you can get user like:
public function getUser(): ?User
{
$token = $this->tokenStorage->getToken();
if (!$token) {
return null;
}
$user = $token->getUser();
if (!$user instanceof User) {
return null;
}
return $user;
}

How to return specific data using urls and routing in symfony 4 when making an API GET request?

I'm new to Symfony and trying to learn the basics. I recently saw this question and I wanted to learn how routing works. So I copied the Controller1.php from the question and changed it to UserController.php this:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class UsersController extends AbstractController
{
/**
* #Route("/listOf/Users", methods={"GET"})
* #param Request $request
* #return JsonResponse
*/
public function list(Request $request)
{
if (empty($request->headers->get('api-key'))) {
return new JsonResponse(['error' => 'Please provide an API_key'], 401);
}
if ($request->headers->get('api-key') !== $_ENV['API_KEY']) {
return new JsonResponse(['error' => 'Invalid API key'], 401);
}
return new JsonResponse($this->getDoctrine()->getRepository('App\Entity\User')->findAll());
}
}
Which indeed, as OP claims, works fine and return the following (manually added data using Sequel Pro) list:
[
{
"id": 14,
"name": "user1 Name"
},
{
"id": 226,
"name": "user2 Name"
},
{
"id": 383,
"name": "user3 Name"
}
]
So my next step was to learn how to adjust this list of users to return a specific user with a given id. So I followed the official Symfony Docs on Routing. So I changed the code to the following:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class UsersController extends AbstractController
{
/**
* #Route("/listOf/Users/{IdUser}", requirements={"IdUser"="\d+"}, methods={"GET"})
* #param Request $request
* #param int $IdUser
* #return JsonResponse
*/
public function list(Request $request, int $IdUser)
{
if (empty($request->headers->get('api-key'))) {
return new JsonResponse(['error' => 'Please provide an API_key'], 401);
}
if ($request->headers->get('api-key') !== $_ENV['API_KEY']) {
return new JsonResponse(['error' => 'Invalid API key'], 401);
}
return new JsonResponse($this->getDoctrine()->getRepository('App\Entity\User\{IdUser}')->findAll());
}
}
and tried to request the data of the user with the id 14, but this didn't work and yielded the following error:
Class App\Entity\User{IdUser} does not exist (500 Internal Server Error)
What more changes do I need to do to be able to do what I'm trying to do?
This is my User.php entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User implements \JsonSerializable
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function jsonSerialize()
{
return get_object_vars($this);
}
}
And my UserRepository.php has nothing beside the automatically generated code in it.
Edit: My first request which worked was of the form: http://domainName.local:80/listOf/Users and my second one was: http://domainName.local:80/listOf/Users/14
As promised earlier - here's why it does not work and how to make it work.
Let's examine the code blow:
$this->getDoctrine()->getRepository('App\Entity\User\{IdUser}')->findAll();
Basically you're saying: doctrine, give me the repository that is responsible for handling
the entity App\Entity\User\{IdUser} literally and ofc there is no such entity class.
What you really want is the repo for App\Entity\User.
The string you pass to the getRepository() method always has to be the fully qualified class name of an entity - period.
To ensure you never have any typos here, it's quite helpful to use the class constant of the entity, which looks like so
$repo = $this->getDoctrine()->getRepository(App\Entity\User::class);
Once you have the repository, you can call it's different methods as shown in the doctrine documentation here https://www.doctrine-project.org/api/orm/latest/Doctrine/ORM/EntityRepository.html
In your case, you have the variable $IdUser, which you want to be mapped to the db column/entity property id of the user class.
Since you know that you want exactly this one user with the id 14, all you have to do is tell the repo to find exactly one which looks like this.
// here's the example for your specific case
$user = $repo->findOneBy(['id' => $IdUser]);
// another example could be e.g. to search a user by their email address
$user = $repo->findOneBy(['email' => $email]);
// you can also pass multiple conditions to find*By methods
$user = $repo->findOneBy([
'first_name' => $firstName,
'last_name' => $lastName,
]);
Hopefully, this was more helpful than confusing =)

Testion controler method in symfony (phpUnit)

i need some help i want to write a unit test about a controler method , i have searched for examples and tested a lot of method's but none of them has worked:
Here is my controller:
class ComputerController extends Controller
{
/**
* #Route("/list-computers.html", name="back_computer_list")
* #return RedirectResponse|Response
*/
function listComputerAction()
{
$ad = $this->get("ldap_service");
$computers = $ad->getAllComputer();
return $this->render('BackBundle:Computer:list.html.twig', array(
"computers" => $computers,
));
}
I have tried to test it with mock like this:
class ComputerController extends Controller
{
/**
* #var EngineInterface
*/
private $templating;
public function setTemplating($templating)
{
$this->templating = $templating;
}
and i have created a test method:
class ComputerControllerTest extends TestCase {
public function testlistComputerAction(){
$templating = $this->getMockBuilder('BackBundle\Controller\ComputerController')->getMock();
$computers = [1,2];
$templating->expects($this->once())
->method('render')
->with('BackBundle:Computer:list.html.twig', array(
"computers" => $computers))
->will($this->returnValue( $computers));
$controller = new ComputerController();
$controller->setTemplating($templating);
$this->assertEquals('success', $controller->listComputerAction());
}
When i start executing phpunit , i have this warning"Trying to configure method "render" which cannot be configured because it does not exist, has not been specified, is final, or is static"
I would be thankful if someone has an idea about this
I tried to Test a method in ldapService : Here is the method's of the service that i want to test
/**
* #return bool|resource
*/
public function getLdapBind()
{
if (!$this->ldapBind) {
if ($this->getLdapConnect()) {
$this->ldapBind = #ldap_bind($this->ldapConnect, $this->ldapUser, $this->ldapPass);
}
}
return $this->ldapBind;
}
/**
* #param $ldapUser
* #param $password
* #return bool
*/
function isAuthorized($ldapUser, $password)
{
$result = false;
if ($this->ldapConnect) {
$result = #ldap_bind($this->ldapConnect, $ldapUser, $password);
}
return $result;
}
Here is the test (using Mock):
<?php
namespace BackBundle\Tests\Service;
use PHPUnit\Framework\TestCase;
use BackBundle\Service\LdapService;
use PHPUnit_Framework_MockObject_InvocationMocker;
class LdapServiceTest extends TestCase {
public function testgetLdapConnect()
{
// $LdapService = new LdapService();
$ldapMock = $this->getMockBuilder( 'LdapService')->setMethods(['getLdapBind'])->disableOriginalConstructor()->getMock();
$ldapMock->expects($this->once())
// ->method()
->with(array('ldap_bind', 'mike', 'password'))
->will($this->returnValue(true));
$ldapMock->isAuthorized('mike', 'password');
}
}
But i have a warning that i can't resolve : "Method name matcher is not defined, cannot define parameter matcher without one"
If someone , has an idea about that please
Honestly, there is nothing useful to test in that three-line controller. #1 is the service container, and #3 is the Twig subsystem. Line #2 can be unit tested on it's own.
With more complex controllers, I have found that making them a service where all the dependencies are passed in, either by constructor, or into the action itself does make slightly more complex controllers quite easy, but very few need that anyway.

Laravel - Emails not including data when sent via Queue

I'm trying to set up a Contact Form and all is going well. Set up my Controller with ->send(), all works fine (takes a bit of time). When I set it up to work with ->queue(), seems to work fine (no delay), job is set up, mail is sent when I dispatch. But this time my mail template does not include the data sent to the Mailer.
My Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Mail\Contact;
use Illuminate\Support\Facades\Mail;
class PagesController extends Controller
{
public function sendContact(Request $request)
{
Mail::to('webform#email.com')
->queue(new Contact($request));
return redirect('/contact')->with('status', 'Message sent. Thanks!');
}
}
My Mailer (App\Mail\Contact):
class Contact extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Build the message.
*
* #return $this
*/
public function build(Request $request)
{
$subject = 'Web Message from: ' . $request->name;
return $this->from('myemail#email.com')
->subject($subject)
->view('emails.contact-template')
->with([
'name' =>$request->name,
'email' => $request->email,
'message' => $request->message,
'date' => $request->date,
]);
}
}
The problem was that I needed to declare the variables as public. Below is the solution that eventually worked:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Http\Request;
use Illuminate\Contracts\Queue\ShouldQueue;
class Contact extends Mailable
{
use Queueable, SerializesModels;
public $request;
public $name;
public $from;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(Request $request)
{
$this->request = $request->all();
$this->name = $request->name;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$subject = 'Webform messsage from: ' . $this->name;
$from = 'webform#mail.com';
return $this
->from( $from )
->subject($subject)
->view('emails.contact-template');
}
}

Validation of fields not present in form but in Entity

I have a form for user registration, and only username field is present in the form. And in my form, I wish to allow user input the username only. Nicename would be same as username on registration.
This form is bind to a User entity, i.e., in my form type class:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Some\Bundle\Entity\User',
));
}
entity User, which has a NotBlank constraint set for both username and nicename.
namespace Some\Bundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Constraints;
//...
class User
{
//...
/**
* #var string $username
*
* #ORM\Column(name="user_login", type="string", length=60, unique=true)
* #Constraints\NotBlank()
*/
private $username;
/**
* #var string $nicename
*
* #ORM\Column(name="user_nicename", type="string", length=64)
* #Constraints\NotBlank()
*/
private $nicename;
//...
However, if I build a form with only username but not nicename, on validation i.e. $form->isValid() it fails to validate.
To bypass this, I come up with the following:
namespace Some\Bundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Some\Bundle\Form\Type\RegisterType;
//...
class UserController extends Controller
{
//...
public function registerAction()
{
//...
$request = $this->getRequest();
$form = $this->createForm(new RegisterType());
if ($request->getMethod() == 'POST') {
// force set nicename to username.
$registerFields = $request->request->get('register');
$registerFields['nicename'] = $registerFields['username'];
$request->request->set('register', $registerFields);
$form->bind($request);
if ($form->isValid()) {
$user = $form->getData();
//persist $user, etc...
And in form type I add this to my buildForm method:
$builder->add('nicename', 'hidden');
But I find this very inelegant, leave some burden to the controller (extract from the request object, put in data, and put it back into the request object, ouch!), and user can see the hidden field if he were to inspect the source code of generated HTML.
Is there anyway that can at least any controller using the form type does not need do things like above, while retaining the entity constraints?
I cannot change the table schema which backs up the User entity, and I would like to keep the NotBlank constraint.
EDIT: After long hassle, I decided to use Validation groups and it worked.
class User
{
//...
/**
* #var string $username
*
* #ORM\Column(name="user_login", type="string", length=60, unique=true)
* #Constraints\NotBlank(groups={"register", "edit"})
*/
private $username;
/**
* #var string $nicename
*
* #ORM\Column(name="user_nicename", type="string", length=64)
* #Constraints\NotBlank(groups={"edit"})
*/
private $nicename;
Form Type:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Some\Bundle\Entity\User',
'validation_groups' => array('register', 'Default')
));
}
That 'Default' is needed or it ignores all other constraints I added in the form type buildForm method... Mind you, its case sensitive: 'default' does not work.
Though, I find that it is not enough (and sorry I didn't put it in my original question), because when I persist, I need to do this in my controller:
$user->setNicename($user->getUsername());
As a bonus, I move this from controller to Form Type level by adding a Form Event Subscriber
In form type buildForm method:
$builder->addEventSubscriber(new RegisterPostBindListener($builder->getFormFactory()));
And the RegisterPostBindListener class
<?php
namespace Some\Bundle\Form\EventListener;
use Symfony\Component\Form\Event\DataEvent;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
class RegisterPostBindListener implements EventSubscriberInterface
{
public function __construct(FormFactoryInterface $factory)
{
}
public static function getSubscribedEvents()
{
return array(FormEvents::POST_BIND => 'setNames');
}
public function setNames(DataEvent $event)
{
$data = $event->getData();
$data->setNicename($data->getUsername());
}
}
I think you should use validation groups.
In your User entity you can tell which field can be nullable:
/**
*#ORM\Column(type="string", length=100, nullable=TRUE)
*/
protected $someVar;
This way your view controllers don't need to do anything.
Forgot to mention. You can also define a PrePersist condition that initialises your nicename variable:
// you need to first tell your User entity class it has LifeCycleCallBacks:
/**
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks()
*/
class User
{
...
/**
*#ORM\PrePersist
*/
public function cloneName()
{
$this->nicename = $this->username;
}
}
In this case, you should use a Callback assertion to create a custom validation rule.

Resources