#Multiple Table Auth Laravel
Explore tagged Tumblr posts
Text
How a Web Development Company Builds Scalable SaaS Platforms
Building a SaaS (Software as a Service) platform isn't just about writing code—it’s about designing a product that can grow with your business, serve thousands of users reliably, and continuously evolve based on market needs. Whether you're launching a CRM, learning management system, or a niche productivity tool, scalability must be part of the plan from day one.
That’s why a professional Web Development Company brings more than just technical skills to the table. They understand the architectural, design, and business logic decisions required to ensure your SaaS product is not just functional—but scalable, secure, and future-proof.
1. Laying a Solid Architectural Foundation
The first step in building a scalable SaaS product is choosing the right architecture. Most development agencies follow a modular, service-oriented approach that separates different components of the application—user management, billing, dashboards, APIs, etc.—into layers or even microservices.
This ensures:
Features can be developed and deployed independently
The system can scale horizontally (adding more servers) or vertically (upgrading resources)
Future updates or integrations won’t require rebuilding the entire platform
Development teams often choose cloud-native architectures built on platforms like AWS, Azure, or GCP for their scalability and reliability.
2. Selecting the Right Tech Stack
Choosing the right technology stack is critical. The tech must support performance under heavy loads and allow for easy development as your team grows.
Popular stacks for SaaS platforms include:
Frontend: React.js, Vue.js, or Angular
Backend: Node.js, Django, Ruby on Rails, or Laravel
Databases: PostgreSQL or MongoDB for flexibility and performance
Infrastructure: Docker, Kubernetes, CI/CD pipelines for automation
A skilled agency doesn’t just pick trendy tools—they choose frameworks aligned with your app’s use case, team skills, and scaling needs.
3. Multi-Tenancy Setup
One of the biggest differentiators in SaaS development is whether the platform is multi-tenant—where one codebase and database serve multiple customers with logical separation.
A web development company configures multi-tenancy using:
Separate schemas per tenant (isolated but efficient)
Shared databases with tenant identifiers (cost-effective)
Isolated instances for enterprise clients (maximum security)
This architecture supports onboarding multiple customers without duplicating infrastructure—making it cost-efficient and easy to manage.
4. Building Secure, Scalable User Management
SaaS platforms must support a range of users—admins, team members, clients—with different permissions. That’s why role-based access control (RBAC) is built into the system from the start.
Key features include:
Secure user registration and login (OAuth2, SSO, MFA)
Dynamic role creation and permission assignment
Audit logs and activity tracking
This layer is integrated with identity providers and third-party auth services to meet enterprise security expectations.
5. Ensuring Seamless Billing and Subscription Management
Monetization is central to SaaS success. Development companies build subscription logic that supports:
Monthly and annual billing cycles
Tiered or usage-based pricing models
Free trials and discounts
Integration with Stripe, Razorpay, or other payment gateways
They also ensure compliance with global standards (like PCI DSS for payment security and GDPR for user data privacy), especially if you're targeting international customers.
6. Performance Optimization from Day One
Scalability means staying fast even as traffic and data grow. Web developers implement:
Caching systems (like Redis or Memcached)
Load balancers and auto-scaling policies
Asynchronous task queues (e.g., Celery, RabbitMQ)
CDN integration for static asset delivery
Combined with code profiling and database indexing, these enhancements ensure your SaaS stays performant no matter how many users are active.
7. Continuous Deployment and Monitoring
SaaS products evolve quickly—new features, fixes, improvements. That’s why agencies set up:
CI/CD pipelines for automated testing and deployment
Error tracking tools like Sentry or Rollbar
Performance monitoring with tools like Datadog or New Relic
Log management for incident response and debugging
This allows for rapid iteration and minimal downtime, which are critical in SaaS environments.
8. Preparing for Scale from a Product Perspective
Scalability isn’t just technical—it’s also about UX and support. A good development company collaborates on:
Intuitive onboarding flows
Scalable navigation and UI design systems
Help center and chatbot integrations
Data export and reporting features for growing teams
These elements allow users to self-serve as the platform scales, reducing support load and improving retention.
Conclusion
SaaS platforms are complex ecosystems that require planning, flexibility, and technical excellence. From architecture and authentication to billing and performance, every layer must be built with growth in mind. That’s why startups and enterprises alike trust a Web Development Company to help them design and launch SaaS solutions that can handle scale—without sacrificing speed or security.
Whether you're building your first SaaS MVP or upgrading an existing product, the right development partner can transform your vision into a resilient, scalable reality.
0 notes
Text
Laravel 5.5 Multi Authentication - 5 Make Reset Password for Custom guard Part 1
Laravel 5.5 Multi Authentication – 5 Make Reset Password for Custom guard Part 1
[ad_1]
File Project: https://github.com/weeework/laravel55multiauth
The last stage of creating custom auth using multiple tables is using the password forgot feature provided by Laravel. This section we make the display forgot password and send email in the form of link. then in the next video will discuss the process of resetting the password.
====================================================…
View On WordPress
#Cus...#Custom Authentication Laravel 5.5#laravel#laravel 5.5#Laravel 5.5 For Beginner#Multi Auth#Multiple Table Auth Laravel#PHP Framework 2017#PHP Tutorial 2017
0 notes
Text
Laravel VII: Abbreviated | Web Development - Yudiz Solutions Pvt. Ltd.
Overview:
Hello there. As we all know the Laracon Online 2020, the largest online Laravel conference, took place on 26 February 2020. Our developer happened to attend a Laracon Online Viewing Party and according to his experience we are going to share with you the highlights. We’re going to focus on Laravel 7 here. Yes, it’s here and stick till the end to know all about it.

