I have a laravel app with passport installed to manage api auth. I'm trying to write some tests but I'm unable to create a Client as per the docs on laravel. I've googled similar SO answers but they all suggest using setUp and tearDown methods which I am doing. When I run the test I get
InvalidArgumentException
Unable to locate factory for [Laravel\Passport\Client].
How can I get this to work?
Below is my code. I have included the Client model from the passport package and I am using the setUp and tearDown methods as suggested in similar SO answers.
I've tried composer dump-autoload and php artisan config:cache.
use Laravel\Passport\Passport;
use Laravel\Passport\Client;
...
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
}
protected function tearDown(): void
{
parent::tearDown();
}
public function testAPIEndpointFailsWhenNoParamIsSet()
{
Passport::actingAsClient(
factory(Client::class)->create(),
['*']
);
$response = $this->postJson('/api/endpoint', [
'param' => ''
]);
$response->assertStatus(401)
->assertJson(['message' => 'Unauthenticated.']);
}
passport client factory should be existed on publishing ...
if it did not .... make it your self:
from : here
use Laravel\Passport\Passport;
use Laravel\Passport\Client;
$factory->define(Client::class, function (Faker $faker) {
return [
'user_id' => null,
'name' => $faker->company,
'secret' => Str::random(40),
'redirect' => $faker->url,
'personal_access_client' => 0,
'password_client' => 0,
'revoked' => 0,
];
});
Related
I have an issue with running migrations while making a test. I have migrations in different places. User migrations depend on Company migrations but each time I run tests I have an error that table 'companies' doesn't exist.
Code from test class:
protected function setUp()
{
parent::setUp();
$this->artisan('migrate', [
'--path' => ['Modules/Company/Database/Migrations',
'Modules/User/Database/Migrations'],
]);
}
protected function tearDown()
{
$this->artisan('migrate:reset', [
'--path' => ['Modules/User/Database/Migrations',
'Modules/Company/Database/Migrations'],
]);
parent::tearDown();
}
Can anyone help me, please.
Thanks!
Problem was in two places:
1) option --path was provided as an array(but no warnings are displayed);
2) command migrate:reset(it resets ALL the migrations using provided --path so the error 'Undefined index: create_company_table' happens).
Final version.
protected function setUp()
{
parent::setUp();
$this->artisan('migrate', [
'--path' => 'Modules/Company/Database/Migrations',
]);
$this->artisan('migrate', [
'--path' => 'Modules/User/Database/Migrations',
]);
}
protected function tearDown()
{
$this->artisan('migrate:rollback', [
'--path' => 'Modules/User/Database/Migrations/',
]);
$this->artisan('migrate:rollback', [
'--path' => 'Modules/Company/Database/Migrations/',
]);
parent::tearDown();
}
I'm trying to define a few different variations of a User model for testing, using Laravels ModelFactory as documented here
$factory->define(App\User::class, function(\Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'remember_token' => str_random(10),
'phone' => $faker->phoneNumber,
];
});
$factory->state(App\User::class, 'admin', function (Faker\Generator $faker) {
return [
'groups' => function(App\User $u) {
return App\Models\Group::where('level', '<=', 5)->get()->toArray();
}
];
});
And then I create a User model:
$user = factory(User::class)->states('admin')->make();
But phpunit seems to exit out of the test without complaining. In the PHP logs, I see:
Call to undefined method Illuminate\Database\Eloquent\Factory::state()
There isn't very much documentation on the state() method in Laravel docs, and I've searched and experimented for hours with no progress to show for it.
As a sidenote: the groups attribute is referring to a Many relationship. However, this Exception is thrown regardless of which model I am creating, even simple models.
After digging around in the Illuminate\Database\Eloquent\Factory and FactoryBuilder classes, I discovered that the state() and states() methods were both missing, compared to the latest Laravel branch on github. After running composer update, it updated me to Laravel Framework v5.3.18, and now the ModelFactory states work as expected.
So I definitely can't wrap my head around this one. I'm following a Laravel 5.2 tutorial here.
http://blog.damirmiladinov.com/laravel/laravel-5.2-socialite-facebook-login.html#.V2gUIrgrJPY
And getting the error listed above in the title. My routes look like this:
Route::get('/', function () {
if(Auth::check()) return view('auth/register');
return view('auth/login');
});
Route::get('/redirect', 'MailAuthController#redirect');
Route::get('/callback', 'MailAuthController#callback');
Controller looks like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Socialite;
class MailAuthController extends Controller
{
//
public function redirect()
{
return \Socialite::with('microsoft')->redirect();
}
public function callback()
{
// when microsoft calls with token
}
public function user()
{
}
}
And services.php looks like this:
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Stripe, Mailgun, Mandrill, and others. This file provides a sane
| default location for this type of information, allowing packages
| to have a conventional place to find your various credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
'mandrill' => [
'secret' => env('MANDRILL_SECRET'),
],
'ses' => [
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
],
'sparkpost' => [
'secret' => env('SPARKPOST_SECRET'),
],
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
'microsoft' => [
'client_id' => env('MICROSOFT_CLIENT_ID'),
'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
'redirect' => env('http://localhost:8000/callback'),
],
];
And other than that I have no idea where I might be going wrong. Light my way!
I would recommend using the Microsoft Graph provider from the Socialite Providers package.
Pull in the Microsoft-Graph provider via your composer.json file:
"require": {
...
"laravel/socialite": "^2.0",
"socialiteproviders/microsoft-graph": "dev-master"
},
Run composer update.
Next, add the connection credentials to config/services.php:
...
'graph' => [
'client_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'client_secret' => 'xxxxxxxxxxxxxxxxxxxxxxx',
'redirect' => 'https://my-app.dev',
],
*Note: if committing config/services.php to a public repo, extract these values to your .env file and reference them via the env helper method;
In config/app.php add the SocialiteProviders/Generators service provider to the providers array:
'providers' => [
...
/*
* Package Service Providers...
*/
Laravel\Socialite\SocialiteServiceProvider::class,
// This is a dependency of the socialiteproviders/microsoft-graph provider, and will be installed with the provider via it's composer.json file
SocialiteProviders\Manager\ServiceProvider::class,
Register the Socialize facade (also in config/app.php):
'aliases' => [
...
'Socialize' => 'Laravel\Socialite\Facades\Socialite',
],
Register an event listener in app/Providers/EventServiceProvider.php:
protected $listen = [
...
'SocialiteProviders\Manager\SocialiteWasCalled' => [
'SocialiteProviders\Graph\GraphExtendSocialite#handle'
],
];
Create your controller to handle the requests:
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use Socialize;
class AuthController extends \App\Http\Controllers\Controller
{
/**
* Redirect the user to the Graph authentication page.
*
* #return Response
*/
public function redirectToProvider()
{
return Socialize::with('graph')->redirect();
}
/**
* Obtain the user information from graph.
*
* #return Response
*/
public function handleProviderCallback(Request $request)
{
$user = Socialize::with('graph')->user();
// $user->token;
}
}
Finally add your routes in routes/web.php:
<?php
Route::get('auth/graph', 'Auth\AuthController#redirectToProvider');
Route::get('auth/graph/callback','Auth\AuthController#handleProviderCallback');
If anyone still arrives here with the same error, but using the SocialiteProviders Microsoft provider already:
Check if you have set up the library correctly.
Make sure to install socialiteproviders/microsoft from composer
Add the SocialiteProviders Manager to your config/providers.php: \SocialiteProviders\Manager\ServiceProvider::class
Add the event listener to your app/Providers/EventServiceProvider.php:
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
[SocialiteProviders\Microsoft\MicrosoftExtendSocialite::class, 'handle'],
],
The last step is important, and what caused the error for me, because I didn't understand the event listener is required (and not just an optional way to extend the provider).
So this might seem obvious but both in my case and judging from the info provided in the question, this step is also missing. I changed from the current Microsoft to the Graph and still got the same error, however I then realized this error happens when the Driver is not registered in the service provider. Make sure you are using the same spelling of the service provider in vendor and that you include the Service provider, in my case:
<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* #var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
// ... other providers
/*--- I forgot this --->*/\SocialiteProviders\Graph\GraphExtendSocialite::class.'#handle',
],
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
//
}
/**
* Determine if events and listeners should be automatically discovered.
*
* #return bool
*/
public function shouldDiscoverEvents()
{
return false;
}
}
This added worked with microsoft graph, driver: "graph" from: https://github.com/SocialiteProviders/Microsoft-Graph
I never got to try with the listed driver "Microsoft" on socialiteproviders.com
and as of the time of this writing Graph was removed from that website, however all I care is that it works and it worked as expected!
So I followed his readme and I have done composer dump-autoload a million times, but still I receive an error.
The code:
'providers' => [
...
Thujohn\Twitter\TwitterServiceProvider::class,
],
'aliases' => [
...
'Twitter' => Thujohn\Twitter\Facades\Twitter::class,
],
In my controller:
class HomeController extends Controller {
public function index() {
$tweets = Twitter::getUserTimeline([
'screen_name' => 'xxxxxxx',
'count' => 10,
'format' => 'json'
]);
dd($tweets);
return view('home');
}
public function about() {
return view('about');
}
}
But I get the error:
FatalErrorException in HomeController.php line 10:
Class 'App\Http\Controllers\Twitter' not found
Um ..... What?
You used non-namespaced name when you refered to Twitter class, so PHP is looking for the class in current namespace. Change that reference to \Twitter or add the following use statement:
use Twitter;
I'd like to keep users away from editing configuration files, so I've made web interface in admin panel for setting up Mail server, username, password, port, encryption..
I was working well in Laravel 4.2, but now when the app has been rewritten into Laravel 5, an error occurs:
Class 'Settings' not found in <b>F:\htdocs\app\config\mail.php</b> on line <b>18</b><br />
For this purpose I've created a service provider, made a facade, put them in config/app.php, Settings::get('var')/Settings::set('var') work perfectly, but not for mail settings.
config/mail.php:
<?php return array(
'driver' => Settings::get('mail_driver'),
'host' => Settings::get('mail_host'),
'port' => Settings::get('mail_port'),
'from' => array('address' => Settings::get('mail_from_address'), 'name' => Settings::get('mail_from_name')),
'encryption' => Settings::get('mail_encryption'),
'username' => Settings::get('mail_username'),
'password' => Settings::get('mail_password'),
'sendmail' => Settings::get('mail_sendmail'),
'pretend' => false,
);
config/app.php:
'providers' => [
...
'App\Providers\SettingsServiceProvider',
...
'aliases' => [
...
'Settings' => 'App\Custom\Facades\Settings',
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Custom\Settings;
class SettingsServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->singleton('settings', function()
{
return new Settings;
});
}
}
<?php namespace App\Custom;
use App\Setting;
class Settings {
public function get($var) {
try{
$setting = Setting::first();
} catch(exception $e)
{
return false;
}
return $setting->$var;
}
public function set($var, $val) {
try{
$setting = Setting::first();
$setting->$var = $val;
$setting->save();
} catch(exception $e)
{
return false;
}
return true;
}
}
<?php
namespace App\Custom\Facades;
use Illuminate\Support\Facades\Facade;
class Settings extends Facade {
protected static function getFacadeAccessor() { return 'settings'; }
}
Any ideas how to implement Laravel mail settings using database?
To archive this I created CustomMailServiceProvider by extending Illuminate\Mail\MailServiceProvider so as to overwrite this method:
protected function registerSwiftTransport(){
$this->app['swift.transport'] = $this->app->share(function($app)
{
return new TransportManager($app);
});
}
Here is the complete solution
I created CustomMailServiceProvider.php in app\Providers
namespace App\Providers;
use Illuminate\Mail\MailServiceProvider;
use App\Customs\CustomTransportManager;
class CustomMailServiceProvider extends MailServiceProvider{
protected function registerSwiftTransport(){
$this->app['swift.transport'] = $this->app->share(function($app)
{
return new CustomTransportManager($app);
});
}
}
I created CustomTransportManager.php in app/customs directory -
NB: app/customs directory doesn't exist in default laravel 5 directory structure, I created it
namespace App\Customs;
use Illuminate\Mail\TransportManager;
use App\Models\Setting; //my models are located in app\models
class CustomTransportManager extends TransportManager {
/**
* Create a new manager instance.
*
* #param \Illuminate\Foundation\Application $app
* #return void
*/
public function __construct($app)
{
$this->app = $app;
if( $settings = Setting::all() ){
$this->app['config']['mail'] = [
'driver' => $settings->mail_driver,
'host' => $settings->mail_host,
'port' => $settings->mail_port,
'from' => [
'address' => $settings->mail_from_address,
'name' => $settings->mail_from_name
],
'encryption' => $settings->mail_encryption,
'username' => $settings->mail_username,
'password' => $settings->mail_password,
'sendmail' => $settings->mail_sendmail,
'pretend' => $settings->mail_pretend
];
}
}
}
And finally, I replaced 'Illuminate\Mail\MailServiceProvider', in config/app.php with 'App\Providers\CustomMailServiceProvider',
I have added
$this->app['config']['services'] = [
'mailgun' => [
'domain' => $settings->mailgun_domain,
'secret' => $settings->mailgun_secret,
]
];
to CustomTransportManager __construct() to include mailgun API credentials that I'm using as mailing service
I configured as mentioned, however got the following error. While I tried your code found that from Laravel 5.4 share method is deprecated and instead informed to use singleton.
Call to undefined method Illuminate\Foundation\Application::share()
here is the below method using singleton instead using share method:
protected function registerSwiftTransport(){
$this->app->singleton('swift.transport', function ($app){
return new CustomTransportManager($app);
});
}
#DigitLimit , method share() has been dropped since Laravel 5.4. I had to work-around this problem using other methods, and I am not sure they are perfect. Here is my registerSwiftTransport() method in CustomMailServiceProvider class.
Firstly, we need to determine if code is not executed while calling app through command line: "if(strpos(php_sapi_name(), 'cli') === false)". If we don't check that and don't prevent setting new params in this case, Artisan will throw us errors in command line. Secondly, we need to get settings from database somehow. I did it using my method getSettingValue(), where first argument is setting key, and second argument is default value if setting is not found. As you see, I assigned settings to $this->app['config']['mail'].
After that, I used singleton() method:
protected function registerSwiftTransport(){
if (strpos(php_sapi_name(), 'cli') === false) {
$this->app['config']['mail'] = [
'driver' => Setting::getSettingValue('mail_driver', '****'),
'host' => Setting::getSettingValue('mail_host', '****'),
'port' => Setting::getSettingValue('mail_port', 25),
'from' => [
'address' => Setting::getSettingValue('mail_from_address', '****'),
'name' => Setting::getSettingValue('mail_from_name', '****'),
],
'encryption' => Setting::getSettingValue('mail_encryption', '***'),
'username' => Setting::getSettingValue('mail_username', '****'),
'password' => Setting::getSettingValue('mail_password', '****'),
];
}
$this->app->singleton('swift.transport', function ($app) {
return new Illuminate\Mail\TransportManager($app);
});
}