Cant get Beautymail to work for Laravel 5.2 - php

I'm trying to use Beautymail for my project to send a receipt after a customer ordered something. The problem is I'm using Beautymail in a function not in a route like their Documentation states.
This is how im using it in my function:
class OrderController extends Controller {
public function postOrder(Request $request) {
// More stuff here, shortned for question purposes
// Get an instance of the currently authenticated user
$user = Auth::user();
// Send email conformation to user that just bought a product or products.
$beautymail = app()->make(Snowfire\Beautymail\Beautymail::class);
$beautymail->send('emails.welcome', [], function($message) {
$message
->from('example#admin.com')
->to($user->email, $user->username)
->subject('Your Receipt');
});
// Then return redirect back with success message
flash()->success('Success', 'Your order was processed successfully. A receipt has been emailed to you');
return redirect()->route('cart');
}
}
And this is the error I get when I "Checkout":
Is there something I have to add? I already did my composer.json file along with adding it into the Providers Array, and publishing it to assets folder like in documentation.

$beautymail = app()->make(\Snowfire\Beautymail\Beautymail::class);
Note the \ before Snowfire\Beautymail\Beautymail::class.
Or, at the top of your controller:
use Snowfire\Beautymail\Beautymail;
and in your method you can have Laravel automatically resolve it through the IoC container, like:
public function postOrder(Request $request, Beautymail $beautymail)
{
$beautymail->send('emails.welcome', [], function($message) {
// etc...
}
Extra info on namespaces in PHP:
When you reference a class outside of use, you need to declare where the if your class is in the global namespace or not. So when you had:
app()->make(Snowfire\Beautymail\Beautymail::class);
without the leading \, PHP will assume you're looking for the requested with in the current namespace, which for you is \App\Http\Controllers.
By adding the leading \ you're telling PHP that the path to your class is relative to the global namespace.
Here's more info: http://php.net/manual/en/language.namespaces.basics.php

It looks like Snowfire\Beautymail\Beautymail::class is missing in your Laravel project. Have you installed as it mentions on https://github.com/Snowfire/Beautymail If you have not, please do so.

Related

Laravel 8 customise email verification link

I am writing an API using Laravel 8 .. I have followed the documentation for implementing email verification, but I want to modify the link that is sent with the email.
My API and Frontend are completely seperate, so the link that Laravel creates needs to be changed to point to my frontend.
I have implemented as per in my AuthServiceProvider;
public function boot(): void
{
$this->registerPolicies();
VerifyEmail::toMailUsing(function ($notifiable, $url) {
return (new MailMessage)
->subject('Verify Email Address')
->line('Click the button below to verify your email address.')
->action('Verify Email Address', $url);
});
}
I am working on localhost so please excuse the URL's .. But the URL that laravel outputs is as follows;
http://localhost/api/email/verify/217gd8b5b-1e23-4450-8b3b-a9c7610b16ed?expires=1625027126&hash=24499f2ba77786684dab8f4d71832d71d86be69e0&signature=e5ac2a5aa6c941ce36ef70d842d8efcea7ed79fc72597a1e44cd36c566fd71b34
I need to change that to something like;
http://localhost:3000/verifyemail/217gd8b5b-1e23-4450-8b3b-a9c7610b16ed?expires=1625027126&hash=24499f2ba77786684dab8f4d71832d71d86be69e0&signature=e5ac2a5aa6c941ce36ef70d842d8efcea7ed79fc72597a1e44cd36c566fd71b34
Is that possible at all?
Cheers,
As per the documentation, you need to set up a route with a specific naming convention; verification.verify.
You can add this route to your web routes like so:
Route::get('/verifyemail/{id}/{hash}', function () {
return;
})->name('verification.verify');
Laravel doesn't care that the actual frontend is detached for parsing the link.
Second, you need to verify the request via your API from your detached frontend. You need to forward the request to the API and use the Illuminate\Foundation\Auth\EmailVerificationRequest as the Request instance to fulfill the verification.
The following example is just a pseudo example, as this might require some tinkering depending on your frontend implementation, but you would hopefully get the idea. This route of course belongs to your api routes.
use Illuminate\Foundation\Auth\EmailVerificationRequest;
Route::get('/verifyemail/{id}/{hash}', function (EmailVerificationRequest $request) {
$request->fulfill();
// Just return a 201 (or 200 if it pleases you better)
return response()->json(null, 201);
// Don't use the verification.verify route name here
})->middleware(['auth', 'signed']);
That should do it.

Laravel 8 | Not hitting policy method

I am trying to define some policies in Laravel 8 which I cannot get to work, however I have the same project in Laravel 7 which seemingly works perfectly.
I am using the JSON API Specification package and it comes built in with Authorizers which allow me to run a policy on different methods.
I am trying to add a policy for the 'create' on all routes no matter what.
I have the following code:
public function create($type, $request)
{
$this->authorize('create', $type);
}
In this context and example, $type = 'App\Models\User' if I do a dd before that line I can confirm that I am hitting that method.
Inside of my AuthServiceProvider I have the following:
public function boot()
{
Gate::guessPolicyNamesUsing(function ($modelClass) {
return 'App\\Policies\\' . class_basename($modelClass) . 'Policy';
});
}
Which as said earlier, works perfectly in another project.
The following is my policy, as you can see it's very basic.
<?php
namespace App\Policies;
use App\Models\User;
class UserPolicy
{
public function create(User $user)
{
return true;
}
}
If I make a constructor in the policy class I can confirm that it is getting hit and I am getting inside of the policy which is why this is confusing me so much.
I have tried changing the name of the method in case it was something clashing with the naming convention but nothing seems to agree with it.
I have tried to dump composer just as a double check but again, no luck.
The issue with this is that there wasn't currently an authenticated user and although specified in the method parameters a user it was still failing.
When providing a guest route, you still need to add the parameter to the method but make it optional.
public function create(?User $user)
{
// do logic here
}
The documentation for this can be found at the following link: https://laravel.com/docs/master/authorization#guest-users

How can we redirect a page to another if a session is not found using route in Laravel 5.3

I am using a session separately other than the default authentication sessions. If an user try to access my secured page, he should have the session set. If anyone without that session try to access means, they will be redirected to error page. I am using Laravel 5.3
The user can view the below two pages only if the session variable named 'secured_user' is set. Otherwise they will be redirect to the error page
Route::get('/secured-page1', 'ValidationController#CheckSecuredLogin_1');
Route::get('/secured-page2', 'ValidationController#CheckSecuredLogin_2');
The best option would be a policy.
You can create certain constrains and couple it with your models. Policies are especially suitable for changing your logic later on.
See here: Create Policy
Within you PagesPolicy, you can add this function:
public function before(User $user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
public function seeSecurePage(User $user)
{
// Your custom Code and session handling
if(session("secured_user")) return true;
return false;
}
and in your controller.
$user->can("seeSecurePage","Pages");
If "can" fails, it will automatically redirect to error 403.
P.S.: Another possibility are Gates
You should use Laravel Middlewares to achieve this, I think middlewares are made for the work you need:
First create a new middleware by running the artisan command:
php artisan make:middleware CheckSesison
Then the CheckSession would look like this:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckSession
{
public function handle($request, Closure $next)
{
if ($session_value != 'YOUR_DESIRED_VALUE') {
return redirect('home');
}
return $next($request);
}
}
Now in your routes file you can use laravel's route middleware() method to implement it like this:
Route::get('/secured-page1', 'ValidationController#CheckSecuredLogin_1')
->middleware(CheckSession::class);
Hope this helps!
In addition to the awnser above, you could also use middleware that's used on the routes and even group them if required. It is a simple, quick and clean solution. Inside the middelware you simple check if the session you require is there and depending on the result you take any action necessary.
Laravel middleware docs

Laravel: simplest/right way to save a new step after login?

I'm having my first interaction with the core laravel code so I want to be careful not to break anything.
In my project, my users also correspond to person records (via user->person_id), so I have a get_person_from_user() function that takes the \Auth::user() (conveniently accessible anywhere) and returns the person object, so I can grab the person record for the authenticated user from any controller and pass it to a view.
The problem: there's a piece of data from the person record that I'd like to include in a nav partial in my default blade view (which gets extended by a bunch of different views), so it's the one case where I'm not going through a controller first. I'm unclear on how I can make the logged in user's person record available here. Any suggestions?
I think I need to add some step after the user logs in, to save the person record (globally? in the session?) so it's generally accessible. The login stuff happens in AuthenticatesUsers.php, and reading around it sounds like I'll want to add an override of postLogin to my AuthController.
But I tried copying that function from AuthenticatesUsers.php into my AuthController (not adding anything else to it yet), and AuthController gives me a new error when I try to log in:
ReflectionException in RouteDependencyResolverTrait.php line 81:
Class App\Http\Controllers\Auth\Request does not exist
Any advice on a good way to go about accessing the person object for the authenticated user, when I don't have a controller to pass it along?
You can setup the correct relationship on the User model to Person model.
public function person()
{
return $this->belongsTo(Person::class);
}
Then you can do:
Auth::user()->person;
For having a variable available to a particular view you can use a View Composer. (You can create and register a Service Provider and add this to the register method.) Potentially something like this:
view()->composer('someview', function ($view) {
if ($user = Auth::user()) {
$somevar = $user->person->somevar;
} else {
$somevar = null; // or some default
}
$view->with('somevar', $somevar);
});
If this view is also used in a scenario where someone doesn't have to be authed you will want to check if Auth::user() is null before trying to use the relationship.
Laravel Docs - Views - View Composers
I suggest you to use Eloquent relation
User.php
public function person()
{
return $this->belongsTo('NAMESPACE_TO_YOUR_MODEL\Person'); //also you can specify FK, more info in docs
}
then you can access Auth facade in your view
Auth::user()->person

Laravel get url's route name [duplicate]

In Laravel, we can get route name from current URL via this:
Route::currentRouteName()
But, how can we get the route name from a specific given URL?
Thank you.
A very easy way to do it Laravel 5.2
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1'))->getName()
It outputs my Route name like this slug.posts.show
Update: For method like POST, PUT or DELETE you can do like this
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST'))->getName()//reference https://github.com/symfony/http-foundation/blob/master/Request.php#L309
Also when you run app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST')) this will return Illuminate\Routing\Route instance where you can call multiple useful public methods like getAction, getValidators etc. Check the source https://github.com/illuminate/routing/blob/master/Route.php for more details.
None of the solutions above worked for me.
This is the correct way to match a route with the URI:
$url = 'url-to-match/some-parameter';
$route = collect(\Route::getRoutes())->first(function($route) use($url){
return $route->matches(request()->create($url));
});
The other solutions perform bindings to the container and can screw up your routes...
I don't think this can be done with out-of-the-box Laravel. Also remember that not all routes in Laravel are named, so you probably want to retrieve the route object, not the route name.
One possible solution would be to extend the default \Iluminate\Routing\Router class and add a public method to your custom class that uses the protected Router::findRoute(Request $request) method.
A simplified example:
class MyRouter extends \Illuminate\Routing\Router {
public function resolveRouteFromUrl($url) {
return $this->findRoute(\Illuminate\Http\Request::create($url));
}
}
This should return the route that matches the URL you specified, but I haven't actually tested this.
Note that if you want this new custom router to replace the built-in one, you will likely have to also create a new ServiceProvider to register your new class into the IoC container instead of the default one.
You could adapt the ServiceProvider in the code below to your needs:
https://github.com/jasonlewis/enhanced-router
Otherwise if you just want to manually instantiate your custom router in your code as needed, you'd have to do something like:
$myRouter = new MyRouter(new \Illuminate\Events\Dispatcher());
$route = $myRouter->resolveRouteFromUrl('/your/url/here');
It can be done without extending the default \Iluminate\Routing\Router class.
Route::dispatchToRoute(Request::create('/your/url/here'));
$route = Route::currentRouteName();
If you call Route::currentRouteName() after dispatchToRoute call, it will return current route name of dispatched request.

Categories