Tuesday, 18 March 2025

Laravel migrations, down, rollback and batch numbers

 When you create a migration using a command such as:

php artisan make:migration category

A migration file is created. As yet, the migration hasn't been made i.e. the resulting table hasn't been created. This gives you the chance to develop the migration file.

2 functions exist by default in the migration file; up() and down().

up() is commonly used to create a table.

down() is commonly used to delete the table.

When a migration has been made, it is added to the migrations table. As well as the migration name is a batch number. The batch number works in co-ordination with the down() function and the rollback command.

If you would like to go back a step, perhaps you have made a mistake, you can use the command:

php artisan migrate:rollback

This command, looks at the migrations table. It looks at the latest batch numbers and reverts the migrations with the latest batch number. It reverts those migrations by performing whatever is contained in the down() functions of those migration files.

You can see how it would be possible to selectively reverse migrations. All you have to do, is apply the latest batch number to the ones you want to reverse. 

Monday, 10 March 2025

Some notes on the Laravel 12 Livewire starter kit

 You can install Laraval with Livewore as a starter kit without Volt. It comes up as an option when you run:

laraval new

Having installed Livewire, you can completely ignore it and continue to develop your application with a Laravel 11 approach. 

Installing the Livewire starter kit without Volt, provides you with directories such as

app/Livewire/Auth

app/Livewire/Settings

The contents of these are Livewire components, which essentially work like controllers.

These then, have corresponding Blade files as views. The views also contain Livewire "wire" directives within for example form tags, used to make calls back to the models.

Volt enables developers not to need separate Livewire components. All the logic is contained in the Blade files.

Laravel 12 contains only the default Flux starter kit. Just because Laravel 12 uses Flux, it doesn't mean you have to only use Flux components e.g. You can simply use a HTML table with Tailwind instead of a flux:table.

Wednesday, 5 March 2025

Delete, add and edit columns using Laravel 12 migrations

 The following code example show how to delete, add and edit columns using Laravel 12 migrations. In all cases, when the migration has been completed, you run the command:
php artisan migrate

Delete example

php artisan make:migration delete_column_name_to_table_name --table=table_name

public function up(): void

    {

        Schema::table('table_name', function (Blueprint $table) {

            $table->dropColumn('column_name');

        });

    }


    public function down(): void

    {

        Schema::table('table_name', function (Blueprint $table) {

            $table->string('column_name'); // Define the column type to restore it

        });

    }

Add example

php artisan make:migration add_column_name_to_table_name --table=table_name

public function up(): void

    {

        Schema::table('table_name', function (Blueprint $table) {

            $table->string('column_name')->nullable();

        });

    }


    public function down(): void

    {

        Schema::table('table_name', function (Blueprint $table) {

            $table->dropColumn('column_name');

        });

    }

Edit example

php artisan make:migration edit_column_name_to_table_name --table=table_name

public function up(): void

    {

        Schema::table('table_name', function (Blueprint $table) {

            $table->string('column_name', 100)->nullable()->change();

        });

    }


    public function down(): void

    {

        Schema::table('table_name', function (Blueprint $table) {

            $table->string('column_name', 255)->notNullable()->change();

        });

    }

Laravel 12 Scheduling Hello world!

Many tasks require to be run every hour or day etc.  On the server this is done using a cron.

Laravel provides an easy way to create scheduled events and (importantly) how to test them before they reach the cron stage on the server.

Below is a "Hello world" example, which should offer some confidence and inspiration.

At the end of routes/console.php add the following lines:

Schedule::call(function () {

    echo "Hello World";

})->everyTwoSeconds();

Now run the command:

php artisan schedule:list

The command helpfully tells where the scheduling is going to take place.

Now let's run the task using the command:

php artisan schedule:work

After a short delay, you will see "Hello world" being outputted every 2 seconds as we stipulated.

Now you can see all sorts of options.

Tuesday, 25 February 2025

Laravel 12, CSS and the Brave web browser

 I just started using the new version of Laravel (version 12)

I created a new project using the Livewire starter kit.

The installation process worked quite well.

I then changed to the new directory and ran:

composer run dev

I use Herd and was given a local URL

I put the URL in my chosen web browser, Brave.

The welcome page came up just fine, with a couple of options for login and register.

I opted to register, but the registration page had no styling.

I then realised that the app.css and a couple of other files were being blocked by the browser.

I put the shields down for the new URL and everything worked.

Nothing had gone wrong with the installation at all.

Something to watch out for folks.

Thursday, 20 February 2025

Custom logging in Laravel 11

 It's often difficult to see what's going on in your code. Many people have difficulty setting up debugging or even if they have, following through the break points. Commonly developers try to resolve this through:

dd

or

var_dump

Another feature which can be used to help in this process is logging. Laravel holds a very good feature to support this. Imagine you are adding a feature called "indeed" and you want to log the progress of your application through it's data points.

You can open up the file:

config/logging.php

