Initial migrate in laravel 5 with a reference in the ConfigServerProvider fails - php

In my ConfigServerProvider.php at boot there is a reference to the configs database table. At initial migrate this database table doesn't exist, so I am getting an error. How can I run the first time 'php artisan migrate', while leaving this boot line intact?
public function boot() {
config([
'version' => "1.0.2",
'title' => Config::where('name', 'title')->first()->pluck('value')
]);
}
I added this around the whole config:
if(Schema::hasTable('configs')) { }
And that seems to make all work.

In my app i made this:
try {
$configs = Config::all();
} catch (\Exception $e) {
$configs = [];
}

Related

Getting Error "Undefined type 'Laravel\Socialite\Facades\Socialite'.intelephense(1009)"

I'm getting this weird error. Although i have performed the required steps of installing the "Socialite" package , for instance i have edit the "providers" and "aliases" in "config/app.php". Thing is I'm using this in existing project, but when i created in fresh copy it was working fine.
Undefined type 'Laravel\Socialite\Facades\Socialite'.intelephense(1009)
Here is my controller code (Where i'm getting this error)
`// Google Registration
public function googleRedirect()
{
return Socialite::driver('google')->redirect();
}
public function loginWithGoogle()
{
try
{
$user = Socialite::driver('google')->user();
$existingUser = User::where('google_id',$user->id)->first();
if($existingUser)
{
Auth::login($existingUser);
return redirect('/home');
}
else{
$createUser = User::create([
$uuid = Str::uuid()->toString(),
'name' => $user->name,
'email' => $user->email,
'google_id' => $user->id,
]);
Auth::login($createUser);
return redirect('/timeline');
}
}
catch(\Throwable $th){
throw $th;
}
}
`
PS* I have already imported the required package on the top
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
I have followed all the required steps to install the socialite package, only problem that i'm facing is getting following error in controller:
Undefined type 'Laravel\Socialite\Facades\Socialite'.intelephense(1009)
PS* I'm using Laravel 9.
i review your code use Socialite::driver('google')->stateless()->user(); this instead of Socialite::driver('google')->user();
The main reason would that you forgot to include the classes in your class. But you did. Then i would try this two commands:
1. php artisan config:clear
2. composer dump-autoload

How to implement Laravel password validation rules as string in arrays?

I want to use the out-of-the-box Laravel password validation rules. This is possible by using the use Illuminate\Validation\Rules\Password class.
So you can use those rules like so:
\Illuminate\Validation\Rule\Password::min(8)->letters()->numbers()->mixedCase()->uncompromised(3)
However, you can't use those rules inside a config file, like in this package because you get the following error when running
artisan config:cache
❯ artisan config:cache > ─╯
Configuration cache cleared successfully.
LogicException
Your configuration files are not serializable.
at vendor/laravel/framework/src/Illuminate/Foundation/Console/ConfigCacheCommand.php:84
80▕ require $configPath;
81▕ } catch (Throwable $e) {
82▕ $this->files->delete($configPath);
83▕
➜ 84▕ throw new LogicException('Your configuration files are not serializable.', 0, $e);
85▕ }
86▕
87▕ $this->info('Configuration cached successfully.');
88▕ }
1 bootstrap/cache/config.php:859
Error::("Call to undefined method Illuminate\Validation\Rules\Password::__set_state()")
After reading the docs, it seems that you can't use those password rules as strings inside an array like so:
"password_rules" => ['min:8'],
So checking the available rules, the rest of the following rules (letters, mixedCase, uncompromised) are not available.
Then, is there a workaround to set those password rules inside the config file?
(so that, I can avoid the LogicException: Your configuration files are not serializable. after executing the artisan config:cache command).
use Illuminate\Validation\Rules\Password;
$rules = [
'password' => [
'required',
'string',
Password::min(8)
->mixedCase()
->numbers()
->symbols()
->uncompromised(),
'confirmed'
],
]
Try using the above code it should work.
I am not a Laravel person, but you can put the config into an array and then unpack it later in your app with something like this:
// for illustration
class Mock {
public function __call($name, $args) {
printf("called: %s(%s)\n", $name, implode(', ', $args));
return $this;
}
// this is awful. never do this.
// in Laravel the min() function, and only this function, is basically
// an alias to the constructor, which is weird.
public static function __callStatic($name, $args) {
return (new self())->$name(...$args);
}
}
$params = [
'min' => [8],
'letters' => [],
'numbers' => [],
'mixedCase' => [],
'uncompromised' => [3]
];
$o = NULL;
foreach( $params as $func => $args ) {
if( is_null($o) ) {
$o = Mock::$func(...$args);
} else {
$o = $o->$func(...$args);
}
}
Output:
called: min(8)
called: letters()
called: numbers()
called: mixedCase()
called: uncompromised(3)