So as most of you might know Taylor Otwell was one of the speakers at the event. He gave us a complete walkthrough for Laravel VII and we are going to cover most of it here.
What is Laravel Airlock?
Airlock is a lightweight Token Generation and verification tool (Provides Authentication) mostly for SPAs (Single Page Applications), where users can generate multiple API tokens and like passport, we can set the roles for particular auth token.
AirLock will work with Laravel 6.x, but everyone recommends using it with Laravel 7.x and you also need to use Laravel UI 2.x for UI files.
We can set allowed domain in config file, so if a request comes from that particular server then and only then that request gets served. So we can say airlock is a similar kind of structure like a passport but it’s for SPA.
For better understanding,we can compare AirLock mechanism with Node/Angular project where frontend API will use AuthToken. Authtoken is similar kind of personal access token which we are used in the passport for mobile authentication
Key features of AirLock:
EncryptCookies
AddQueuedCookiesToResponse
StartSession
VerifyCsrfToken
Laravel Custom Casts:
In Laravel VII, we can create our own casting for an eloquent model, there are two methods, “get()” and “set()”
“get()” method is used to convert raw data into casted data.
“set()” method is used to convert casted data into raw data value.
For example, if we need to decode data when we receive it and encode data when we save details, we can use these methods like this:
Syntax for “get()” method:
public function get($model, $key, $value, $attributes) {
return json_decode($value, true);
}
Syntax for “set()” method:
public function set($model, $key, $value, $attributes) {
return json_encode($value, true);
}
For eloquent we need to define detail as:
protected $casts = [
'column_name' => Json::class,
];
So now every time we fetch data of a column, we get JSON decoded data and when the data is saved to the column it will get encoded.
HTTP Client:
HTTP Client is used for making an HTTP request from one website to another website or web application. For HTTP client you have to install guzzlehttp/guzzle package into your project. We can make any request along with header through the HTTP Client, also we get the details of response and other params directly, like if we want the main body of the response, then just write down $response->body() this will return the body. If we need to check the status of the response then just need to call $response->status().
Likewise, we can use the following details:
$response->body();
$response->json();
$response->status();
$response->ok();
$response->successful();
$response->serverError();
$response->clientError();
$response->header($header);
$response->headers();
And for the routes we have to write details like:
$response = Http::withHeaders([
'accept' => 'application/json',
])->post('http://domain.com/users/list', [
'name' => 'User',
]);
So now onwards we can fire the API from the web routes along with the Headers. We can also pass the Bearer Token by just adding:
$response = Http::withToken('token')->post('http://www.domain.com', ['name' => 'User']);
Fluent String Operations:
We can all agree how useful string operations are as they help us manipulate strings easily and without much hassle. Thanks to Laravel VII, some new and useful string operations were added in this version. String operations such as trim(), replace(‘x’, ‘y’), after(), before(), words() and many more now will be available in Laravel VII.
CORS Support:
Laravel VII also came with the fresh first-party package “CORS” along with options, so now no need to create custom middleware for the same, just configure the config files and use CORS services.
Stub Customization:
This is one of the best updates of Laravel. This will help us to boost up the speed of development. For example, whenever we create a new Model, we will write protected $guarded = [*] in all the models, it becomes a bit time consuming if you see it on a larger picture. So now, we can create our own stub for these kinds of changes, So, if we added protected $guarded = [*] into stub then whenever we create a new model, this line will be added automatically. For example, in all tables we need one default column $table->string(‘custom_id’), in all the migrates, so we will publish the stub and customize it.
Route Model Binding:
This is one of the most interesting features of Laravel 7. In the older version, we can bind any model to route, for example:
Route::get('user/{user}', function(User $user) {
dd($user);
});
// domain.com/user/1
Here we’ll get the user’s personal details like we applied dependency injection of the User model. In Laravel 7, there is support for Implicit Model Binding, such as if I want to get the user’s details based on the user’s name then I’ll get details by adding simple “:” after model’s name.
Route::get('user/{user:username}', function(User $user){
return $user;
});
// domain.com/user/kmjadeja
We can also add custom keys and scoping for the Route Model Binding, it’s a very useful thing which can help us to generate SEO friendly URLs.
Custom Keys and Scope:
Sometimes, we need to bind multiple models to the single route and second binding param is dependent on the first building param like we need to get product details that are available under one specific category.
For example, we get all the lists of all the mobile devices which are available under the android category, So now we can do this with simple Route Model Binding
Route::get('category/{category:type}/device/{device:type}',
function (Category $category, Device $device) {
return $device;
});
// domain.com/category/mobile/device/android
One more simple example:
Route::get('user/{user}/posts/{post:slug}',
function (User $user, Post $post) {
return $post;
});
// domain.com/user/1/posts/upcoming-events
Laravel Query Cast:
· Query cast is used to “cast” a column while executing the query.
· Let’s take an example : In the database we save user’s ID, System IP, create_at and updated_at details when user LoggedIn to the system. Now we want to know the last login date of particular user in that case my code will be:
$users = User::select([
'users.*',
'last_logged_in_at' => UserLog::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->where('id', 1)->withCasts([
'last_logged_in_at' => 'date'
])->get();
So here we get the user’s last loggedIn details in “data”, not in the timestamp, we cast the user’s create_at column to date.
Improve email template design:
In Laravel 7 they have simply improved the email template, made the email template simpler and finer.
Queue Configuration:
Currently, if any queue or job is throwing an exception, each time the job will get executed and throw the exception. In Laravel 7, we can set maxExceptions for jobs. If we set the value equal to 3, in that case, if the job gets the exception more than 3 times, the queue stops automatically. #noExtraExecution
Speed improvements for route-cache:
Laravel 7 have 2x speed improvement for routes, it is mostly used with 800+ routes (big projects), php artisan route:cache is used to cache the routes.
Conclusion:
So that’s all for this blog but that’s not all for Laravel 7 and our discussion on it. Stick with us for the next blog regarding some of the features along with their demo codes. Till then, get started with the master document. You can read the master document here.
Hope, you have liked & enjoyed this blog. If you like this blog then follow us for more such interesting articles on the latest technologies.
0 notes
Text
My answer to How do I use JWT Auth for a multiple table in Laravel 5.5? I have users and admin table. https://t.co/tGsWti0E8K
My answer to How do I use JWT Auth for a multiple table in Laravel 5.5? I have users and admin table. https://t.co/tGsWti0E8K
— Martin Tonev (@microDesignn) July 5, 2018
from Twitter https://twitter.com/microDesignn July 05, 2018 at 01:57PM via IFTTT
0 notes
Photo
New Post has been published on https://programmingbiters.com/custom-user-authentication-in-laravel-5-application/
Custom User Authentication in Laravel 5 Application
There are times when we need a particular section of our app to be accessible only to some particular users. For example, if we are building a forum, we may want to restrict access to /admin routes. In such a scenario, we need separate logins for regular users and users with administrative rights. A custom user authentication system is useful for these scenarios.
Laravel’s out of the box authentication system isn’t very useful for above example. However, because the default auth system is so much flexible, we can easily extend it to implement a multi-auth system.
# Setting up the Database
First migrate the default tables that Laravel comes with and then scaffold authentication.
We will add just one column is_admin to the default users table that comes with Laravel. By default, it is set to false. For users with admin privileges, this will be set to true. We will then use this field to filter admin users from basic users.
So create a new migration and update the up() and down() functions.
public function up() Schema::table('users', function (Blueprint $table) $table->boolean('is_admin')->default(0); ); public function down() Schema::table('users', function (Blueprint $table) $table->dropColumn('is_admin'); );
Migrate this and we are set to go.
# Setting up the Controllers and the Routes
First, let’s create an admin controller.
<?php namespace AppHttpControllersAdmin; use AppHttpControllersController; use IlluminateHttpRequest; class AdminController extends Controller public function index() return "Welcome to admin area";
and a corresponding route :
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function() Route::get('/', 'AdminController@index'); );
We want this route to be accessible only to users with administrative rights.
# Writing a new User Provider
Next, we need to create a new User Provider class, AdminUserProvider , that will retrieve a user by the provided credentials only if the user is an admin.
Since we are using Eloquent, we can simply extend Laravel’s default IlluminateAuthEloquentUserProvider class that implements the IlluminateContractsAuthUserProvider contract.
Now our AdminUserProvider will only retrieve an admin user, so we will just override retrieveByCredentials() method. Also since we are not modifying the basic logic behind retrieving an user, we can simply call the same method on the parent class.
$user = parent::retrieveByCredentials($credentials);
We can now check if an user with the provided details was found and if yes, whether that user is an admin or not.
if($user === null || !$user->is_admin) return null;
If no user was found or if the user is not an admin, we will simply return NULL. Otherwise we will return the user.
The complete class is as follows:
<?php namespace AppLibraries; use IlluminateAuthEloquentUserProvider; class AdminUserProvider extends EloquentUserProvider public function retrieveByCredentials(array $credentials) !$user->is_admin) return null; return $user;
Now we need to register our custom provider in AppProvidersAuthServiceProvider . In the boot() method, add the following:
Auth::provider('admin-user-provider', function ($app, array $config) return new AdminUserProvider($app['hash'], $config['model']); );
admin-user-provider is the driver name that we will use in configauth.php . Since we are using IlluminateAuthEloquentUserProvider , we need the $app and $config to initialize our admin provider. Check out Laravel’s documentation for more information about registering custom providers.
Finally, let’s update the providers array in configauth.php and add our just created provider.
'providers' => [ //...... 'admin-users' => [ 'driver' => 'admin-user-provider', 'model' => AppUser::class, ], //....... ],
admin-users is our provider’s name that we will use to define a custom guard.
# Configuring Guards
Now that our custom user provider is complete, let’s add a new guard that will utilize this provider. In the guards array in configauth.php , create a new guard.
'guards' => [ // .... 'admin' => [ 'driver' => 'session', 'provider' => 'admin-users' ], // .... ],
Since this a web app, we are sticking with the session driver rather than token .
# Writing a Middleware
Next we need a custom middleware that only allows admin users to access certain routes. The handle() method will have a $guard parameter that is default to null. We will use this $guard to fetch the actual guard for that request.
$reqGuard = Auth::guard($guard);
Once we have the guard, we can check if the authenticated user is not an admin or if the request is coming from an unauthenticated user. In both case, we want to abort the request and throw an error.
if($reqGuard->guest() || !$reqGuard->user()->is_admin) return abort(401);
However if the authenticated user is an admin, we need to pass the request to the next middleware.
return $next($request);
The complete middleware is as follows:
<?php namespace AppHttpMiddleware; use Closure; use IlluminateSupportFacadesAuth; class AuthenticateAdmin /** * Handle an incoming request. * * @param IlluminateHttpRequest $request * @param Closure $next * @return mixed */ public function handle($request, Closure $next, $guard = null) !$reqGuard->user()->is_admin) return abort(401); return $next($request);
Finally we register the middleware in AppHttpKernel.php . In the $routeMiddleware array, add our middleware :
protected $routeMiddleware = [ // .... 'auth.admin' => AppHttpMiddlewareAuthenticateAdmin::class, // .... ];
Now we can use this middleware to protect routes.
# Let’s stitch everything together!
Our provider, guard and middleware are ready. However if we authenticate our admin users through the standard login form, they still won’t be able to access /admin . This is because they are being authenticated using the web guard. We need to authenticate them using our admin guard that we wrote. For this we need to create a separate login controller that will render a separate login form for our admins.
<?php namespace AppHttpControllersAdmin; use AppHttpControllersController; use IlluminateFoundationAuthAuthenticatesUsers; use Auth; class AdminLoginController extends Controller use AuthenticatesUsers; protected $redirectTo = '/admin'; public function __construct() $this->middleware('guest')->except('logout'); public function showLoginForm() return view('admin.login'); protected function guard() return Auth::guard('admin');
We are overriding showLoginForm() and guard() methods from the AuthenticatesUsers trait. Also we set the after login redirection to our /admin route.
For the login form, just copy the the default login template to resources/views/admin/ and update the action field in the form to /admin/login . Finally, let’s update the routes :
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function() Route::get('/', 'AdminController@index'); Route::get('/login', 'AdminLoginController@showLoginForm'); Route::post('/login', 'AdminLoginController@login'); Route::get('/logout', 'AdminLoginController@logout'); );
Before we forget, let’s also update our AdminController and add a constructor that uses our AuthenticateAdmin middleware:
public function __construct() $this->middleware('auth.admin:admin');
That’s all ! Now we have multiple authentication mechanism setup for our categorically different users.
Our regular users can login through /login and can’t access the /admin area. However our admin users can login through /admin/login and bingo 🙂
The complete code for the project can be found on Github.
0 notes
Text
Laravel 5.5 Auth Multiple Table - 3 Multi Auth Login Page Laravel
Laravel 5.5 Auth Multiple Table – 3 Multi Auth Login Page Laravel
[ad_1]
hi, in this video we will discuss specifically about how to login for admin account that we have created in admins table. We will discuss more deeply the use of handlers and middleware on laravel. Obviously this will be useful when we want to create multiple authentication using laravel 5.5.
======================================================
hai, pada video kali ini kita akan membahas…
View On WordPress
1 note
·
View note
Photo
New Post has been published on https://programmingbiters.com/email-verification-with-laravel-5-5-with-example/
Email Verification with Laravel 5.5 With Example
Laravel makes it pretty easier to implement email verification. The default auth scaffolding that comes with Laravel is very flexible and we can easily modify it to include verification functionality.
The overall procedure is also simple:
When an user registers, log him out immediately.
Register a provider, e.g EloquentEventServiceProvider , that looks for eloquent events, and when an user is created, generate a corresponding token for that user and fire off an event, e.g UserRegistered .
If a user requests a verification email to be resent, fire off another event, e.g UserRequestedVerificationEmail .
Create an event listener, e.g SendVerificationEmail , that listens for UserRegistered or UserRequestedVerificationEmail event, and then send a email with the verification link using a mailable class.
Finally, when the user visits the link sent to email, match the token from the url with the one in the database and on successful matching, set the verified flag to true.
When an user tries to log in, check if the verified flag is true. If not, redirect him back to login.
TL;DR: A complete implementation can be found on this Github repo 🙂
# Setting up the migrations
Quick tip: If you’re using a fresh installation of Laravel 5.5, use Laravel’s default auth scaffolding: php artisan make:auth
We will add just one column verified to the users table. This will be a boolean field and we will set it to false by default.
$table->boolean(‘verified’)->default(false);
Next, we will create a new table verification_tokens that will hold the verification token we generate for the user. We will also setup a Foreign Key Constraints with the users table.
$table->integer(‘user_id’)->unsigned()->index();
$table->string(‘token’);
$table->foreign(‘user_id’)->references(‘id’)->on(‘users’)->onDelete(‘cascade’);
Run the migrations and we are good to go.
# Setting up the relationship
Relationship between User and VerificationToken is straightforward – a token belongs to an user and an user has one token. We can simply add these relationships to corresponding models.
//User model
public function verificationToken()
return $this->hasOne(VerificationToken::class);
and on VerificationToken model
//VerificationToken model
public function user()
return $this->belongsTo(User::class);
While we are at it, let’s change the route key name for our VerificationToken model.
public function getRouteKeyName()
return ‘token’;
We will use the token field rather than the id field to do an implicit model binding when we fetch the token from the link.
# Setting up the verification controller and the routes
We need a controller that will be used to verify the token and resend the verification email, should the user requests it. We will define two methods –
The verify() method will receive an instance of VerificationToken model (we will use route binding for this). The actual verification using the token will be done here.
The resend() method will be used to resend the verification link to the user.
class VerificationController extends Controller
public function verify(VerificationToken $token)
//
public function resend(Request $request)
//
Let’s define two corresponding routes for the VerificationController :
Route::get(‘/verify/token/token’, ‘AuthVerificationController@verify’)->name(‘auth.verify’);
Route::get(‘/verify/resend’, ‘AuthVerificationController@resend’)->name(‘auth.verify.resend’);
I have created the controller in AppHttpControllersAuth namespace. Feel free to create it anywhere within AppHttpControllers and update the relevant namespaces.
# Updating the Auth Controllers
When an user registers an account, by default, he’ll also be logged in immediately. The RegisterController uses the RegistersUsers trait defined in IlluminateFoundationAuth . We can override the registered() method from the trait on our RegisterController to perform an immediate logout.
protected function registered(Request $request, $user)
$this->guard()->logout();
return redirect(‘/login’)->withInfo(‘Please verify your email’);
The guard() method is also defined on the RegistersUsers trait that fetches the current guard for the logged in user and performs the logout. We then redirect the user to the login page with appropriate message.
We also need to ensure that a user can not login without verifying the email first. There are many ways to accomplish this. However, the simplest way is to override the authenticated() method from AuthenticatesUsers trait in our LoginController .
protected function authenticated(Request $request, $user)
if(!$user->hasVerifiedEmail())
$this->guard()->logout();
return redirect(‘/login’)
->withError(‘Please activate your account. <a href=”‘ . route(‘auth.verify.resend’) . ‘?email=’ . $user->email .‘”>Resend?</a>’);
If the $user is not verified, we would log him out immediately and redirect him to login page with an error message. We are also injecting the user’s email in the query string that we can later use to fetch the user by email when resending the verification link.
When a user resets the password, on successful reset, by default laravel automatically signs them in. If a user has not verified the email, we do not want them to be able to sign in. But they should be able to reset the password. This sounds complicated, but is really simple.
The ResetPasswordController uses the ResetsPasswords trait from IlluminateFoundationAuth , which implements sendResetResponse() method to check whether a reset has been successful. We can override this method in ResetPasswordController to do our verified account check just before the response is set.
Because on a successful password reset the user will be logged in, we can call the guard() , grab the user and check if they already verified their email. If they are not verified, we would log them out immediately and redirect them back to the login page with an appropriate message.
protected function sendResetResponse($response)
if(!$this->guard()->user()->hasVerifiedEmail())
$this->guard()->logout();
return redirect(‘/login’)->withInfo(‘Password changed successfully. Please verify your email’);
return redirect($this->redirectPath())
->with(‘status’, trans($response));
However, if the user is already verified, they would be redirected to application’s home authenticated view.
# Registering a Service Provider for Eloquent Events
Now create a service provider and register it in the configapp.php . This service provider that will look for a specific Eloquent event: created on User model. The created eloquent event also receives a instance of the model that has been created, in this case the User model.
public function boot()
User::created(function($user)
$token = $user->verificationToken()->create([
‘token’ => bin2hex(random_bytes(32))
]);
event(new UserRegistered($user));
);
When an user is created, we want to generate a token for that user. We can use PHP 7’s shiny new random_bytes() function to generate a 64 characters long random string. Finally a new UserRegistered event is fired.
# Creating UserRegistered event
Let’s create the UserRegistered event we have used in above snippet.
The whole idea behind using events and listeners here is that apart from firing a verification email, we may later also want to send a welcome email, or a do some payment stuff when an user registers. We can easily hook all that up without much refactoring.
Since our UserRegistered event is receiving the created User instance, we can assign this to a public property so that our listener can pick it up.
public $user;
public function __construct(User $user)
$this->user = $user;
Now we have the flexibility to listen when this event is fired and do multiple stuff.
# Creating UserRequestedVerificationEmail event
But what if the user requests to resend the verification email? Let’s create another event for that: UserRequestedVerificationEmail . This event will also receive a User instance, so we can assign this to a public property for our listeners to pick it up, just like we did with the UserRegistered event.
public $user;
public function __construct(User $user)
$this->user = $user;
That’s all we need for this event. Let’s jump into creating a listener.
# Creating a Listener
Okay. Now that we are done with the events, let’s create a listener: SendVerificationEmail .
This listener has only one job – whenever a UserRegistered or UserRequestedVerificationEmail event is fired, pick up the user and send a new email with the verification link.
public function handle($event)
Mail::to($event->user)->send(new SendVerificationToken($event->user->verificationToken));
The handle() method receives an event instance and from that we can extract the user and access the token associated with that user using the relationship. SendVerificationToken is the mailable class we are using to send email.
Finally map the event listener in EventServiceProvider .
protected $listen = [
‘AppEventsUserRegistered’ => [
‘AppListenersSendVerificationEmail’,
],
‘AppEventsUserRequestedVerificationEmail’ => [
‘AppListenersSendVerificationEmail’,
],
];
Now our event/listener setup is complete.
# Creating a mailable class
Because any public property in Laravel’s mailable class is automatically available in the view, very simple we can set a $token property that contains the verification token and then use that in the mail view.
public $token;
public function __construct(VerificationToken $token)
$this->token = $token;
The build() method is also very simple.
public function build()
return $this->subject(‘Please verify your email’)
->view(’email.auth.verification’);
Finally we create the view:
To verify your account, visit the following link. <br> <br>
<a href=“ route(‘auth.verify’, $token) ”>Verify now</a>
We are using the route() helper method to generate the link for us. Since we are using laravel’s implicit model binding, the $token will be used to generate a valid link automatically.
# Verifying the User
In our verify() method in VerificationController , using the route model binding, the model instance that has a token matching the corresponding value from the request URI will be automatically injected ( laravel <3 ) . So we can access the user associated with that token and update the verified field.
$token->user()->update([
‘verified’ => true
]);
We do not need the token anymore.
Then we can simply redirect them to the login page so they can login again using their email/password.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function verify(VerificationToken $token)
$token->user()->update([
‘verified’ => true
]);
$token->delete();
// Uncomment the following lines if you want to login the user
// directly upon email verification
// Auth::login($token->user);
// return redirect(‘/home’);
return redirect(‘/login’)->withInfo(‘Email verification succesful. Please login again’);
What we can also do is login the user automatically and redirect them to home page or profile page. Update it as per your need.
# Resending verification mail
In our resend() method, since when the user requests resending verification email, we are passing his email in the query string, we can easily grab the email from the request and fetch the user.
$user = User::where(’email’, $request->email)->firstOrFail();
Notice the use of firstOrFail() , because if an user with that email is not found, this will throw a IlluminateDatabaseEloquentModelNotFoundException . (In a real world application, you might want to catch that exception and render a custom error message. If the exception is not caught, laravel will throw a simple 404 error).
We now need to check if the user is already verified. If the user has already verified the email, we do not want to send a verification link.
if($user->hasVerifiedEmail())
return redirect(‘/home’)->withInfo(‘Your email has already been verified’);
Since we created a token when the user registered, we do not need to recreate it. Therefore, to resend the verification email, we simply fire off the UserRequestedVerificationEmail event. Since we already set it up along with a listener, much of the work has been done.
event(new UserRequestedVerificationEmail($user));
That’s all we need. Now we can redirect them with the appropriate message.
public function resend(Request $request)
$user = User::byEmail($request->email)->firstOrFail();
if($user->hasVerifiedEmail())
return redirect(‘/home’);
event(new UserRequestedVerificationEmail($user));
return redirect(‘/login’)->withInfo(‘Verification email resent. Please check your inbox’);
The complete resend() method is shown above.
# Conclusion
Laravel’s event listeners implements a observer implementation which are extremely useful for solving problems like this. Breaking the whole procedure into providers, events and listeners makes the overall architecture very flexible. Even if we are using a custom authentication instead of the default auth scaffolding, it is still easier to implement and test new features.
A complete implementation can be found on this Github repo 🙂
0 notes
Photo
New Post has been published on https://programmingbiters.com/recent-views-view-counter-log-in-laravel/
Recent Views & View Counter log in Laravel
Sometimes we need to implement a view counter to keep track of how many times a post was viewed. Of course we can simply create a count variable and keep incrementing it with every GET request. But what if we consider logging recent views to keep track of the recent posts an user has viewed? In that case, a simple counter variable isn’t very helpful.
A simple yet flexible solution is to create a pivot between users and posts that stores how many times a post has been viewed by an user. We will create a separate entry for each user viewing a post. The overall procedure would be something like the following:
When an user views a post, dispatch a Job, e.g UserViewedPost , that will handle all the logic for logging the view.
Create a collection of the posts this user has viewed. If the collection contains the post currently being viewed, simply increment the view count. If the collection does not contain the current post, attach the current post to the collection.
To calculate total views of a post, sum up the number of times any user has viewed that particular post.
TL;DR: A complete implementation can be found on this Github repo 🙂
# Setting up the migrations
Let’s create a pivot table user_post_views to store all the view related data.
public function up() Schema::create('user_post_views', function (Blueprint $table) $table->increments('id'); $table->integer('user_id')->unsigned(); $table->integer('post_id')->unsigned(); $table->integer('count'); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade'); );
user_id will store the id of the user who is viewing the post. post_id will contain the id of the post currently being viewed. count is the number of times this user has viewed this post.
# Setting up the relationship
Relationship between User and Post is simple – a user may view many postsand a post may be viewed by many users. Therefore, we setup a many to manyrelationship. Let’s define these relationships in the corresponding models.
Let’s start with User model:
public function viewedPosts() return $this->belongsToMany(Post::class, 'user_post_views') ->withTimestamps() ->withPivot(['count', 'id']);
The withTimestamps() method will ensure that the created_at andupdated_at timestamps are automatically maintained at the pivot table. We are also grabbing the count and id fields from the pivot table because later we need to increment this.
Now let’s define the inverse relationship on our Post model:
public function viewedUsers() return $this->belongsToMany(User::class, 'user_post_views') ->withTimestamps() ->withPivot(['count']);
Here also we are grabbing the count field from the pivot table. We will later use this to sum up the number of times a particular post has been viewed by different users.
# Dispatching a job from the controller
Now that we have the relationship and pivot table setup between our models, let’s work on logging a view. Say we have this route to view a post:
Route::get('/posts/post', 'PostController@show')->name('posts.show');
Of course we can write the entire logging logic within the show() method onPostController , but a more flexible way would be to create a job and dispatch it every time a user views a post. In this way we not only separate the logging logic from the controller and keep it slim, but going forward we can even implement queuing on this.
So let’s create a job, say UserViewedPost . Now in the show() method, we can quickly dispatch() it before rendering the requested post.
public function show(Request $request, Post $post) if($request->user()) dispatch(new UserViewedPost($request->user(), $post)); return view('posts.show', compact('post'));
We first ensure that a user is currently signed in. We then dispatch the UserViewedPost job and pass the currently signed in user and the post into the job’s constructor. Finally we render a view with that post.
# Logging recent views
Now that we are dispatching UserViewedPost job from the PostController , let’s log the view.
First let’s accept the models that were passed into the job’s constructor.
public $user; public $post; public function __construct(User $user, Post $post) $this->user = $user; $this->post = $post;
We are keeping the $user and $post properties as public, because we may want to queue this job later.
Next, in the handle() method, we first want to check if this user has already viewed this post. In case he has already viewed it, we do not need to create a new entry as we can simply increment the count from the previous entry.
// this user has already viewed this post if($this->user->viewedPosts->contains($this->post)) $this->user->viewedPosts->where('id', $this->post->id) ->first() ->pivot ->increment('count'); return;
$this->user->viewedPosts is used to access the relationship betweenUser and Post . This will return a collection of posts this user has viewed. Thecontains($this->post) will determine if the collection already contains this post. If it does, we search for this post where(‘id’, $this->post->id) in the collection, grab the first() entry, then access the pivot and increment thecount .
However, if this user has not viewed this post earlier, we want to create a new record for this in our pivot table.
// this user is viewing this post for the first time $this->user->viewedPosts()->attach($this->post, [ 'count' => 1 ]);
Because we are working with many to many relationship, we can simply access this user’s viewed posts $this->user->viewedPosts() and attach() this post to this user. We also want to initialize our view count. The attach() method also takes an array of additional data, so we can pass the initial count into this method attach($this->post, [‘count’ => 1]) .
That’s all we need to log views. The complete handle() method is as follows:
public function handle() // this user has already viewed this post if($this->user->viewedPosts->contains($this->post)) $this->user->viewedPosts->where('id', $this->post->id) ->first() ->pivot ->increment('count'); return; // this user is viewing this post for the first time $this->user->viewedPosts()->attach($this->post, [ 'count' => 1 ]);
The handle() method is called whenever the job is processed. We can also queue this job. Laravel documentation provides a detailed explanation of setting up queues.
# Fetching the recently viewed posts
Now that the views are being logged, we want to show the users a list of their recently viewed posts.
Say we have a route like this:
Route::get('/posts/recent', 'PostController@recentlyViewedPosts') ->name('posts.recent') ->middleware('auth');
Because we have the necessary relationship setup, fetching these records are very easy.
public function recentlyViewedPosts(Request $request) $posts = $request->user()->viewedPosts() ->orderBy('pivot_updated_at', 'desc') ->take(5) ->get(); return view('posts.recent', [ 'posts' => $posts ]);
We get the request object and from that request, we extract the currently signed in user and accessing the relationship, we query for all the posts this user has viewed, $request->user()->viewedPosts() , sort the result byupdated_at field and take() the last 5 posts. In the orderBy() method, we are using pivot_updated_at to sort the posts by using the time they were last viewed. If we just use updated_at instead, it will use the time when the posts were last edited and not the time when they were inserted or incremented in the pivot, which we do not want. Lastly, we go ahead and render a view.
Notice that we are hardcoding the number of posts in the take() method. If you want to mention the number of posts you are showing in your view, you have to again hardcode it. This is usually not a good practice. A better way is to create a limiting constant, say const POST_LIMIT = 5; and then use it like this: take(self::POST_LIMIT) . You can then pass this constant to your views and use it. This way refactoring becomes easy.
# Calculating total views of a post
To calculate the total views of a post, we will use the reverse relationship we setup in our Post model.
public function views() return array_sum($this->viewedUsers->pluck('pivot.count')->toArray());
Remember we have set this as a many to many relationship. That means, each post has many users who may have viewed it. Therefore, using the reverse relationship, we create a collection of users $this->viewedUsers who have viewed this post. Using the pluck() method, we then pluck out the count from the pivot table , which gives us a collection of the number of times any user has viewed this particular post. The toArray() method then converts the collection to an array and we use array_sum() to sum up all the values.
Now in our views, we can use $post->views() to show the number of times a post has been viewed.
# Conclusion
There are a couple of things we have not addressed here:
First, the view counter only works for signed in users. If an user is not signed in, but viewing a post, that view will not be added to the total number of views. Of course you can go ahead and tweak this code to increment the count regardless of the user is signed in or not.
Second, we have not implemented view throttling. What we are doing here is that if a signed in user keeps loading a post, the view count will keep on increasing. You may want to limit this count hourly or daily, i.e. if a user views a post multiple times within an hour, view count will be incremented only once. An excellent blog post on view throttling, written, can be found here.
Happy coding…
0 notes