Skip to content

Commit 6ee272a

Browse files
committed
create a service generator
1 parent f3ab891 commit 6ee272a

File tree

8 files changed

+387
-7
lines changed

8 files changed

+387
-7
lines changed

README.md

Lines changed: 181 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ RajTechnologies\Tools\ToolServiceProvider::class,
2222

2323
## URL Routes
2424

25-
| Name | URL | Description |
26-
|-----------------|---------------------|---------------------------------|
27-
| Clear Cache | clear-cache | all type cache clear in larevel |
28-
| HTTP status Code| httplist | HTTP Status Code List (cheat sheet) |
29-
| Routes List | routeslist | All Routes List |
30-
| API Routes List | routeslist?only=api | Only API Routes List |
25+
| Name | URL | Description |
26+
| ---------------- | ------------------- | ----------------------------------- |
27+
| Clear Cache | clear-cache | all type cache clear in larevel |
28+
| HTTP status Code | httplist | HTTP Status Code List (cheat sheet) |
29+
| Routes List | routeslist | All Routes List |
30+
| API Routes List | routeslist?only=api | Only API Routes List |
3131

3232
## PWA App
3333
- Open your `config/app.php` and add the following to the `providers` array:
@@ -175,6 +175,181 @@ class RepositoryServiceProvider extends ServiceProvider
175175
}
176176
}
177177
```
178+
179+
# Service Generator
180+
181+
## Table of Contents
182+
<ol>
183+
<li><a href="#features">Features</a></li>
184+
<li><a href="#installation">Installation</a></li>
185+
<li>
186+
<a href="#usage">Usage</a>
187+
<ul>
188+
<li><a href="#generate-services">Generate services</a></li>
189+
<li><a href="#generate-services-for-models">Generate services for models</a></li>
190+
<li><a href="#generate-services-for-controllers">Generate services for controllers</a></li>
191+
</ul>
192+
</li>
193+
<li>
194+
<a href="#the-service-pattern">The service pattern</a>
195+
<ul>
196+
<li><a href="#when-to-use-the-service-pattern">When to use the service pattern</a></li>
197+
<li>
198+
<a href="#how-to-use-services">How to use services</a>
199+
<ul>
200+
<li><a href="#static-methods">Static methods</a></li>
201+
<li><a href="#depency-injection">Dependency Injection</a></li>
202+
</ul>
203+
</li>
204+
</ul>
205+
</li>
206+
<li><a href="#more-generator-packages">More generator packages</a></li>
207+
<li><a href="#contributing">Contributing</a></li>
208+
<li><a href="#license">License</a></li>
209+
</ol>
210+
211+
## Usage
212+
After installation the ```php artisan make:service {name}``` will be available in the list
213+
of artisan commands.
214+
215+
### Generate Service
216+
To generate a new service use the following artisan command.
217+
```bash
218+
php artisan make:service UserService
219+
```
220+
221+
### Generate a service for a model
222+
Add a ```--service``` or ```-S``` param to generate a service for the model.
223+
```bash
224+
php artisan make:model Post --service
225+
```
226+
227+
Use the ```-a``` or ```--all``` param to generate a service, migration, seeder, factory, policy,
228+
and resource controller for the model.
229+
```bash
230+
php artisan make:model Post --all
231+
```
232+
233+
### Generate a service for a controller
234+
Add a ```--service``` or ```-S``` param to generate a service for the controller.
235+
236+
```bash
237+
php artisan make:controller PostController --service
238+
```
239+
240+
## The service pattern
241+
242+
### When to use the service pattern
243+
A common question is: where do I put my business logic? You want to keep your models thin and your controller functions
244+
skinny. There are multiple ways to archive this, extracting your business logic to the
245+
service layer is a common method. By encapsulating your business logic in a service class you
246+
are able to re-use the logic for example in your controllers, commands, jobs and middelware.
247+
248+
### How to use services
249+
Once you have made a service it is time to add your business logic. We will discus how to use a service via static methods,
250+
dependency injection and how to use it with interfaces and repositories.
251+
252+
#### Static methods
253+
a common way to use a service is to call it's methods statically. It is similar to helper functions. Let's say we have
254+
a ```PostService``` with a method to get a post based on a slug.
255+
256+
```php
257+
namespace App\Services;
258+
259+
use App\Models\Post;
260+
261+
class PostService
262+
{
263+
// Declare the function as static
264+
public static function getPostBySlug(string $slug): Post
265+
{
266+
return Post::with('tags')
267+
->where('slug', $slug)
268+
->get();
269+
}
270+
}
271+
```
272+
273+
Next you can include the service class for example your controller and call the ```getPostBySlug``` method statically.
274+
```php
275+
namespace App\Http\Controllers;
276+
277+
// Include the service
278+
use App\Services\PostService;
279+
280+
class PostController extends Controller
281+
{
282+
public function show(string $slug)
283+
{
284+
// Call the method statically from the service class
285+
$post = PostService::getPostBySlug($slug);
286+
287+
return view('posts.show', compact('post'));
288+
}
289+
}#
290+
```
291+
292+
The ```getPostBySlug``` method is in this example a very simple function but as you can see it keeps you controller skinny
293+
and and your business logic seperated. Keep in mind that static classes and methods are stateless. The class won't save
294+
any data in itself.
295+
296+
#### Dependency Injection
297+
Another popular method is to use services with dependency injection. With dependency injection you can write loosely
298+
coupled code. When done right this will improve the flexibility and maintainability of your code.
299+
300+
The ```PostService``` we used as example before will remain
301+
almost the same except we don't declare the functions inside the class as static anymore.
302+
303+
```php
304+
namespace App\Services;
305+
306+
use App\Models\Post;
307+
308+
class PostService
309+
{
310+
public function getPostBySlug(string $slug): Post
311+
{
312+
return Post::with('tags')
313+
->where('slug', $slug)
314+
->get();
315+
}
316+
}
317+
```
318+
319+
Next we inject the service into the constructor of the class where we want to use it. Inside the constructor we
320+
assign the object to the ```$postService``` class property. Now the ```$postService``` property will be callable in
321+
all functions within the class with ```$this->postService```. While typing your IDE will already typehint the functions
322+
in your PostService class, in this case only ```->getPostBySlug($slug)```.
323+
```php
324+
namespace App\Http\Controllers;
325+
326+
// Include the service
327+
use App\Services\PostService;
328+
329+
class PostController extends Controller
330+
{
331+
// Declare the property
332+
protected $postService;
333+
334+
// Inject the service into the constructor
335+
public function __construct(PostService $postService)
336+
{
337+
// Assign the service instance to the class property
338+
$this->postService = $postService;
339+
}
340+
341+
public function show($slug)
342+
{
343+
// Call the method you need from the service via the class property
344+
$post = $this->postService->getPostBySlug($slug);
345+
346+
return view('posts.show', compact('post'));
347+
}
348+
}
349+
```
350+
351+
352+
178353
## Contributing
179354

180355
- [Bhargav Raviya](https://github.com/bhargavraviya)

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"extra": {
3232
"laravel": {
3333
"providers": [
34-
"RajTechnologies\\Tools\\ToolServiceProvider"
34+
"RajTechnologies\\Tools\\ToolServiceProvider",
35+
"RajTechnologies\\Tools\\Http\\Providers\\CommandServiceProvider"
3536
]
3637
}
3738
}

src/Console/MakeController.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace RajTechnologies\Tools\Console;
4+
5+
use Illuminate\Routing\Console\ControllerMakeCommand;
6+
use Illuminate\Support\Str;
7+
use Symfony\Component\Console\Input\InputOption;
8+
9+
class MakeController extends ControllerMakeCommand
10+
{
11+
/**
12+
* @return void
13+
*/
14+
public function handle()
15+
{
16+
parent::handle();
17+
18+
if ($this->option('service')) {
19+
$this->createService();
20+
}
21+
}
22+
23+
/**
24+
* Create a model factory for the model.
25+
*
26+
* @return void
27+
*/
28+
protected function createService()
29+
{
30+
$nameInput = Str::replace('Controller', '', $this->getNameInput());
31+
$name = Str::studly($nameInput);
32+
33+
$this->call('make:service', [
34+
'name' => "{$name}Service"
35+
]);
36+
}
37+
38+
/**
39+
* @return array
40+
*/
41+
public function getOptions(): array
42+
{
43+
$options = parent::getOptions();
44+
$options[] = ['service', 's', InputOption::VALUE_NONE, 'Generate a service for the controller'];
45+
46+
return $options;
47+
}
48+
}

src/Console/MakeModel.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace RajTechnologies\Tools\Console;
4+
5+
use Illuminate\Foundation\Console\ModelMakeCommand;
6+
use Illuminate\Support\Str;
7+
use Symfony\Component\Console\Input\InputOption;
8+
9+
class MakeModel extends ModelMakeCommand
10+
{
11+
/**
12+
* @return void
13+
*/
14+
public function handle()
15+
{
16+
parent::handle();
17+
18+
if ($this->option('all')) {
19+
$this->input->setOption('service', true);
20+
}
21+
22+
if ($this->option('service')) {
23+
$this->createService();
24+
}
25+
}
26+
27+
/**
28+
* Create a model factory for the model.
29+
*
30+
* @return void
31+
*/
32+
protected function createService()
33+
{
34+
$name = Str::studly($this->getNameInput());
35+
36+
$this->call('make:service', [
37+
'name' => "{$name}Service"
38+
]);
39+
}
40+
41+
/**
42+
* @return array
43+
*/
44+
public function getOptions(): array
45+
{
46+
$options = parent::getOptions();
47+
$options[] = ['service', 'S', InputOption::VALUE_NONE, 'Generate a service for the model'];
48+
49+
return $options;
50+
}
51+
}

src/Console/MakeService.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace RajTechnologies\Tools\Console;
4+
5+
use Illuminate\Console\GeneratorCommand;
6+
7+
class MakeService extends GeneratorCommand
8+
{
9+
/**
10+
* The name and signature of the console command.
11+
*
12+
* @var string
13+
*/
14+
protected $signature = 'make:service {name}';
15+
16+
/**
17+
* The console command description.
18+
*
19+
* @var string
20+
*/
21+
protected $description = 'Create a new service class';
22+
23+
/**
24+
* The type of class being generated.
25+
*
26+
* @var string
27+
*/
28+
protected $type = 'Service';
29+
30+
/**
31+
* Get the stub file for the generator.
32+
*
33+
* @return string
34+
*/
35+
protected function getStub()
36+
{
37+
return __DIR__.'/../../stubs/service.stub';
38+
}
39+
40+
/**
41+
* Get the default namespace for the class.
42+
*
43+
* @param string $rootNamespace
44+
* @return string
45+
*/
46+
protected function getDefaultNamespace($rootNamespace)
47+
{
48+
return $rootNamespace.'\Services';
49+
}
50+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace RajTechnologies\Tools\Http\Providers;
4+
5+
use Illuminate\Foundation\Providers\ArtisanServiceProvider;
6+
use RajTechnologies\Tools\Console\MakeController;
7+
use RajTechnologies\Tools\Console\MakeModel;
8+
9+
class CommandServiceProvider extends ArtisanServiceProvider
10+
{
11+
/**
12+
* Register the command.
13+
*
14+
* @return void
15+
*/
16+
protected function registerModelMakeCommand()
17+
{
18+
$this->app->singleton('command.model.make', function ($app) {
19+
return new MakeModel($app['files']);
20+
});
21+
}
22+
23+
/**
24+
* Register the command.
25+
*
26+
* @return void
27+
*/
28+
protected function registerControllerMakeCommand()
29+
{
30+
$this->app->singleton('command.controller.make', function ($app) {
31+
return new MakeController($app['files']);
32+
});
33+
}
34+
}

0 commit comments

Comments
 (0)