Prevent repeating almost identical code in Laravel.

huangapple go评论60阅读模式
英文:

Prevent repeating almost identical code in laravel

问题

如何防止我重复编写这些几乎相同的代码?

英文:

I have a controller in my API that contains methods that fetches various data from different tables like account statuses, account types, etc and returns it to the API consumer.

use App\Models\AccountStatus;
use App\Models\AccountType;
use App\Models\AlertLevel;

class ClientController extends Controller
{
   public function getAccountStatuses() {
        try {
            $accountStatuses = AccountStatus::all();

            return response()->json([
                'error' => false,
                'message' => 'OK',
                'account_statuses' => $accountStatuses
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => true,
                'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine()
            ], 500);
        }
    }

    public function getAccountTypes() {
        try {
            $accountTypes = AccountType::all();

            return response()->json([
                'error' => false,
                'message' => 'OK',
                'account_types' => $accountTypes
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => true,
                'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine()
            ], 500);
        }
    }

    public function getAlertLevels() {
        try {
            $alertLevels = AlertLevel::all();

            return response()->json([
                'error' => false,
                'message' => 'OK',
                'alert_levels' => $alertLevels
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => true,
                'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine()
            ], 500);
        }
    }
}

How do i prevent myself from repeating these almost identical code?

答案1

得分: 1

If you want to do some clean code, you should create a Class which will contain a function to handle your duplicate code:

class ResponseBuilder
{
    public function createResponseFromData(string $dataResponseKey, $data) 
    {
        try {
            return response()->json([
                'error' => false,
                'message' => 'OK',
                $dataResponseKey => $data
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => true,
                'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine()
            ], 500);
        }
    }
}

This will respect Single Responsibility Principle, and in your Controller, just inject it and use it:

private ResponseBuilder $responseBuilder;

public function __construct(ResponseBuilder $responseBuilder)
{
     $this->responseBuilder = $responseBuilder; 
}

public function getAccountStatuses() 
{
     $accountStatuses = AccountStatus::all();

     return $this->responseBuilder->createResponseFromData('account_statuses', $accountStatuses);
}

You should declare an Interface (ResponseBuilderInterface) to inject it, this way your Controller won't be responsible for injection.

英文:

If you want to do some clean code, you should create a Class which will contain a function to handle your duplicate code:

class ResponseBuilder
{
public function createResponseFromData(string $dataResponseKey, $data) 
{
try {
return response()->json([
'error' => false,
'message' => 'OK',
$dataResponseKey => $data
]);
} catch (\Exception $e) {
return response()->json([
'error' => true,
'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine()
], 500);
}
}
}

This will respect Single Responsability Principle, and in your Controller, just inject it and use it:

private ResponseBuilder $responseBuilder;
public function __construct(ResponseBuilder $responseBuilder)
{
$this->responseBuilder = $responseBuilder; 
}
public function getAccountStatuses() 
{
$accountStatuses = AccountStatus::all();
return $this->responseBuilder->createResponseFromData('account_statuses', $accountStatuses);
}

You should declare an Interface (ResponseBuilderInterface) to inject it, this way your Controller won't be responsible of injection.

答案2

得分: 1

Sure, here is the translated content:

好的,有许多方法可以防止重复相同的代码。这取决于开发者的技能、知识和经验。在我的情况下,我创建了一个trait文件来处理响应。

<?php

namespace App\Http\Traits;

trait ResponseHandler {
    public function successResponse($responseKey='data', $data) {
        return response()->json([
            'error' => false,
            'message' => 'OK',
            $responseKey => $data
        ]);
    }
    
    public function errorResponse($errorMessage) {
        return response()->json([
            'error' => true,
            'message' => $errorMessage
        ], 500);
    }
}

在您的ClientController.php中,您可以使用ResponseHandler.php。

<?php

use App\Models\AccountStatus;
use App\Models\AccountType;
use App\Models\AlertLevel;
use App\Http\Traits\ResponseHandler;

class ClientController extends Controller
{
    use ResponseHandler;
    public function getAccountStatuses()
    {
        try {
            $accountStatuses = AccountStatus::all();
            return $this->successResponse('account_types', $accountStatuses);
        } catch (\Exception $e) {
            return $this->errorResponse($e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine());
        }
    }
}

其他方法

  1. 尝试仓储模式
  2. 尝试服务仓储模式(我个人喜欢这种模式)

您还可以尝试Eloquent: API资源,这可以帮助您将模型和模型集合轻松转换为JSON。

英文:

Well, there can be many ways to stop repeating the identical codes. It depends on developer's skills, knowledge and experience. In my case I create A trait file to handel responses.

&lt;?php
namespace App\Http\Traits;
trait ResponseHandler {
public function successResponse($responseKey=&#39;data&#39;, $data) {
return response()-&gt;json([
&#39;error&#39; =&gt; false,
&#39;message&#39; =&gt; &#39;OK&#39;,
$responseKey =&gt; $data
]);
}
public function errorResponse($errorMessage) {
return response()-&gt;json([
&#39;error&#39; =&gt; true,
&#39;message&#39; =&gt; $errorMessage
], 500);
}}

In Your Clientcontroller.php you can use ResponseHandler.php

