An open API service indexing awesome lists of open source software.

https://github.com/elishamutang/saas-jokes-api

REST API for Jokes Management System built using Laravel
https://github.com/elishamutang/saas-jokes-api

laravel laravel-sanctum php rest-api test-driven-development

Last synced: 2 months ago
JSON representation

REST API for Jokes Management System built using Laravel

Awesome Lists containing this project

README

          

## Install Laravel installer & Update

```shell≈
composer global require laravel/installer
composer global update
```

## Create Application from Scratch

```shell
laravel new l12-base
```

| Step | Value |
|-----------------------|----------|
| Project Name | l12-base |
| Starter Kit | None |
| Test Framework | Pest |
| Database (dev) | SQLite |
| NPM install and Build | Yes |

## Add Sanctum, and other Packages

We will add:

- [Laravel Breeze](https://laravel.com/docs/sanctum) (with Sanctum Authentication)
- Laravel Pint (Code Tidy +)
- [Laravel PHP Stan](https://github.com/larastan/larastan) (Static Testing)
- [Laravel Debug Bar](https://laraveldebugbar.com) (Development toolbar)
- [Laravel Livewire](https://livewire.laravel.com) (SPA components in PHP)
- [Laravel Telescope](https://laravel.com/docs/telescope) (Application Monitoring)

Note that with Windows Systems not having the `pcntl` extension for PHP we cannot install Laravel Pail.

For non Windows users, or those using Windows Subsystem for Linux, please feel free to install and use Laravel Pail, a
log streaming package.

---

### Installing Breeze

```shell
cd l12-base

composer require laravel/breeze

php artisan breeze:install
```

| Step | Value |
|-----------|-------------------|
| Framework | Blade with Alpine |
| Dark Mode | No |
| Testing | Pest |

#### Remove the postcss.config.js

```shell
rm postconfig.config.js
```

#### Add FontAwesome NPM Package

```shell
npm install @forawesome/fontawesome-free
npm update
```

#### Update any node dependencies

```shell
npm update
```

#### Update the following files:

- vite.config.js
- tailwind.config.js
- resources/css/app.css
- resources/js/app.js

##### vite.config.js

Open the `vite.config.js` file and update the contents to be:

```js
import {defineConfig} from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
tailwindcss(),
]
});
```

##### tailwind.config.js

Open the `tailwind.config.js` file and update the contents to be:

```js
import defaultTheme from 'tailwindcss/defaultTheme';
import forms from '@tailwindcss/forms';

/** @type {import('tailwindcss').Config} */
export default {
content: [
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
'./storage/framework/views/*.php',
'./resources/views/**/*.blade.php',
],

theme: {
extend: {
fontFamily: {
sans: ['Figtree', ...defaultTheme.fontFamily.sans],
},
},
},

plugins: [forms],
};
```

##### resources/css/app.css

Open the `resources/css/app.css` file and update the contents to be:

```css
@import 'tailwindcss';
@import "@fortawesome/fontawesome-free/css/all.css";

@theme {
--font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
}
```

##### resources/js/app.js

Open the `resources/js/app.js` file and update the contents to be:

```js
import './bootstrap';
```

---

### Install Laravel Pint (Code Tidy +)

Install the composer package for "development mode only":

```shell
composer require laravel/pint --dev
```

---

### Install Laravel Stan (Static Testing)

Install the composer package for "development mode only",
and create new file `phpstan.neon` in the root folder of the project:

```shell
composer require --dev "larastan/larastan"

touch phpstan.neon
```

Edit the `phpstan.neon` (this is a YAML style file) and add:

```neon
includes:
- vendor/larastan/larastan/extension.neon
- vendor/nesbot/carbon/extension.neon

parameters:

paths:
- app/

# Level 10 is the highest level
level: 5

# ignoreErrors:
# - '#PHPDoc tag @var#'
#
# excludePaths:
# - ./*/*/FileToBeExcluded.php
```

---

### Install Laravel Debug Bar (Development toolbar)

Install the composer package for "development mode only":

```shell
composer require barryvdh/laravel-debugbar --dev
```

---

### Install Laravel Livewire (SPA components in PHP)

Install Livewire and publish its assets:

```shell
composer require livewire/livewire

php artisan vendor:publish --tag=livewire:assets --ansi --force
```

---

### Install Laravel Telescope (Application Monitoring)

```shell
composer require laravel/telescope
php artisan telescope:install
php artisan migrate
```

## Publish Assets (Error messages, pagination et al.)

We will publish a number of assets so that they may be customized as we write our code.

```shell
php artisan vendor:publish --tag=laravel-errors
php artisan vendor:publish --tag=laravel-mail
php artisan vendor:publish --tag=laravel-pagination
php artisan vendor:publish --tag=livewire:pagination
```

### Execute First Static Analysis

Run PHPStan using:

```shell
./vendor/bin/phpstan analyse --memory-limit=2G
```

> ###### Note:
>
> The memory limit of 2GB is needed, the default 128MB is simply not enough for
> analysing Laravel Apps.

Any errors? Fix them at this point.

#### Example PhpStan Output

```text
Note: Using configuration file C:\Users\goulda\Source\Repos\l12-base\phpstan.neon.
104/104 [============================] 100%

------ ---------------------------------------------------------------------------
Line app\Http\Controllers\StaticPageController.php
------ ---------------------------------------------------------------------------
22 Method App\Http\Controllers\StaticPageController::about() should return
Illuminate\View\View but return statement is missing.
27 Method App\Http\Controllers\StaticPageController::contact() should return
Illuminate\View\View but return statement is missing.
32 Method App\Http\Controllers\StaticPageController::privacy() should return
Illuminate\View\View but return statement is missing.
37 Method App\Http\Controllers\StaticPageController::terms() should return
Illuminate\View\View but return statement is missing.
------ ---------------------------------------------------------------------------

[ERROR] Found 4 errors

```

#### Must Verify Email Error

The following is a fix we discovered, **BUT** it is important **NOT** to use this for **EVERY** error
you encounter, as that defeats the purpose of the static analysis:

Open the `app/Http/Controllers/Auth/VerifyEmailController.php` file and locate the lines:

```php
if ($request->user()->markEmailAsVerified()) {
event(new Verified($request->user()));
}
```

Add a single line as shown below:

```php
if ($request->user()->markEmailAsVerified()) {
/** @phpstan-ignore-next-line */
event(new Verified($request->user()));
}
```

> ###### Aside:
>
> We may need to see of Taylor and the Laravel crew will look
> at this error and publish a patch.

### Execute First Laravel Pint

Execute Laravel Pint to fix any code structure errors.

This will ensure your code matches the Laravel style.

```shell
./vendor/bin/pint
```

### Add New Environment Variable

Open the `.env` file and between the `APP_URL` and `APP_LOCALE` add the `APP_VERSION` (also update the Locale to `en_AU`
as shown):

```ini
APP_URL = http://localhost:8000

APP_VERSION = "0.0 α"

APP_LOCALE = en_AU
```

## Execute the Development Instance

We can run a development server in a number of different ways.

For this we will use the Terminal and execute the "dev" server script.

Either:
Split the current terminal into 2 halves, or
Open a new terminal instance

Verify you are in the correct folder, if not use the cd command:

> This presumes you are in a folder location such as `Source/Repos`.

```shell
cd l12-base
composer run dev
```

This will execute the dev script that is in the `composer.json` file.

After a few moments, you will be able to open the `http://localhost:8000` location in a
browser and see the default home page:

![img.png](_docs/images/default-landing-page.png)

## Adding Default Users

To make it easier to test the application we will add a "seeder" that will fill the database
with some default users.

This is ideal for the development and testing process.

### Create a User Seeder

Execute:

```shell
php artisan make:seeder UserSeeder
```

Open the newly created `database/seeders/UserSeeder.php` file and update the `run` method to
read:

```php
$seedUsers = [
[
'id' => 99,
'name' => 'Super Admin',
'email' => 'supervisor@example.com',
'password' => 'Password1',
'email_verified_at' => now(),
'roles' => ['super-user', 'admin',],
'permissions' => [],
],

[
'id' => 100,
'name' => 'Admin I Strator',
'email' => 'admin@example.com',
'password' => 'Password1',
'email_verified_at' => now(),
'roles' => ['admin',],
'permissions' => [],
],

[
'id' => 200,
'name' => 'Staff User',
'email' => 'staff@example.com',
'password' => 'Password1',
'email_verified_at' => now(),
'roles' => ['staff',],
'permissions' => [],
],

[
'id' => 300,
'name' => 'Client User',
'email' => 'client@example.com',
'password' => 'Password1',
'email_verified_at' => now(),
'roles' => ['client',],
'permissions' => [],
],

[
'id' => 301,
'name' => 'Client User II',
'email' => 'client2@example.com',
'password' => 'Password1',
'email_verified_at' => null,
'roles' => ['client',],
'permissions' => [],
],

[
'id' => 302,
'name' => 'Client User III',
'email' => 'client3@example.com',
'password' => 'Password1',
'email_verified_at' => null,
'roles' => ['client',],
'permissions' => [],
],
];

foreach ($seedUsers as $newUser) {

// grab the roles & additional permissions from the seed users
$roles = $newUser['roles'];
unset($newUser['roles']);

$permissions = $newUser['permissions'];
unset($newUser['permissions']);

$user = User::updateOrCreate(
['id' => $newUser['id']],
$newUser
);

// Uncomment these lines when using Spatie Permissions, to
// assign the role and additional permissions to the users:
// $user->assignRole($roles);
// $user->assignPermissions($permissions);

}

// Uncomment the line below to create (10) randomly named users using the User Factory.
// User::factory(10)->create();
```

To run this seeder only we can use:

```shell
php artisan db:seed UserSeeder
```

To add the seeder to execute when performing a fresh migration and seed use:

Edit the `database/migrations/DatabaseSeeder.php` file, and update the code tobe:

```php
public function run(): void
{

$this->call(
[
// When using Spatie Permissions, perform the Role / Permission seeding FIRST
UserSeeder::class,
// Add further seeder classes here
]
);

}
```

> ### ⚠️ WARNING:
>
> This performs a total database reset and SHOULD NOT be used on production applications.
>
>
> To execute this and reset the database and any logged-in sessions in one go use:
>
> ```shell
> php artisan migrate:fresh --seed
> ```

## Add Static page Controller

We will creat a static page controller that will handle pages that do not perform any
add/edit/delete actions.

Generally, we look at these pages being:

- Home (Welcome)
- Privacy
- License
- About
- Contact Us
- Terms

and so on.

Create the static page controller using:

```shell
php artisan make:controller StaticPageController
```

> ###### Important:
>
> Always name controllers with `Controller` as the last word in the name.

### Add the Static Page Methods to the Controller

Open the new `app/Http/Controllers/StatsicPageController.php` file and add the following
static page methods:

```php
/**
* Display site 'Welcome/Index' page
*
* @return View
*/
public function home(): View
{
return view('static.welcome');
}

/**
* Display 'About Us' page
*
* @return View
*/
public function about(): View
{
// return view('static.about');
}
```

### Edit the Routes

Open the `routes/web.php` file and update it..

Add the required `use` lines:

```php
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\StaticPageController;
use Illuminate\Support\Facades\Route;
```

Update the Home (Welcome) page route

```php

Route::get('/', [StaticPageController::class, 'home'])
->name('home');

Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'dashboard'])
->name('dashboard');
});

Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});

require __DIR__ . '/auth.php';
```

## Test USers

For this template, we have the following test users:

| Name | Username | Password | Role | Verified |
|-----------------|------------------------|-----------|-------------|----------|
| Super Admin | supervisor@example.com | Password1 | Super-Admin | Y |
| Admin I Strator | admin@example.com | Password1 | Admin | Y |
| Staff User | staff@example.com | Password1 | Staff | Y |
| Client User | client@example.com | Password1 | Client | Y |
| Client User II | client2@example.com | Password1 | Client | N |
| Client User III | client3@example.com | Password1 | Client | N |

### Create a Dashboard Controller:

```shell
php artisan make DashboardController
```

Edit the new `app/Http/Controllers/DashboardController.php` file, adding the missing lines
from the code below:

```php
class DashboardController extends Controller
{

public function dashboard(): View
{
$user = auth()->user();

return view('static.dashboard')
->with('user', $user);
}
}

```

We updated the dashboard route in the previous step.

## Admin Page Layout

- Create Admin Layout Component
- Move the view to resource/views/layout and rename to admin.blade.php
- Create an Admin Page Controller
- Create Admin Home page view
- Create Admin Navigation layout view
- Create admin route in routes/web.php

```shell
php artisan make:component AdminLayout

mv resources/views/components/admin-layout.blade.php resources/views/layout/admin.blade.php

phg artisan make:controller Admin/AdminController

mkdir resources/views/admin
touch resources/views/admin/index.blade.php
touch resources/views/layouts/admin-navigation.blade.php
```

#### Admin Page Layout

In the `admin/index.blade.php` file add:

```php



{{ __('Admin Zone') }}




{{__('Statistics')}}









1,234


{{ __('Jokes') }}










65


{{ __('Categories') }}










{{ $userCount }}


{{ __('Users') }}










674,865


{{ __('Passengers') }}










3


{{ __('Roles') }}










23,567,890


{{ __('Unique Visitors') }}










219


{{ __('Logged In') }}







{{__('System')}}








{{ env('APP_VERSION')??"development" }}


{{__('Version')}}











{{ env('APP_ENV')??'Unknown' }}


{{__('Environment')}}




```

#### Admin Navigation Layout

in the `admin/layouts/admin-navigation.blade.php` add:

```php





Home





{{ __('Admin Home') }}



{{ __('Dashboard') }}





{{ __('Users') }}





{{ __('Accounts') }}


{{ __('Suspended') }}


{{ __('Banned Users') }}



{{ __('Jokes') }}



{{ __('Categories') }}





{{ __('Security') }}






{{ __('Roles') }}


{{ __('Permissions') }}



{{ __('Link X') }}




@csrf


{{ __('Log Out') }}




Admin Istrator

admin@example.com





```

> #### ℹ️ Remember
>
> The repository will always have the most up-to-date version of the template code.

#### Side Nav Link Component

Create a new nav component using:

```shell
touch resources/views/components/side-nav-link.blade.php
```

Add the following:

```php
@props(['active'])

@php
$classes = ($active ?? false)
? 'block px-4 py-2 text-sm font-medium
text-gray-500 hover:text-gray-700
hover:bg-gray-200
focus:border-indigo-700
focus:outline-none
transition duration-250 ease-in-out'
: 'block px-4 py-2 text-sm font-medium
text-gray-500 hover:text-gray-700 focus:text-gray-700
hover:bg-gray-200
hover:border-gray-300 focus:border-gray-300
focus:outline-none
transition duration-250 ease-in-out';
@endphp

merge(['class' => $classes]) }}
>
{{ $slot }}

```

Edit the `routes/web.php` file, and find the lines:

```php

Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
```

Immediately BEFORE this, add:

```php
Route::middleware(['auth', 'verified'])
->prefix('admin')
->name('admin.')
->group(function () {
Route::get('/', [AdminController::class, 'index'])->name('index');
});
```

### Run Pint

Execute Laravel Pint to tidy code:

```shell
./vendor/bin/pint
```

Example of output, actually run on this code:

```text
✓........✓.✓.✓..........................✓✓...✓...........

───────────────────────────────────────────────────────────────────────── Laravel
FIXED ........................................ 57 files, 7 style issues fixed
✓ app\Http\Controllers\Admin\AdminController.php method_argument_space, no_unuse…
✓ app\Http\Controllers\Auth\VerifyEmailController.php phpdoc_indent
✓ app\Http\Controllers\DashboardController.php class_attributes_separation, no_u…
✓ app\Http\Controllers\StaticPageController.php class_attributes_separation, no_…
✓ database\seeders\DatabaseSeeder.php no_unused_imports, blank_line_after_namesp…
✓ database\seeders\UserSeeder.php no_trailing_comma_in_singleline, no_unused_imp…
✓ routes\web.php concat_space, no_extra_blank_lines

```

---

- Blade Templates circa Laravel 11
- Navigation bar on guest and app layouts
- Footer in guest and app layouts
- Email Verification enabled
- [Font Awesome 6 (Free)](https://fontawesome.com)

# After Cloning

The following steps will be done:

- cd into folder
- create a database.sqlite file
- install npm packages
- install composer packages
- migrate and seed

```shell
cd FOLDRE_NAME
touch database/database.sqlite
npm i
npm update
composer install
composer update
php artisan migrate:fresh --seed

```

## Tutorials, Articles & References

Tutorials and Articles on the individual components

McDougall, S. (2022, June 20). Running PHPStan on max with Laravel - Laravel News. Laravel
News. https://laravel-news.com/running-phpstan-on-max-with-laravel

Laravel.io. (2024). How to get your Laravel app from 0 to 9 with Larastan | Laravel.io.
Laravel.io. https://laravel.io/articles/how-to-get-your-laravel-app-from-0-to-9-with-larastan

Larastan. (2025, June 20). GitHub - larastan/larastan: ⚗️ Adds code analysis to Laravel improving developer productivity
and code quality. GitHub. https://github.com/larastan/larastan