Requirements
- NodeJS last version
- PHP
- Composer
Introduction
I’ve been programming for more than 20 years, mostly with .NET. Recently I had to work on a project with PHP. It was a simple project, and because I didn’t touch PHP for ten years apart from a few quick fixes on WordPress. I decided to go and look at how the PHP community evolved, and while looking around for the best web framework, Laravel kept coming up.
They call it The PHP Framework For Web Artisans, and because it has been built with developer happiness in mind and with a solid foundation, you shouldn’t be sweating on the small thing. This a great way to introduce a framework to a new developer. All framework I have tried over the years they all look shiny and fabulous on the surface, but in the end to get a full app you need to stitch a few libraries together with different design and goals. By the end of the day, you wasted a lot of time-fighting to make everything work together, while it would have been better if you could spend that time building your application. Of course, any framework or technology is going to have its issues. When most of my time is spent on framework issues instead of my code issues, I start to question why in 2021 we are still having all these issues. So I decided to give it a try.
My own requirements before i even start a simple project
But before creating a new Laravel project, I had to check what they usually use for building their web user interfaces. I was looking to start simple. I prefer to avoid complex front-end framework like React and Vue because I’m looking to develop apps with the path of least resistance. Those frameworks tend to make things more convoluted and complex than they need to be, especially for simple control panels where all you need to do is data entry.
But I also wanted to use Tailwind CSS because I fall in love with it a few weeks before even thinking of using PHP and Laravel. And by simply looking a little deeper at the Laravel web site, I was happily surprised that they work a lot with Tailwind CSS. They have a project called Jetstream witch provides two UI Stacks, one with Livewire + Blade and the other is Inertia + Vue. As you can imagine, I have chosen Livewire + Blade witch is the more straightforward approach for me, and the best part is that both use Tailwind CSS, so they are telling me to download it now!!
How to create your first Laravel jetstream project
Before you can create a Laravel jetstream project, you need to create an empty Laravel project. To do so, I usually use the Laravel installer, and you need to have composer installed. If you currently don’t have the Laravel command-line installer, you get it on your machine by running the following command.
composer global require laravel/installer
When the above command finish, you can proceed further by creating an empty Laravel project with the following command.
laravel new myjetstreamapp
You can specify any name you like in place of myjetstreamapp
Now we are ready to install the jetstream starter kit with composer. In this example, I will proceed with the livewire version. For more info, check jetstream’s official website. First run composer require.
composer require laravel/jetstream
Then we need to install Jetstream with livewire support.
php artisan jetstream:install livewire
Then as per jetstream doc we must finish our installation by running npm and migrations.
npm install
npm run dev
php artisan migrate
You have probably noticed that by running the last command php artisan migrate
it output an error, this usually happen because you don’t have a connection configure for your database.
Usually, I would configure a mysql test database, but I will guide you with sqlite, a robust database on a file for this tutorial.
To enable sqlite you need to edit the .env file. If you don’t see it on your os is because it is a hidden file. On MacOS, you can press CMD + . to show hidden files; if you press it again, it will hide them again. Open the .env file on your editor of choice and first set the DB_CONNECTION setting as:
DB_CONNECTION=sqlite
Then you need to remove DB_DATABASE setting line. If you don’t remove it, it will prevent database migration. Now create an empty sqlite database with the following command.
touch database/database.sqlite
Now you can rerun the migration command. The migration command will create the default tables included with jetstream for user management.
php artisan migrate
Now you should see something like the following output.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (1.32ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.83ms)
Migrating: 2014_10_12_200000_add_two_factor_columns_to_users_table
Migrated: 2014_10_12_200000_add_two_factor_columns_to_users_table (0.77ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.81ms)
Migrating: 2019_12_14_000001_create_personal_access_tokens_table
Migrated: 2019_12_14_000001_create_personal_access_tokens_table (1.08ms)
Migrating: 2021_05_17_193135_create_sessions_table
Migrated: 2021_05_17_193135_create_sessions_table (1.04ms)
Ok it’s time to see how you project looks like, run php artisan serve
and navigate on your browser at http://127.0.0.1:8000/.
Your empty project is now ready!
Seeding the database with a default user
Right now, you can’t log in to your new website because there are no users. But Laravel, for this specific purpose, provides a feature named Database Seeder, which is very useful for providing default data on your database or populating your database with test data. Later, I will show you how to seed some faked users to build a user list, using seeders and fakers to make this trivial. For now, let’s create a default test user. Execute the following command, which will generate a UserSeeder class for you.
php artisan make:seeder UserSeeder
The UserSeeder.php is located inside the database/seeders
folder.
Replace the file content with the following snippet
<?php
namespace Database\\Seeders;
use Illuminate\\Database\\Seeder;
use Illuminate\\Support\\Facades\\App;
use Illuminate\\Support\\Facades\\Hash;
use Illuminate\\Support\\Str;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
if (App::environment('local')) {
\\App\\Models\\User::insert([
[
'name' => 'Admin',
'email' => 'admin@localhost',
'email_verified_at' => now(),
'password' => Hash::make("admin@pwd23"), // password
'remember_token' => Str::random(10)
]
]);
}
}
}
This will create a new user with admin@localhost
as login email and admin@pwd23
.
But before you try to login on your app you need to run the seeder with the following artisan command.
php artisan db:seed --class=UserSeeder
Try to login to check if everything is running ok.
Populating the users table with fake users
There are a few steps to make a seeder with randomly generated users. But Laravel makes this very easy trivial. We need to make a few fake users so we can later build a user data table using Livewire, and without a few users, we wouldn’t be able to see a paginated table. In an empty Laravel project, you would have to run the php artisan make:factory UserFactory
to create a custom factory for your user model, but you get one for free on the jetstream template. This is what you get on the box.
<?php
namespace Database\\Factories;
use App\\Models\\Team;
use App\\Models\\User;
use Illuminate\\Database\\Eloquent\\Factories\\Factory;
use Illuminate\\Support\\Str;
use Laravel\\Jetstream\\Features;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
/**
* Indicate that the model's email address should be unverified.
*
* @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory
*/
public function unverified()
{
return $this->state(function (array $attributes) {
return [
'email_verified_at' => null,
];
});
}
/**
* Indicate that the user should have a personal team.
*
* @return $this
*/
public function withPersonalTeam()
{
if (! Features::hasTeamFeatures()) {
return $this->state([]);
}
return $this->has(
Team::factory()
->state(function (array $attributes, User $user) {
return ['name' => $user->name.'\\'s Team', 'user_id' => $user->id, 'personal_team' => true];
}),
'ownedTeams'
);
}
}
Look at the definition function. You can see that it is using $this->faker to generate
a fake name and email; for the email, you can see nicety $this->faker->unique()->safeEmail
this will guarantee that you generated email is unique. Now modify the UserSeeder.php
run method as per example, notice that now we check if the admin user already exists.
public function run()
{
if (App::environment('local')) {
if(User::where('name', '=', 'Admin')->count() === 0) {
\\App\\Models\\User::insert([
[
'name' => 'Admin',
'email' => 'admin@localhost',
'email_verified_at' => now(),
'password' => Hash::make("admin@pwd23"), // password
'remember_token' => Str::random(10)
]
]);
}
User::factory()->times(200)->create();
}
}
Now run the seed command again to add 200 users to you database.
php artisan db:seed --class=UserSeeder
If you open the sqlite database in a db viewer like TablePlus, you should see 201 rows.
Now we are ready to proceed with the creation of a Livewire users table
Creating the user table component with Livewire and an open source component
You could easily create your data table with Livewire and Tailwind CSS, but we will use an excellent open-source library. Install the library with the following command.
composer require mediconesystems/livewire-datatables
As suggested by the package author you should add the following css snippet in your app.css
which is located inside resources/css
, this is necessary to avoid flickers as the package use alpinejs.
[x-cloak] {
display: none;
}
Now we need to create our UsersListComponent
with the following.
php artisan livewire:make UsersListComponent
This will create a new livewire component where we are going to add our data table.
Open the users-list-component.blade.php
file and replace the content with the following code.
<div>
<x-slot name="header">
<div class="md:flex md:items-center md:justify-between md:space-x-5">
<div class="flex items-start space-x-5">
<div class="flex-shrink-0">
<div class="relative">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Users') }}
</h2>
</div>
</div>
</div>
</div>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
<livewire:datatable
searchable="name,email"
model="App\\Models\\User"
include="id, name, email, created_at"
dates="created_at"
/>
</div>
</div>
</div>
</div>
Most of the code is layout but if you look at the data table part is very trivial to define a simple data table that provides pagination and search! Here only the datable snippet.
<livewire:datatable
searchable="name,email"
model="App\\Models\\User"
include="id, name, email, created_at"
dates="created_at"
/>
But we are not finished! We need to enable a new route in the web.php file to show it! Open the web.php file and remove the dashboard route and replace it with the following code, which embeds the dashboard route and users route inside a group, so both get authenticated, and there is no need to duplicate the middleware part.
Route::middleware(['auth:sanctum', 'verified'])->group(function (){
Route::get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
Route::get('/users', \\App\\Http\\Livewire\\UsersListComponent::class)->name('users');
});
Now serve it with php artisan serve
and look at your newly create users page!
Conclusion
Building great websites in Laravel and livewire is very trivial. This is a simple example but is a good starting point to see how productive this ecosystem is. Hopefully, you enjoyed this article, and if so, please leave a comment or a clap!