&lt;?php
use App\Models\AccountStatus;
use App\Models\AccountType;
use App\Models\AlertLevel;
use App\Http\Traits\ResponseHandler;
class ClientController extends Controller
{
use ResponseHandler;
public function getAccountStatuses()
{
try {
$accountStatuses = AccountStatus::all();
return $this-&gt;successResponse(&#39;account_types&#39;, $accountStatuses);
} catch (\Exception $e) {
return $this-&gt;errorResponse($e-&gt;getMessage() . &#39; &#39; . $e-&gt;getFile() . &#39; &#39; . $e-&gt;getLine());
}
}
}

Other ways:

  1. Try Repository patterns
  2. Try Service Repository Pattern (I personally like this pattern)

You should also try Eloquent: API Resources this can help you to expressively and easily transform your models and model collections into JSON.

答案3

得分: 1

在Laravel中有一个JsonResource可以帮助您构建JSON响应。

创建一个JsonResource

php artisan make:resource UserListResource

UserListResource

/**
 * 将资源转换为数组。
 *
 * @return array<string, mixed>
 */
public function toArray(Request $request): array
{
    // 在这里定义您的数据结构
    return [
        'users' => $this->resource
    ];
}

控制器

public function __invoke(Request $request)
{
    $users = $this->userService->get(); // 返回一个模型集合

    // 成功响应
    return new UserListResource($users);
}

一个处理错误响应的简单示例。

创建错误资源

php artisan make:resource ErrorResource

ErrorResource

public function with(Request $request)
{
    return [
        'code'     => 999,  // 如果需要,可以是您系统的错误代码
        'messages' => $this->resource->getMessage()
    ];
}

public function toArray(Request $request): array
{
    return [];
}

在JSON解码响应后,应该是这样的:

{
    'data': [],
    'code': 999,
    'messages': "错误消息"
}

处理异常

在app\Exceptions\Handler.php中

$this->renderable(function (Throwable $e, $request) {
    if ($request->is('api/*')) { // 确保异常发生在API而不是Web中
        return (new ExceptionResponse($e))->response()->setStatusCode(500);
    }
});

您可以在这里找到文档。

英文:

There is a JsonResource in Laravel can help you building json response.

Make a JsonResource

php artisan make:resource UserListResource

UserListResource

/**
 * Transform the resource into an array.
 *
 * @return array&lt;string, mixed&gt;
 */
public function toArray(Request $request): array
{
    // Defined your data structure here
    return [
        &#39;users&#39; =&gt; $this-&gt;resource
    ];
}

Controller

public function __invoke(Request $request)
{
    $users = $this-&gt;userService-&gt;get(); // Return a Model Collection

    // Success response
    return new UserListResource($users);
}

An simple example for handle error response.

Make error resource

php artisan make:resource ErrorResource

ErrorResource

public function with(Request $request)
{
    return [
        &#39;code&#39;     =&gt; 999,  // error code of your system if you need
        &#39;messages&#39; =&gt; $this-&gt;resource-&gt;getMessage()
    ];
}

public function toArray(Request $request): array
{
    return [];
}

After json decode the response should be:

{
&#39;data&#39;: [],
&#39;code&#39;: 999,
&#39;messages&#39;: &quot;error message&quot;
}

Handle exceptions

In app\Exceptions\Handler.php

$this-&gt;renderable(function (Throwable $e, $request) {
    if ($request-&gt;is(&#39;api/*&#39;)) { // Ensure exception is during api instead of web
        return (new ExceptionResponse($e))-&gt;response()-&gt;setStatusCode(500);
    }
});

You can find the document from here.

答案4

得分: -1

我们可以将此函数存储在一个特性中并使用它。传递模型名称,可以是任何你想要获取数据的模型。在你的情况下,account_statusesaccount_typesalert_levels

public function getData($model) {
    try {
        $data = $model::all();

        return response()->json([
            'error' => false,
            'message' => 'OK',
            'account_statuses' => $data
        ]);
    } catch (\Exception $e) {
        return response()->json([
            'error' => true,
            'message' => $e->getMessage() . ' ' . $e->getFile() . ' ' . $e->getLine()
        ], 500);
    }
}

例如:

$accountStatus = getData('AccountStatus');
$accountType = getData('AccountType');
$alertLevels = getData('AlertLevel');
英文:

We can store this function in a trait and use it. Pass on the model name it can any model from which you want fetch data. In your case account_statuses, account_types and alert_levels.

public function getData($model) {
try {
$data = $model::all();
return response()-&gt;json([
&#39;error&#39; =&gt; false,
&#39;message&#39; =&gt; &#39;OK&#39;,
&#39;account_statuses&#39; =&gt; $data
]);
} catch (\Exception $e) {
return response()-&gt;json([
&#39;error&#39; =&gt; true,
&#39;message&#39; =&gt; $e-&gt;getMessage() . &#39; &#39; . $e-&gt;getFile() . &#39; &#39; . $e-&gt;getLine()
], 500);
}
}

For eg :

$accountStatus = getData(&#39;AccountStatus&#39;);
$accountType = getData(&#39;AccountType&#39;);
$alertLevels = getData(&#39;AlertLevel&#39;);

huangapple
  • 本文由 发表于 2023年6月13日 14:07:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76462082.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定