and add lines like these:

'channels' => [

    // Other channels...

    'indeed' => [

        'driver' => 'single',

        'path' => storage_path('logs/indeed.log'),

        'level' => 'info',

    ],

],

Now you can add a line like this to your code within the "indeed" feature:

Log::channel('indeed')->info('This is a custom log message');

Look inside the directory:

storage/logs

You will see a file called indeed.log containing your output.

Thursday, 20 June 2024

Creating a basic authentication API using Laravel 11

I have used this blog post to create the API, but with a couple of tweaks and some additional explanations. So, thanks Hendrik!

Pre-requisites

I'll assume that you have Laravel set up to use laravel commands.

First, create your application

Run:
laravel new sanctum-example

To question 'Would you like to install a starter kit?', select 'No starter kit'.
To question 'Which testing framework do you prefer?',  select 'Pest'.
To question 'Would you like to initialize a Git repository?', select 'yes'.
To question 'Which database will your application use?', select 'MySQL'.
To question 'Would you like to run the default database migrations?', select 'no'.

Run:
cd sanctum-example

Run:
php artisan install:api

At this stage, the API script reports: "INFO  API scaffolding installed. Please add the [Laravel\Sanctum\HasApiTokens] trait to your User model".
So, let's do that first.
Open app/Models/User.php and change the line:
use HasFactory, Notifiable;
to:
use HasApiTokens, HasFactory, Notifiable;
This will also require you to add the namespace:
use Laravel\Sanctum\HasApiTokens;

Now that's done:
Delete the resources directory
Delete the file routes/web.php
Delete the line web: __DIR__.'/../routes/web.php', from bootstrap/app.php

At this stage I like to create the database so that migrations can be added.
Run:
php artisan serve
Now open your favourite MySQL editor and create the database, i.e.
CREATE DATABASE `sanctum-example`;
Now we can close the server using Ctrl-c.
We should now edit our database settings in the .env file to something similar to this:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=sanctum-example
DB_USERNAME=root
DB_PASSWORD=<yourpassword>


We're now in a good place to do our migrations:
php artisan migrate

At this stage Sanctum doesn't have a configuration published. For this we have to run:
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

Create an Authentication Controller

Our application is API only, so we don't need to create a separate directory to hold API code. So, run:
php artisan make:controller AuthController
We should now have a file called app/Http/Controllers/AuthController.php
To this controller, let's add a method to handle registration:
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
    'name'      => 'required|string|max:255',
    'email'     => 'required|string|max:255|unique:users',
    'password'  => 'required|string'
]);

if ($validator->fails()) {
    return response()->json($validator->errors());
}

$user = User::create([
    'name'      => $request->name,
    'email'     => $request->email,
    'password'  => Hash::make($request->password)
]);

$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
    'data'          => $user,
    'access_token'  => $token,
    'token_type'    => 'Bearer'
]);
}
A method to handle login:
public function login(Request $request)
{
        $validator = Validator::make($request->all(), [
            'email'     => 'required|string|max:255',
            'password'  => 'required|string'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }

        $credentials    =   $request->only('email', 'password');

        if (!Auth::attempt($credentials)) {
            return response()->json([
                'message' => 'User not found'
            ], 401);
        }

        $user   = User::where('email', $request->email)->firstOrFail();
        $token  = $user->createToken('auth_token')->plainTextToken;

        return response()->json([
            'message'       => 'Login success',
            'access_token'  => $token,
            'token_type'    => 'Bearer'
        ]);
}
Finally, a method to handle logout:
public function logout()
{
        Auth::user()->tokens()->delete();
        return response()->json([
            'message' => 'Logout successfull'
        ]);
}
In order to support these methods, you need to have the following namespaces at the top of your class:
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

Create Routes

Next we need to edit the file  routes/api.php
We'll begin by adding our new namespace to the top of the file:
use App\Http\Controllers\AuthController;

Now we can add the routes to support the work we did in the AuthController.
A route for /user should already exist. Don't remove/override that, we'll need it later. Add:
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);

Route::middleware('auth:sanctum')->group(function () {
    Route::post('/logout', [AuthController::class, 'logout']);
});

Testing our work

Let's start the server again:
php artisan serve
I use Postman for this, but essentially, below are the values you need to perform in each test.

Register

Method: POST
URL: http://127.0.0.1:8000/api/register
Header fields: Accept: application/json
Body fields: name,email,password
Make up your own name, email address and password

Login

Method: POST
URL: http://127.0.0.1:8000/api/login
Headers fields: Accept: application/json
Body fields: email, password

Get User

Method: GET
URL: http://127.0.0.1:8000/api/login
Headers: Accept : application/json
Authorization: <Bearer token>
Make use of the token returned when you used the login or register API.

Logout

Method: POST
URL: http://127.0.0.1:8000/api/logout
Headers: Accept: application/json
Authorization: <Bearer token>
Make use of the token returned when you used the login or register API.