How to create a module with your Laravel application?
Mohammed Minuddin Peal
Full Stack Developer, Javascript, PHP, Laravel, Zend, Symfony, Vue, React, Node, Express, Typescript, MongoDB, Oracle, MySql, PgSql, Docker, Tailwind css, Bootstrap
Laravel awesome PHP framework, Php developers become mighty because of Laravel powerful features, and it has passed long time , during this time laravel has introduced many many things like IOC, event, schedule, email, notification, console command, real time notification, very flexible integration process with javascript framework like vue js, reactjs and package creation etc, as a senior developer you could also apply your way with Laravel because Laravel is liberal to apply software engineering process like SOLID principle, Today I will share with you my experience when I am working with my project how did I modular my application code?
At first I want to clear that module in laravel almost like a package except module will not take composer.json file it will use root composer.json file, and it is place in app folder, here I will show you the way of module I have used, it is my own way to do it, I don’t know others developers how to they do. Maybe they could do it like me, or to do it in their way.
So, let’s start our topic, your attention please. Here I am showing you how to create a module for blog, maybe in future we have to define others modules like product module, inventory module, store module etc to do so at first we will learn how to create module,
At first download fresh copy of laravel using below command
$ composer create-project — prefer-dist laravel/laravel laravelModule
After completing the installation, test it from your command prompt
$ php artisan serve
Our installation is successes. Now open up your .env file put your database name, username name password and save .env file
DB_DATABASE = blog DB_USERNAME = root DB_PASSWORD =
then run artisan command $ php artisan make:auth to to scaffold all of the routes and views you need for authentication.
Not working because I am using here Laravel 6, make:auth omitted from Laravel 6, instead of this you have to do so like below in the picture
That means you need to install a package $ composer require laravel/ui after that you have to run these commands $ php aritsan ui vue— auth then you have to run below npm commands also, otherwise your authentication related blade file will render without assets file like css and js.
$ npm install and $ npm run watch to compile your assets to to compile your fresh scaffolding.
Now run $ php artisan migrate command to create tables into database, now our migration is completed.
From your browser hit https://localhost:8000/register to create a user after user is created browser will redirect you home page of the dashboard.
At this point our Laravel installation is completed successfully.
So let’s start to create our blog module open up your project using your favorite IDE, my favorite IDE is vscode, create your module folder inside app folder name it Blog, so that you folder structure look like below.
Inside Blog folder I have created several necessary folders like AbstractModel, config, Consumes, Contracts, Controllers, migrations, Models, Render, views and BlogServiceProvider.php for our blog module. Because of the module I am showing you is an advance level module that’s why it is bit more complex structures and following SOLID principle. Now I am explaining you php files inside these folders.So than let’s start, under AbstractModel folder I have created a abstract class file and name it AbstractComsumeModel.php is controlling our strategy which is implemented IConsume interface, this file mapping our derived class strategy of our Blog application, the file looks like below.
<?php namespace App\Blog\AbstractModel; use App\Blog\Contracts\IConsume; abstract class AbstractConsumeModel implements IConsume { /** * Show records * * @return json object */ public function show(){} /** * Create record * * @param array $data * @return void */ public function create(array $data){} /** * Update record * * @param [type] $id * @return void */ public function update($id){} /** * Delete record * * @param [type] $id * @return void */ public function delete($id){} }
And inside our Contracts directory IConsume.php is our interface class looks like below
<?php namespace App\grubapi\Contracts; Interface IConsumer { /** * Show records * * @return json object */ public function show(); /** * Create record * * @param array $data * @return void */ public function create(array $data); /** * Update record * * @param [type] $id * @return void */ public function update($id); /** * Delete records * * @param [type] $id * @return void */ public function delete($id); }
And inside our render folder we have define our main context class Render.php which will control our derived objects dynamically at run time.
<?php namespace App\Blog\Render; use App\Blog\AbstractModel\AbstractConsumeModel; class Render { protected $consume; /** * Pass AbstractComsumeModel instance * * @param AbstractComsumeModel $parameter */ public function __construct(AbstractConsumeModel $consume) { $this->consume = $consume; } /** * Access methods and properties of the parameters * * @return AbstractParameterModel */ public function renderResource():AbstractConsumeModel { return $this->consume; } }
Inside config folder I have created blog module configuration file, where I have listed all derived classes of AbstractConsumeModel class, which is inside consume folder. And this config file will be published under Laravel config directory when ever I will run the command php artisan vendor:publish. I will show you every steps within couple of minutes stay with me please. Now look at blog.php file inside config folder below.
<?php return [ ‘blog’ => [ ‘post’ => \App\blog\Consumes\Posts::class, // other's may come depends on your needs ] ];
So let’s look at the derive class Posts.php inside consumes folder, which is extending our AbstractConsumeModel class.
<?php namespace App\Blog\Consumes; use App\Blog\AbstractModel\AbstractConsumeModel; use App\Blog\Models\Post; class Posts extends AbstractConsumeModel { /** * Show records * * @return json object */ public function show() { $posts = Post::all(); return response()->json($posts, 200); } /** * Create record * * @param array $data * @return void */ public function create(array $data){} /** * Update record * * @param [type] $id * @return void */ public function update($id){} /** * Delete record * * @param [type] $id * @return void */ public function delete($id){} }
Now let’s create our Model file and migration file, our model file located inside our Modles folder and migration file is located inside migrations folder. Our model file structure looks like below.
<?php namespace App\Blog\Models; use Illuminate\Database\Eloquent\Model; class Post extends Model { // }
Now create our migration file for our posts table and name our migration file 2019_09_05_081439_create_posts_table.php and it looks like below.
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreatePostsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('title'); $table->text('body'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('posts'); } }
At this point our module is created from the architectural point of view, Now I am seeding my database, for that at first I am creating my model factory. For that type the command below
$ php artisan make:factory PostFactory — model=Blog/Models/Post
<?php /** @var \Illuminate\Database\Eloquent\Factory $factory */ use App\Blog\Models\Post; use Faker\Generator as Faker; $factory->define(Post::class, function (Faker $faker) { return [ 'title' => $faker->sentence($nbWords = 6), 'body' => $faker->paragraph($nbSentences = 3) ]; });
Using the model factory I would like to create 50 fake records, that’s why I am using Faker.
Now it is time to seeding our posts table, for that I have created seeder class using the command $ php artisan make:seeder PostsTableSeeder
<?php use Illuminate\Database\Seeder; use App\Blog\Models\Post; class PostsTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { factory(Post::class, 50)->create(); } }
After that list our PostTableSeeder into our main DatabaseSeeder class to run db:seed
<?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call(PostsTableSeeder::class); } }
To seeds our posts table type the command looks like below
$ php artisan db:seed — class=”PostsTableSeeder” 50 fake records will be created into posts table.
Now, than our module almost done, just now we have to inform Laravel hey Laravel I have a service I want to list it in your IOC container, for that let’s examine our BlogServiceProvider.php file, there I am setting up my main context class as of my service and it is serving blog derived classes objects dynamically at run time, the file looks like below
<?php namespace App\Blog; use Illuminate\Support\ServiceProvider; use App\Blog\Render\Render; class BlogServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { $this->publishConfig(); //$this->publishView(); // if you want to use your views from your module $this->loadMigration(); } /** * Register any application services. * * @return void */ public function register() { $this->app->bind('resources', function($app, $consume) { return new Render(new $consume['resource']); }); } /** * Publish package config file to framework config folder */ protected function publishConfig() { $this->publishes([ __DIR__.'/config/blog.php' => config_path('blog.php') ]); $this->mergeConfigFrom(__DIR__.'/config/blog.php', 'blog'); } /** * Load application view public function publishView() { $this->loadViewsFrom(__DIR__.'/views', 'view'); } */ /** * Load Application migration to create database */ public function loadMigration() { $this->publishes([ __DIR__.'/migrations/' => database_path('migrations') ]); $this->loadMigrationsFrom(__DIR__.'/migrations'); } }
Look at the register method, here I have bind my service and name it `resources` using the IOC container I am changing derived class object at run time, if you are experience in OOP then you would understand how it is working with real life project.
Because our module is not a Laravel traditional package, it will not contain composer.json file, it is under app folder and is resolved by the application’s root composer.json file through.
"autoload": { "psr-4": { "App\\": "app/" }, }
That is why our service provider class will not take the auto discovery facility, so we need to list our service provider class manually at the app.php ‘s providers config array.
'providers' => [ ..... App\Blog\BlogServiceProvider::class, ],
Now from your project directory open up your terminal and type $ php artisan vendor:publish
Which provider or tag's files would you like to publish?: [0 ] Publish files from all providers and tags listed below [1 ] Provider: App\Blog\BlogServiceProvider [2 ] Provider: Fideloper\Proxy\TrustedProxyServiceProvider [3 ] Provider: Illuminate\Foundation\Providers\FoundationServiceProvider [4 ] Provider: Illuminate\Mail\MailServiceProvider [5 ] Provider: Illuminate\Notifications\NotificationServiceProvider [6 ] Provider: Illuminate\Pagination\PaginationServiceProvider [7 ] Provider: Laravel\Tinker\TinkerServiceProvider [8 ] Tag: laravel-errors [9 ] Tag: laravel-mail [10] Tag: laravel-notifications [11] Tag: laravel-pagination
Press $ 1 the config file blog.php, migration file 2019_09_05_081439_create_posts_table.php form migrations folder will be published into the mapping folders where I have mapped into BlogServiceProvider.php file, please check the path from BlogServiceProvider.php file.
Now practically our module is created let’s try our service from our controller file, for that let’s create our controller file and name it PostController.php under Controllers folder inside Blog folder.
<?php namespace App\Blog\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use App\Http\Requests; use App; class PostController extends Controller { protected $rescource; //protected $category; //If we have category /** * Get parameters instance from IOC container */ public function __construct() { $this->rescource = App::make('resources', [ 'resource' => config('blog.blog.post') ]); /** If you have a category class than /*$this->category = App::make('resources', [ 'resource' => config('blog.blog.category') ]); */ } /** * * @param Request request * * @return json object */ public function showPosts(Request $request) { return $this->rescource ->renderResource() ->show(); } /** * If we want to show category using IOC container * @param Request request * * @return json object public function showCategory(Request $request) { return $this->category ->renderResource() ->show(); } */ }
Now it is time to check our module working or not, let’s create our route into our web.php file
Route::get(‘testposts’, ‘\App\Blog\Controllers\PostController@showPosts’);
Open up your favorite browser type https://localhost:8000/testposts, you will see the output like below
That’s all, I hope you are enjoying this tutorial, and I am ensuring you that, this is really important to develop your application modular, what ever size it has, to be a good software engineer you should not repeat everything from first, keep always smile :), bye for this moment.
Full Stack Developer | PHP | Laravel | Codeigniter | CakePHP | JavaScript | VueJs | NodeJs | MySQL | Rest API | Web Automation | DigitalOcean Cloud
5 年greet job, sir :)