I have this annoying message in my test after updating PhpStorm.
The error says:
Trait method 'beginDatabaseTransaction' will not be applied, because it collides with 'RefreshDatabase'
Why PhpStorm ignores insteadof ?
I there any way to disable this or fix it?
Thanks.
This is the whole test:
<?php
namespace Tests\Feature\Auth\User;
use App\Application\Traits\RefreshDatabaseTransactionLess;
use App\Domain\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Hash;
use Tests\TestCase;
class LoginUserTest extends TestCase
{
use RefreshDatabase, DatabaseMigrations, RefreshDatabaseTransactionless {
RefreshDatabaseTransactionless::beginDatabaseTransaction insteadof RefreshDatabase;
}
protected function postLoginRoute()
{
return route('auth.user.login');
}
public function testUserCanLogin()
{
$password = 'password';
$user = factory(User::class)->create([
'email' => 'test#test.com',
'password' => Hash::make($password)
]);
$response = $this->post($this->postLoginRoute(), [
'email' => $user->email,
'password' => $password
]);
$response->assertSuccessful();
$response->assertJsonStructure([
'token',
'type',
'expires'
]);
}
}
If you are running PhpStorm 2019.3, it's a bug from the new inspection introduced in this release: https://youtrack.jetbrains.com/issue/WEB-43949.
Under certain circumstances the inspection appears to ignore the insteadof keyword.
This is fixed as of (approx) today. Update your IDEs and it should work.
Related
Just playing around with laravel-8 unit tests. I extended the basic TestCase and thought laravels factory method would be available. I checked the composer.json and the factories are being loaded.
I am trying to run this particular test but factory is not found any ideas:
<?php
namespace Tests\Feature\Http\Controllers\Auth;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\User;
class LoginControllerTest extends TestCase
{
use RefreshDatabase;
/** #test */
public function login_authenticates_and_redirects_user()
{
$user = factory(User::class)->create();
$response = $this->post(route('login'), [
'email' => $user->email,
'password' => 'password'
]);
$response->assertRedirect(route('home'));
$this->assertAuthenticatedAs($user);
}
}
The error I am getting is:
1) Tests\Feature\Http\Controllers\Auth\LoginControllerTest::login_authenticates_and_redirects_user
Error: Call to undefined function Tests\Feature\Http\Controllers\Auth\factory()
On laravel 8 models are at 'App\Models\'.
It changes how factory works. See at docs.
So, it should be like:
<?php
namespace Tests\Feature\Http\Controllers\Auth;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\Models\User;
class LoginControllerTest extends TestCase
{
use RefreshDatabase;
/** #test */
public function login_authenticates_and_redirects_user()
{
$user = User::factory->create();
$response = $this->post(route('login'), [
'email' => $user->email,
'password' => 'password'
]);
$response->assertRedirect(route('home'));
$this->assertAuthenticatedAs($user);
}
}
Turns out in upgrading to laravel-8 release notes:
https://laravel.com/docs/8.x/upgrade#seeder-factory-namespaces
"Laravel's model factories feature has been totally rewritten to support classes and is not compatible with Laravel 7.x style factories."
So in order to make it work I used:
$user = \App\Models\User::factory(User::class)->make();
This described in the class Laravel\Fortify\Http\Requests\LoginRequest
I want to add one more validation line
namespace Laravel\Fortify\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Laravel\Fortify\Fortify;
class LoginRequest extends FormRequest
{
/..
public function rules()
{
return [
Fortify::username() => 'required|string',
'password' => 'required|string',
];
}
}
But I cannot do the customizations in the vendor.
My question is how to do this?
Just to add to the comment above, it's a bad idea to make changes in the vendor folder as stated earlier. For one, any code pushes to a repository will not reflect these changes (unless you modify the ignore file).
For Laravel/Fortify adding new fields and changing the default validation rules, even the password requirements is very straightforward. It's not clear to me what your requirement is, but it might be easier to simply use a Validator. That is what Fortify uses as well. For example, Fortify publishes two files:
App\Actions\Fortify\CreateNewUser.php
App\Actions\Fortify\PasswordValidationRules.php
To add a new validation rule for a field, simply add it the CreateNewUser.php under the Validator::make method that Fortify itself is using. You can follow the same logic in your custom implementation. For example to add a firstname field, modify as follows:
Validator::make($input, [
'firstname' => ['required', 'string', 'max:255'],
])->validate();
return User::create([
'firstname' => $input['firstname'],
]);
You can add as many field as you want. To change the password requirements, make changes to the passwordRules() function in the PasswordValidationRules.php file as follows:
protected function passwordRules()
{
return ['required',
'string',
(new Password)->requireUppercase()
->length(10)
->requireNumeric()
->requireSpecialCharacter(),
'confirmed'];
}
All this info can be found at the official docs https://jetstream.laravel.com/1.x/features/authentication.html#password-validation-rules
In short, I solved the problem like this
copy vendor\laravel\fortify\src\Http\Controllers\AuthenticatedSessionController.php to
app\Http\Controllers\Auth\LoginController.php (change namespace and class name)
copy vendor\laravel\fortify\src\Http\Requests\LoginRequest.php to app\Http\Requests\LoginFormRequest.php (change namespace and class name)
add new route in routes/web.php
use App\Http\Controllers\Auth\LoginController;
//
Route::post('/login', [LoginController::class, 'store'])
->middleware(array_filter([
'guest',
$limiter ? 'throttle:'.$limiter : null,
]));
in LoginController changed LoginRequest to LoginFormRequest and
public function store(LoginFormRequest $request)
{
return $this->loginPipeline($request)->then(function ($request) {
return app(LoginResponse::class);
});
}
in LoginFormRequest add my new rule(s)
public function rules()
{
return [
Fortify::username() => 'required|string',
'password' => 'required|string',
'myNewRule' => 'required|string',
];
}
Here's how you can use your own validation rules when authenticating with Fortify:
Create a file LoginRequest.php in App\Http\Requests that extends Fortify's LoginRequest.php class
I would just copy that class and update the namespace:
namespace App\Http\Requests;
use Laravel\Fortify\Http\Requests\LoginRequest as FortifyLoginRequest;
use Laravel\Fortify\Fortify;
class LoginRequest extends FortifyLoginRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
Fortify::username() => 'required|string',
'password' => 'required|string',
'myAttribute' => 'rules' // Customizations...
];
}
}
Add a binding in your AppServiceProviders.php boot method to resolve Fortify's class with your own:
public function boot()
{
$this->app->bind('Laravel\Fortify\Http\Requests\LoginRequest', \App\Http\Requests\LoginRequest::class);
}
I've found that page: https://dev.to/aibnuhibban/login-customization-in-laravel-8-2gc8
Go to vendor > laravel > fortify > src > Rule > Password.php
There you can change those config.
I'm getting below error when trying login with google or Facebook.
Argument 1 passed to Illuminate\Auth\Guard::login() must implement
interface Illuminate\Contracts\Auth\Authenticatable, null given
i'm using socialite package for laravel. what is the problem, i'm unable to solve it.i'm first time using laravel Socialite package
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Laravel\Socialite\Facades\Socialite;
class RegisterController extends Controller
{
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'user_type' => 'user',
'active_status' => '1'
]);
}
public function redirectToProvider()
{
return Socialite::driver('facebook')->redirect();
}
public function handleProviderCallback()
{
try{
$socialuser = Socialite::driver('facebook')->stateless()->user();
}
catch(exception $e){
return redirect('/');
}
$user=User::where('facebook_id',$socialuser->getid())->first();
if(!$user)
User::create([
'facebook_id'=>$socialuser->getid(),
'email'=>$socialuser->getemail(),
'name'=>$socialuser->getname(),
]);
auth()->login($user);
return redirect()->to('/dashboard');
}
}
Please help me.i'm a beginner.
Thanks
Check your User model make sure it implements Authenticable. I'd guess it currently extends Model but doesn't use Authenticable. Post it here to let use confirm it looks ok.
Hey guys I'm trying to learn PHP frameworks as well as OOP and I'm using Laravel 5.1 LTS.
I have the following code in my AuthController
<?php
namespace App\Http\Controllers\Auth;
use App\Verification;
use Mail;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
private $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest', ['except' => 'getLogout']);
}
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
protected function create(array $data){
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
// generate our UUID confirmation_code
mt_srand((double)microtime()*15000);//optional for php 4.2.0 and up.
$charid = strtoupper(md5(uniqid(rand(), true)));
$uuid = substr($charid, 0, 8)
.substr($charid, 8, 4)
.substr($charid,12, 4)
.substr($charid,16, 4)
.substr($charid,20,12);
$data['confirmation_code'] = $uuid;
// pass everything to the model here
$setVerification = new Verification();
$setVerification->setVerificationCode($data['email'], $data['confirmation_code']);
// send email for confirmation
Mail::send('email.test', $data, function ($m) use ($data){
$m->from('test#test.com', 'Your Application');
$m->to($data['email'])->subject('Thanks for register! Dont forget to confirm your email address');
});
return $user;
}
}
my error message Class 'Models\Verification' not found is coming from this piece of code here
// pass everything to the model here
$setVerification = new Verification();
$setVerification->setVerificationCode($data['email'], $data['confirmation_code']);
which looks right to my beginner's eyes, but it's clearly wrong.
Here is my Verification class that has the setVerificationCode method
<?php
namespace App\Http\Controllers;
use App\User;
use DB;
use App\Http\Controllers\Controller;
class Verification {
/**
* This method will update the confirmation_code column with the UUID
* return boolean
**/
protected function setVerificationCode($email, $uuid) {
$this->email = $email;
$this->uuid = $uuid;
// check to see if $email & $uuid is set
if (isset($email) && isset($uuid)) {
DB::table('users')
->where('email', $email)
->update(['confirmation_code' => $uuid]);
return TRUE;
} else {
return FALSE;
}
}
/**
* This method will validate if the UUID sent in the email matches with the one stored in the DB
* return boolean
**/
protected function verifyConfirmationCode() {
}
}
Please give the following in AuthController
use App\Http\Controllers\Verification;
instead of
use App\Verification;
If we give use App\Verification , it will check if there is any model named Verification.
its seems that, you are missing something, which, Extend your Model with eloquent model
use Illuminate\Database\Eloquent\Model;
class Verification extends Model
{
and the rest is seems fine.
also share your verification model code
Updated
instead of your this line
use App\Verification;
do this
use App\Models\Verification;
as you created custom directory for your Models then its better to auto load it in your composer.json file. add this line "app/Models" in your "autoload" section. follow this
"autoload": {
"classmap": [
"database",
"app/Models"
],
and after that, run this command in your project repo composer dump-autoload
I'm building a package in Laravel 4 but am getting a non-object error when attempting to access the db from which seems to be a properly instantiated object. Here's the setup:
The config and class in question:
composer.json:
...
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php"
],
"psr-0": {
"Vendor\\Chat": "src/vendor/chat/src"
}
}
...
The class:
namespace Vendor\Chat;
use Illuminate\Database\Eloquent\Model as Eloquent;
class ChatHistory extends Eloquent
{
protected $table = 'chat_history';
protected $fillable = array('message', 'user_id', 'room_token');
public function __construct($attributes = array())
{
parent::__construct($attributes);
}
}
The call:
$message = new Message($msg);
$history = new ChatHistory;
$history->create(array(
'room_token' => $message->getRoomToken(),
'user_id' => $message->getUserId(),
'message' => $message->getMessage(),
));
The error:
PHP Fatal error: Call to a member function connection() on a non-object in /home/vagrant/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 2894
I believe I'm missing something fundamental and under my nose. Thanks for any and all help!
EDIT:
Here is the class that's instantiating ChatHistory and calling the write:
namespace Vendor\Chat;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Vendor\Chat\Client;
use Vendor\Chat\Message;
use Vendor\Chat\ChatHistory;
use Illuminate\Database\Model;
class Chat implements MessageComponentInterface {
protected $app;
protected $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn)
{
$client = new Client;
$client->setId($conn->resourceId);
$client->setSocket($conn);
$this->clients->attach($client);
}
public function onMessage(ConnectionInterface $conn, $msg)
{
$message = new Message($msg);
$history = new ChatHistory;
ChatHistory::create(array(
'room_token' => $message->getRoomToken(),
'user_id' => $message->getUserId(),
'message' => $message->getMessage(),
));
/* error here */
/* ... */
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
$conn->close();
}
protected function getClientByConn(ConnectionInterface $conn)
{
foreach($this->clients as $client) {
if($client->getSocket() === $conn) {
return $client;
}
}
return null;
}
}
The fact that DB isn't available suggest that Eloquent isn't being loaded up top?
Answer:
Bootstrap your package in your service provider's boot method.
Explanation:
Since you're developing a package to be used with Laravel, there's no point in making your own Capsule instance. You can just use Eloquent directly.
Your problem seems to stem from DB/Eloquent not being set up yet by the time your code hits it.
You have not shown us your service provider, but I'm guessing you're using one and doing it all in the register method.
Since your package depends on a different service provider (DatabaseServiceProvider) to be wired up prior to its own execution, the correct place to bootstrap your package is in your service provider's boot method.
Here's a quote from the docs:
The register method is called immediately when the service provider is registered, while the boot command is only called right before a request is routed.
So, if actions in your service provider rely on another service provider already being registered [...] you should use the boot method.
In case you're working with Lumen, you may occur identical problem. In this case just uncomment:
// $app->withFacades();
// $app->withEloquent();
in bootstrap\app.php
#matpop and #TonyStark were on the right track: Capsule\Manager wasn't being booted.
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule;
$capsule->addConnection([
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'project',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
]);
// Set the event dispatcher used by Eloquent models... (optional)
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;
$capsule->setEventDispatcher(new Dispatcher(new Container));
// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();
// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
$capsule->bootEloquent();
I am able to extend Eloquent after booting. I think another solution might be along the lines of (but not tested):
include __DIR__ . '/../../vendor/autoload.php';
$app = require_once __DIR__ . '/../../bootstrap/start.php';
$app->boot();
What i did was simple, i just forgot to uncomment $app->withFacades();
$app->withEloquent(); in my bootstrap/app.php.
Now works fine
Try including the DB facade as well as Eloquent...
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Model as Eloquent;
...and then see if you have access to DB::table('chat_history').
(Also note that in your class, your call to use Illuminate\Database\Model; should be Illuminate\Database\Eloquent\Model; )
you must use
$capsule->`bootEloquent`();
in database.php / after your connection.
this is your full codes:
<?php
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule;
$capsule->`addConnection`([
'driver' => `'mysql'`,
'host' => 'localhost',
'database' => 'test1',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => '',
]);
$capsule->`bootEloquent`();
<?php
namespace App\Providers;
use App\Setting;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
Schema::defaultStringLength(191);
$settings = Setting::all();
foreach ($settings as $key => $settings) {
if($key === 0) $system_name = $setting->value;
elseif($key === 1) $favicon = $setting->value;
elseif($key === 2) $front_logo = $setting->value;
elseif($key === 3) $admin_logo = $setting->value;
}
$shareData = array(
'system_name'=>$system_name,
'favicon'=>$favicon,
'front_logo'=>$front_logo,
'admin_logo'=>$admin_logo
);
view()->share('shareData',$shareData);
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
}