I have added a controller for my package and I need to call Auth methods inside the constructor of this controller but I get the following error :
ReflectionException in Container.php line 734:
Class hash does not exist
Here is my code :
use Auth;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Session;
class CartController extends Controller
{
private $customer;
public function __construct()
{
$this->middleware('auth', ['except' => ['add']]);
$multiauth = config('cart.multiauth');
if ($multiauth) {
$guard = config('auth.defaults.guard');
$this->customer = Auth::guard($guard)->user();
} else {
$this->customer = Auth::user();
}
}
public function add()
{
// Code
}
}
When I add the code of constructor inside the other functions it works properly but it fails when it is called from constructor of the controller.
I have searched alot for this and found no working solution.
I've solved the problem by adding a middleware :
namespace myNamespace\myPackage;
use Closure;
use Illuminate\Support\Facades\Auth;
class CustomerMiddleware
{
public function handle($request, Closure $next)
{
$multiauth = config('cart.multiauth');
if ($multiauth) {
$guard = config('auth.defaults.guard');
$customer = Auth::guard($guard)->user();
} else {
$customer = Auth::user();
}
$request->attributes->add(['customer' => $customer]);
return $next($request);
}
}
Then I used this middleware for the 'cart/add' route :
Route::group(['middleware' => ['web']], function () {
Route::group(['middleware' => 'customer'], function() {
Route::post('cart/add',
'myNamespace\myPackage\CartController#add');
});
});
So by checking the $request->get('customer') parameter inside the 'add' method of 'CartController', I have access to information of current user :
class CartController extends Controller
{
public function __construct() { }
public function add()
{
$customer = $request->get('customer');
// Code
}
}
I hope this helps someone else :)
You can't use middleware in controller __construct , create a functions and use it
Related
I'm new to laravel and to php oop. My main goal is to call createLogs() everytime a function is called without putting the call method in each function because it's a hassle. I need help please.
I made a controller called WebLogs with a function called createLogs() that inserts data to a table. I want it to be auto-called whenever another function is called. I tried using this solution and put it in Controller class because WebLogs extends Controller class, and all my other controllers extends Controller class, but the solution doesn't seem to work.
So my Controller class now looks like this:
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
// Added this function from the solution I mentioned
public function __call($method, $arguments) {
echo 'hello world';
echo '<br><br>';
echo $method;
if(method_exists($this, $method)) {
return call_user_func_array(array($this,$method),$arguments);
}
}
}
Example controller:
class DashboardController extends Controller
{
public function index()
{
(new WebLogs)->createLogs(); //I don't want to call this for every function
return view('dashboard');
}
public function showSomething()
{
(new WebLogs)->createLogs();
return view('something');
}
public function updateSomething()
{
(new WebLogs)->createLogs();
return redirect()->back()->with('message','yeey');
}
}
How the functions from DashboardController are being called from web.php:
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
Route::get('/something', [DashboardController::class, 'showSomething'])->name('something');
Route::post('/something/update', [DashboardController::class, 'updateSomething'])->name('something.update');
Create app\Classes\WebLogs.php with content:
<?php
namespace App\Classes;
class WebLogs {
public function __construct() {
return "WebLogs class with construct function was initialized.";
}
public function createLogs($routeName,$routePath) {
$status = 0;
logger('WebLogs class is running:');
logger([$routeName,$routePath]);
// Save to database here
// ...
return $status;
}
}
Then, create an AutoCreateLogs middleware, it will save as app\Http\Middleware\AutoCreateLogs.php:
$ php artisan make:middleware AutoCreateLogs
With content:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Classes\WebLogs;
class AutoCreateLogs
{
public function handle(Request $request, Closure $next)
{
$route = Route::current();
$routePath = $route->uri;
$routeName = $route->action['as'];
$w = new WebLogs;
$w->createLogs($routeName,$routePath);
return $next($request);
}
}
And use this middleware like this:
Route::middleware([AutoCreateLogs::class])->group(function () {
Route::get('/', [App\Http\Controllers\DashboardController::class, 'index'])->name('dashboard');
Route::get('/something', [App\Http\Controllers\DashboardController::class, 'showSomething'])->name('something');
Route::post('/something/update', [App\Http\Controllers\DashboardController::class, 'updateSomething'])->name('something.update');
Route::get('/something/{value}', [App\Http\Controllers\DashboardController::class, 'getSomething'])->name('get.something');
});
With app\Http\Controllers\DashboardController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DashboardController extends Controller
{
public function index()
{
$page = 'index';
return view('welcome', ['page'=>$page]);
}
public function showSomething()
{
$page = 'showSomething';
return view('welcome', ['page'=>$page]);
}
public function updateSomething()
{
$page = 'updateSomething';
return response()->json(['page'=>$page]);
}
public function getSomething(Request $request)
{
$page = 'getSomething';
return view('welcome', ['page'=>$page]);
}
}
Then, empty storage\logs\laravel.log, and run with example route
http://laravel-me.com/something/value99
It will show the successful result:
[2022-02-18 22:56:09] local.DEBUG: WebLogs class is running:
[2022-02-18 22:56:09] local.DEBUG: array (
0 => 'get.something',
1 => 'something/{value}',
)
Read more about middleware: https://laravel.com/docs/8.x/middleware
What I want to do is to get the a User's activation status before running any methods and redirect if they're not active. Here's my code:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class HomeController extends BaseController
{
public function __construct(){
parent::__CONSTRUCT();
$this->middleware('auth');
//SEE IF ACTIVE, something like auth()->user()->active
}
public function home()
{
return redirect('/home');
}
}
Look at the comment on the last line of the constructor, how do I do that?
From 5.3 onwards, you can't directly access session info in a controllers constructor. You can, though, define a Closure based middleware directly in your controller's constructor. More info in the docs
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
if(Auth::user()->active) {
return Redirect::route('activate');
}
return $next($request);
});
}
First of all, I already check that in other controller (not in resource controller) my session work very well, but when I did it in the resource controller my code for get session didn't work.
Here's my resource controller
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
//tambahan
use DB;
use Session;
//model
use App\_admins;
use App\Mahasiswas;
class MahasiswaController extends Controller
{
protected $data;
protected $token;
public function __contruct(){
$this->data = array();
$this->middleware(function ($request, $next) {
$this->token = $request->session()->get('_admin_id');
if (!$request->session()->has('_admin_id')) {
abort(404);
}
return $next($request);
});
}
private function user($token){
$this->data['query'] = _admins::find($token);
}
public function index(){
echo $this->token;
}
There is more public function, but it's still empty so I am not showing it here to avoid confusion. And here is my route in web.php:
Route::group(['namespace' => 'Admin'],function(){
Route::resource('/admin/mahasiswa','MahasiswaController');
Route::resource('/admin/nilai','NilaiController');
});
In 5.3 the middleware hasn't run yet in the constructor, so you're unable to gather session data. But using your closure-based approach, you should be able to access it with something like this:
$this->middleware(function($request, $next) {
// Get the session value (uses global helper)
$this->token = session('_admin_id');
// If the value is null, abort the request
if (null === $this->token) abort(404);
return $next($request);
});
I am using Laravel 5.3 My ForgotPasswordController looks like that:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Base\BaseController;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends BaseController
{
use SendsPasswordResetEmails;
public function __construct()
{
$this->middleware('guest');
}
public function showLinkRequestForm()
{
$title = $this->title;
$appName = $this->appName;
$action = $this->action;
return view('password.forgotPassword')->with(compact('title', 'appName', 'action'));
}
}
ResetPasswordController code :
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Base\BaseController;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends BaseController
{
use ResetsPasswords;
public function __construct()
{
$this->middleware('guest');
}
public function showResetForm(Request $request, $token = null)
{
return view('passwords.resetPassword')->with(
['token' => $token, 'email' => $request->email]
);
}
public function reset(Request $request)
{
$this->validate($request, [
'token' => 'required',
'password' => 'required|confirmed|min:6',
]);
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
}
My Admin Route :
Route::group(['namespace' => 'Auth'], function() {
Route::get('/forgotpassword/reset', 'ForgotPasswordController#showLinkRequestForm');
Route::post('/forgotpassword/email', 'ForgotPasswordController#sendResetLinkEmail');
Route::get('/password/reset/{token}', 'ResetPasswordController#showResetForm');
Route::post('/password/reset', 'ResetPasswordController#reset');
});
BaseController Code :
<?php
namespace App\Http\Controllers\Base;
use App\Http\Controllers\Controller;
class BaseController extends Controller
{
protected $appName = 'Stackoverflow';
protected $title = 'Welcome to Stackoverflow';
protected $action;
}
I can send the link to my email, but once I click the link/button.
It throws an error like above. Any idea ?
You are not using the required namespace, try to use the following in your controller:
use Illuminate\Http\Request;
You are getting the error due to the fact that your script tries to load the Request class from the current namespace :App\Http\Controllers\Auth
Request docs for Laravel 5.3
I am about $this->close() to giving up on Mockery in my unit tests. Here's what's going on, I am working with Laravel 5.1 and I'm trying to test my repository pattern abstraction using Mockery in PHPUnit. I've followed the tutorials, poured over the StackOverflow questions so it's not a duplicate. When you see anything about modules here, it's PingPong Sky Modules package.
Basically, when I try to mock the repository interface and set shouldReceive('create')->with([])->once() , Mockery throws:
Mockery\Exception\InvalidCountException: Method create(array()) from Mockery_0_Modules_Documents_Repositories_DocumentRepositoryInterface should be called exactly 1 times but called 0 times.
DocumentsTest.php
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
class FileUploadTest extends TestCase {
use WithoutMiddleware;
public function mock($class){
$mock = Mockery::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
public function testFileUpload(){
// Mock the Repository
$mock = $this->mock('\Modules\Documents\Repositories\DocumentRepositoryInterface');
$mock->shouldReceive('create')->with([])->once();
$this->call('POST', '/documents', [], [], []);
$this->assertResponseStatus(201);
}
}
DocumentRepositoryInterface.php
<?php namespace Modules\Documents\Repositories;
interface DocumentRepositoryInterface {
public function create(array $data);
}
DatabaseDocumentRepository.php
<?php namespace Modules\Documents\Repositories;
use Modules\Documents\Repositories\DocumentRepositoryInterface;
use \Illuminate\Database\Eloquent\Model;
class DatabaseDocumentRepository implements DocumentRepositoryInterface {
protected $documents;
public function __construct(Model $documents) {
$this->documents = $documents;
}
public function create(array $data) {
// Eloquent code.
return "response";
}
}
Document.php
<?php namespace Modules\Documents\Entities;
use Illuminate\Database\Eloquent\Model;
class Document extends Model {
protected $fillable = [];
}
routes.php
$this->app->bind(
'Modules\Documents\Repositories\DocumentRepositoryInterface', function(){
return new Modules\Documents\Repositories\DatabaseDocumentRepository(new Modules\Documents\Entities\Document());
});
Route::group(['prefix' => 'documents', 'namespace' => 'Modules\Documents\Http\Controllers'], function(){
Route::post('/', ['as' => '/', 'uses'=> 'DocumentsController#create']);
});
DocumentsController.php
<?php namespace Modules\Documents\Http\Controllers;
use Modules\Documents\Repositories\DocumentRepositoryInterface;
use Pingpong\Modules\Routing\Controller;
use Module;
use Illuminate\Http\Response;
use Illuminate\Http\Request;
class DocumentsController extends Controller {
private $documents;
public function __construct(DocumentRepositoryInterface $doc){
$this->documents = $doc;
}
public function create(Request $request){
$this->documents->create([]);
return response("", Response::HTTP_CREATED);
}
}
I want to say it has something to do with the mocked object not getting injected into the DocumentsController because the create() function is getting called. I put a print_r in the create function and it displayed in my console. This is strange and it could also be related to PingPong Sky Modules. What am I doing wrong or not doing?