I have a models with custom rules of validation, In every model I have variable $rules:
public static $rules = [...];
https://medium.com/#konafets/a-better-place-for-your-validation-rules-in-laravel-f5e3f5b7cc
I want use these rules in custom request:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class ModelRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return Auth::check() ? true : false;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return static::$rules;
}
}
I get error:
Access to undeclared static property: App\Http\Requests\ModelRequest::$rules
In controller:
public function store(ModelRequest $request)
{
...
}
This is globally. I need get instance of model, but how?
If you've put the $rules variable in your model you can't access it like this, because static refers to the class you are currently in.
Try this out:
Notice: I assume that your models are under the App name space
// In your model class
class YourModel extends Model{
const RULES=[];
}
//Then in your request class
class ModelRequest extends FormRequest
{
public function rules()
{
return App\YourModel::RULES;
}
}
Related
I'm using Laravel 5.3 and I'm trying to get the authenticated user's id in the constructor method so I can filter the user by assigned company as follows:
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\View;
use App\Models\User;
use App\Models\Company;
use Illuminate\Support\Facades\Auth;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests ;
public $user;
public $company;
public function __construct()
{
$companies = Company::pluck('name', 'id');
$companies->prepend('Please select');
view()->share('companies', $companies);
$this->user = User::with('profile')->where('id', \Auth::id())->first();
if(isset($this->user->company_id)){
$this->company = Company::find($this->user->company_id);
if (!isset($this->company)) {
$this->company = new Company();
}
view()->share('company', $this->company);
view()->share('user', $this->user);
}
}
However this doesn't return the user id. I've even tried Auth::check() and it doesn't work.
If I move the Auth::check() out of the __construct() method then this works as follows:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
dd(\Auth::check());
return view('home');
}
}
However this fails if I put this in the construct method in the HomeController too!
Any ideas why this is failing?
docs
you can't access the session or authenticated user in your
controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly
in your controller's constructor. Before using this feature, make sure
that your application is running Laravel 5.3.4 or above:
class ProjectController extends Controller
{
/**
* All of the current user's projects.
*/
protected $projects;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->projects = Auth::user()->projects;
return $next($request);
});
}
}
Since 5.3 Auth::check will not work in a controller's construtor, it's one of undocumented changes. So, you need to move it to middleware or do check in controller methods instead or move project to 5.2.x.
It fails because you call $this->middleware('auth'); after parent::__construct();. It means that you auth middleware is not loaded properly.
I have a StripeClient service provider which needs a key to instantiate:-
namespace App\Providers;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
use Stripe\StripeClient;
class StripeServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(StripeClient::class, function ($app) {
return new StripeClient(config('services.stripe.secret'));
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return [StripeClient::class];
}
Then a trait with a bunch of api call functions like this:-
trait StripeClientTrait
{
protected $stripe;
function __construct(StripeClient $stripeClient)
{
$this->stripe = $stripeClient;
}
/**
* #param User $user
*
* #return \Stripe\Customer
* #throws \Stripe\Exception\ApiErrorException
*/
function createCustomer(User $user)
{
return $this->stripe->customers->create([ 'name' => $user->fullname,
'email' => $user->email
]);
}
...
The trait works in a controller perfectly as expected:-
class SubscriptionContoller extends Controller
{
use StripeClientTrait;
public function checkout()
{
try {
$customer = $this->createCustomer(Auth::user());
if($checkoutSession = $this->createCheckoutSession($customer)) {
return redirect($checkoutSession->url);
}
} catch (ApiErrorException $ex){
Log::error($ex->getMessage());
return back()->with(['error'=>$ex->getMessage()]);
}
return back();
}
...
But I now need to use the trait in a model to provide access to some api functions.
class Company extends Tenant
{
use HasFactory, StripeClientTrait;
but adding the trait causes:-
Too few arguments to function App\Models\Company::__construct(), 0 passed in /home/vagrant/code/profiler/vendor/spatie/laravel-multitenancy/src/Models/Concerns/UsesTenantModel.php on line 13 and exactly 1 expected
Can anyone tell me how to implement the trait without using the constructor? I just need some static function helpers to lookup stuff on the API.
Thanks for any guidance :-)
having persevered I've found this way to use the service container in a model:-
public function getPrices()
{
$stripe = app(StripeClient::class);
return $stripe->prices->all(['active'=>true]);
}
But would still like to understand how to use the trait in the model, if anyone could explain I'd be grateful
I'm trying to implement multiple controllers which listens to one route /account.
There are two controllers and only one should be executed on that URL where the choice lies within user's role.
namespace AppBundle\Controller;
use AppBundle\Entity\Role;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;
/**
* #Route("/account")
*/
abstract class DashboardController extends Controller
{
protected $userRoles;
public function __construct()
{
$this->userRoles = $this->getUser()->getRoles();
}
/**
* Get all user roles
*/
public function getRoles()
{
return $this->userRoles;
}
/**
* Get user account type
*
* #return Role
*/
public function getAccountType(): Role
{
$accountType = new Role();
foreach ($this->userRoles as $role) {
if(Role::ROLE_STUDENT == $role->getName()) {
$accountType = $role;
} else if(Role::ROLE_SCHOOL_REPRESENTATIVE == $role->getName()) {
$accountType = $role;
} else if(Role::ROLE_EMPLOYER == $role->getName()) {
$accountType = $role;
} else if(Role::ROLE_ADMIN == $role->getName()) {
$accountType = $role;
}
}
return $accountType;
}
}
namespace AppBundle\Controller;
class CompanyDashboardController extends DashboardController
{
public function __construct()
{
parent::__construct();
}
/**
* #Route("/", name="dashboard_company_home", methods={"GET"})
* #return Response
*/
public function index()
{
return $this->render('dashboard/company/index.html.twig');
}
}
namespace AppBundle\Controller;
class AdminDashboardController extends DashboardController
{
public function __construct()
{
parent::__construct();
}
/**
* #Route("/", name="dashboard_admin_home", methods={"GET"})
* #return Response
*/
public function index()
{
return $this->render('dashboard/admin/index.html.twig');
}
}
That's what I've got so far.
You can't do this with "route" declarations, since the route listener is executed with higher priority than the security listener. Both happen during the KernelEvents::REQUEST event, but routing comes before firewall.
When the route to controller mapping is being resolved, you do not have yet user information (which is why you can't simply attach another a listener and inject the user information on the Request object, so it's available to use in the route declaration for expression matching, for example).
Basically, one route, one controller. If you want to have diverging logic for these users, you'll have to apply it after you get into the controller.
I am writing a general policy which which will apply on multiple Models. How can I retrieve the class name of the class which needs to be authorized?
Policies:
protected $policies = [
'App\User' => 'App\Policies\ModelPolicy',
'App\Customer' => 'App\Policies\ModelPolicy',
];
The ModelPolicy:
class ModelPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
}
public function index(User $user){
// how can I retrieve the class name, like User or Customer?
return true;
}
}
This is for example my customer controller. So in the policy I want to retrieve something like: App\Customer.
class CustomerController extends Controller
{
public function index(){
$this->authorize('index', Customer::class);
echo "test";
}
}
You'll need custom gates.
In your controller:
$this->authorize('model-index', Appointment::first());
In AuthServiceProvider:
Gate::define('model-index', function ($user, $model) {
var_dump(get_class($model));
die();
});
This way you can take the parameters you need for your authorization methods.
Please see
https://laravel.com/docs/5.5/authorization#gates
Laravel Policies - How to Pass Multiple Arguments to function
I'm using Laravel 5.3 and I'm trying to get the authenticated user's id in the constructor method so I can filter the user by assigned company as follows:
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\View;
use App\Models\User;
use App\Models\Company;
use Illuminate\Support\Facades\Auth;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests ;
public $user;
public $company;
public function __construct()
{
$companies = Company::pluck('name', 'id');
$companies->prepend('Please select');
view()->share('companies', $companies);
$this->user = User::with('profile')->where('id', \Auth::id())->first();
if(isset($this->user->company_id)){
$this->company = Company::find($this->user->company_id);
if (!isset($this->company)) {
$this->company = new Company();
}
view()->share('company', $this->company);
view()->share('user', $this->user);
}
}
However this doesn't return the user id. I've even tried Auth::check() and it doesn't work.
If I move the Auth::check() out of the __construct() method then this works as follows:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
dd(\Auth::check());
return view('home');
}
}
However this fails if I put this in the construct method in the HomeController too!
Any ideas why this is failing?
docs
you can't access the session or authenticated user in your
controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly
in your controller's constructor. Before using this feature, make sure
that your application is running Laravel 5.3.4 or above:
class ProjectController extends Controller
{
/**
* All of the current user's projects.
*/
protected $projects;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->projects = Auth::user()->projects;
return $next($request);
});
}
}
Since 5.3 Auth::check will not work in a controller's construtor, it's one of undocumented changes. So, you need to move it to middleware or do check in controller methods instead or move project to 5.2.x.
It fails because you call $this->middleware('auth'); after parent::__construct();. It means that you auth middleware is not loaded properly.