How to properly handle Excepcion when creating new record in db throught Service-Repository pattern. [Laravel]

I am trying to use Service-Repository pattern for the first time in my Laravel app and I have to handle a situation: a record can´t be added to a table (for example because trying to add same unique email....).
I have CustomAuthCOntroller with customRegistration method:
//Validatting request
$request->validated();
//running logic behind this in service
$is_Registered = $this->loginService->register_user(
$request->get('email'),
$request->get('password'),
$request->get('name'),
$request->get('surname')
);
// If everything goes right shol login page
if ($is_Registered) {
return redirect("/login")->withSuccess('Registrácia prebehla úspešne');
} else {
// Else HERE I HAVE TO SHOW what error happened
return redirect("/register")->withError('Registrácia prebehla úspešne');
}
My LoginService->register_user:
public function register_user($email, $password, $firstname, $lastname, $role = 'student') {
$user_attributes = [
'email' => $email,
'password' => $password,
'name' => $firstname,
'surname' => $lastname,
];
$this->userRepositor->create_new_user($user_attributes);
}
And my userRepository->create_new_user:
public function create_new_user(Array $attributes) : bool
{
DB::beginTransaction();
try {
User::create($attributes);
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
}
}
Is this right way how to achieve my goal? How can I show the error in my view if a exception is thrown?
You should not have any problems as you should be validating your input, so if the email/username or whatever that should be unique does already exist, then the validation should fail and return automatically with the errors (no try/catch).
If, you still want to catch any other possible error, let's say the DB timed out because of a connection problem or whatever (something not related to data), then you could either have a general try/catch (as I will show you) or do not catch it at all and let it go to the user, but this last approach depends a lot in your frontend:
If you have an API, then JS should handle this and show the error correctly.
If this is not an API (no AJAX), then the error could be shown to the user as a 500 error (0% descriptive for the user and would be a blank page with a 500 on it).
So, if you want the try/catch approach, you could do this:
//Validatting request
$request->validated();
try {
//running logic behind this in service
$this->loginService->register_user(
$request->get('email'),
$request->get('password'),
$request->get('name'),
$request->get('surname')
);
// If everything goes right shol login page
return redirect("/login")->withSuccess('Registrácia prebehla úspešne');
} catch (Throwable $exception) {
// HERE I HAVE TO SHOW what error happened
// You can even add the exception error with $exception->getMessage()
return redirect("/register")->withError('Registrácia prebehla úspešne');
}
And then, change your create_new_user to either of these:
public function create_new_user(Array $attributes) : bool
{
DB::beginTransaction();
try {
User::create($attributes);
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
}
Or use DB::transaction(). It will automatically rollback and throw the exception. See the source code here and here.
public function create_new_user(Array $attributes) : bool
{
DB::transaction(function () use ($attributes) {
User::create($attributes);
});
}
One personal recommendatation, do not declare methods as kebab_case like create_new_user, follow the PSR standard and Laravel standard, it should be camelCase: createNewUser.

How to trigger laravel jobs failed() method when job fails?

Currently I'm calling task Report.php and generating report using generateReport() method. I have checked that the jobs have been executed using CLI command php artsan queue:listen. If anything goes wrong while calling Artisan::call() the error message will be displayed in terminal. So I want to catch the exception in failed() and I want to log the error into logs.
I have tried with try catch in handle() method but it's not catching the exception.
protected $options;
public function __construct($options)
{
$this->options = array_merge(
[
'task' => 'Report',
'do' => 'generateReport',
'limit' => '10000'
],
$options
);
}
public function handle()
{
Artisan::call('execute', [
'--task' => $this->options['task'],
'--do' => $this->options['do'],
'--parameters' => $this->options,
]);
}
public function failed()
{
//
}
How can I trigger the failed() and get the error into logs?
Artisan::call is actually just calling the execute console class so if you throw an Exception in there it should automatically end up in the failed method.
However, in 5.2 the Exception object is not passed to the failed method (this was added in 5.3).
Laravel 5.2
So if you need the Exception object passed to the failed method then you will need to do something like this in 5.2:
public function handle()
{
try {
Artisan::call('execute', [
'--task' => $this->options['task'],
'--do' => $this->options['do'],
'--parameters' => $this->options,
]);
} catch (\Exception $e) {
$this->failed($e)
}
}
public function failed(\Exception $e = null)
{
//handle error
}
Laravel 5.3+
In 5.3 the Exception is automatically passed to failed so your code would be like this:
public function handle()
{
Artisan::call('execute', [
'--task' => $this->options['task'],
'--do' => $this->options['do'],
'--parameters' => $this->options,
]);
}
public function failed(\Exception $e = null)
{
//handle error
}

Dingo/API when Unit Testing: The version given was unknown or has no registered routes

I built an API using dingo/api 0.10.0, Laravel 5.1 and lucadegasperi/oauth2-server-laravel": "^5.1".
All my routes work fine in Postman/Paw!
The problem appears when I try to test the API using PHPUnit.
This is part of my route-api.php file
<?php
$api = app('Dingo\Api\Routing\Router');
$api->version(['v1'], function ($api) {
$api->post('oauth/access_token', function () {
return response(
\LucaDegasperi\OAuth2Server\Facades\Authorizer::issueAccessToken()
)->header('Content-Type', 'application/json');
});
$api->group(['middleware' => ['oauth', 'api.auth']], function ($api) {
$api->post('/register', 'YPS\Http\Controllers\Api\UserController#register');
});
And this is my test file UserRegistrationTest.php
class UserRegistrationTest extends ApiTestCase
{
public function setUp()
{
parent::setUp();
parent::afterApplicationCreated();
}
public function testRegisterSuccess()
{
$data = factory(YPS\User::class)->make()->toArray();
$data['password'] = 'password123';
$this->post('api/register', $data, $this->headers)
->seeStatusCode(201)
->seeJson([
'email' => $data['email'],
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
]);
}
public function testRegisterMissingParams()
{
$this->post('api/register', [], $this->headers, $this->headers, $this->headers)->seeStatusCode(422);
}
}
The ApiTestCase simply retrieves a token and sets the headers.
private function setHeaders()
{
$this->headers = [
'Accept' => 'application/vnd.yps.v1+json',
'Authorization' => 'Bearer ' . $this->OAuthAccessToken,
];
}
Now, the weird part is that the first test testRegisterSuccess runs perfectly and returns the response I expect. But the second one testRegisterMissingParams, even though it's the same route, returns this,
array:2 [
"message" => "The version given was unknown or has no registered routes."
"status_code" => 400
]
I tracked the error and it is in the Laravel adapter here:
public function dispatch(Request $request, $version)
{
// it seems that the second time around can't find any routes with the key 'v1'
if (! isset($this->routes[$version])) {
throw new UnknownVersionException;
}
$routes = $this->mergeExistingRoutes($this->routes[$version]);
$this->router->setRoutes($routes);
return $this->router->dispatch($request);
}
And further more, if i run one test at a time (eg comment one out, run test and then comment the other and run test) i see the result expected in both tests. The problem is when i run multiple tests.
Any thoughts on that?
Thank you!
Run php artisan api:routes to see full path you may have missed something for the URL, also if this working if you request your URL manually?
I had same problem with testing using Dingo & Lumen. This worked for me - remove bootstrap="bootstrap/app.php" from phpunit.xml file and change line processIsolation="false" to processIsolation="true".

Categories