많은 양의 GET 매개 변수를 가져 와서 이에 따라 쿼리를 깔끔하게 필터링하려면 어떻게해야합니까?

세르지오 E. 디아즈

상대적으로 많은 양의 매개 변수를 가져와 쿼리를 구문 분석하고 제공 여부에 따라 데이터를 가져 오는 Laravel Lumen에서 빌드중인 RESTful API 용 컨트롤러가 있습니다. 예를 들면

GET /nodes?region=California
GET /nodes?ip=127.0.0.1

나는 현재 생성자에서 매개 변수 배열을 만들고 (루멘에서 원시 get 배열을 얻는 방법을 알 수 없었고 이미 다른 매개 변수가 있기 때문에 불편할 것이기 때문에) 필터링하고 있습니다. null 값 (쿼리에없는 경우 값을 null로 설정합니다).

이제 배열의 각 값을 필터링 할 때 foreach 배열을 사용합니다. 이것은 너무 많은 코드없이 할 수있는 가장 깨끗한 방법입니다 (컨트롤러를 너무 뚱뚱하게 만들고 싶지 않습니다.). 함수 / 클래스를 분리하여 깔끔하게 수행 할 수있는 다른 방법이 있습니까?

내 생성자 코드는 다음과 같습니다.

/**
 * Get some values before using functions.
 * 
 * @param Request $request Instance of request.
 */
public function __construct(Request $request)
{
    $this->offset = (int) $request->input('offset', 0);

    // TODO: I'm not sure how to implement this, code in question
    $this->filters = [
        'region' => $request->input('region', null),
        'name' => $request->input('name', null),
        'ip' => $request->input('ip', null)
    ];

    $this->filters = array_filter($this->filters, function ($v) {
        return !is_null($v);
    });

    // Set a sane SQL limit.
    $this->limit = 5;
    $this->request = $request;
}

그리고 컨트롤러 코드 :

/**
 * List all nodes.
 * 
 * @return [string] [JSON containing list of nodes, if sorted.]
 */
public function all()
{
    try {
        // use filters provided
        $data =  Nodes::limit($this->limit)->offset($this->offset);

        foreach ($this->filters as $filter => $value) {
            $data->where($filter, $value);
        }

        $data = $data->get();
        $response = $this->respond($data);
    } catch (\Exception $e) {
        $response = $this->respondServerError('Could not retrieve data from database.');
    }

    return $response;    
}
stratedge

따라서 API에서 리소스 목록 필터링을 수행해야 할 때마다 수행하는 방법은 다음과 같습니다.

하지만 먼저 시작하기 전에 컨트롤러 메서드에있을 때 Request 객체를 가져 오는 것에 관한 빠른 팁 : 함수에 Request $request대한 매개 변수로 추가 all()하면 생성자와 동일한 $ request 변수에 액세스 할 수 있습니다. . 따라서 완전한 서명은 public function all(Request $request). 컨트롤러 메서드에는 다른 클래스 생성자가 Laravel / Lumen에서 얻는 것과 동일한 매직 종속성 주입이 있습니다. 또는 함수에서 항상 app()특정 클래스의 객체를 제공 하도록 함수에 요청할 수 있습니다 . Request 객체는 Container에서 'request'에만 바인딩되어 있으므로 전체 클래스 이름 또는 'request'만 요청할 수 있습니다.$request = app('request');

따라서 요청 객체가 있으면 컨트롤러 메서드 내에서 각 필터가 얼마나 복잡한 지에 따라 그룹으로 또는 하나씩 각 필터를 살펴보고 싶습니다. 때로는 필터가 배열로 분해되어야하는 쉼표로 구분 된 ID 목록처럼 복잡합니다. 그래도 단순한 문자열 필터라면 목록을 배열에 넣고 실행하는 경향이 있습니다.

다음은 몇 가지 아이디어를 설명하는 예제 함수입니다.

public function getIndex(Request $request)
{
    //Create a User object to append WHERE clauses onto
    $user = app('App\Models\User');

    //Run through our simple text fields
    foreach(['first_name', 'last_name', 'region', 'ip'] as $field) {
        if ($request->has($field)) {
            $user->where($field, $request->input($field));
        }
    }

    //This field uses a LIKE match, handle it separately
    if ($request->has('email')) {
        $user->where('email', LIKE, '%' . $request->input('email') . '%');
    }

    //This field is a list of IDs
    if ($request->has('id')) {
        $ids = explode(',', $request->input('id'));
        $user->whereIn('id', $ids);
    }

    //Use pagination
    $users = $user->paginate(25);

    /**
     * Continue with the rest of response formatting below here
     */
}

결과를 제한하기 위해 페이지 매김 기능을 사용했음을 알 수 있습니다. 리소스를 나열하는 API 엔드 포인트를 빌드 할 때 첫 번째, 이전, 다음 및 마지막 결과 페이지를 가져 오는 방법에 대한 헤더 (내 기본 설정) 또는 응답 본문 정보를 입력 할 수 있습니다. Laravel의 Pagination 기능은 links()메서드를 사용하여 대부분의 링크를 구성 할 수 있기 때문에이를 쉽게 만듭니다 .

안타깝게도 요청에서 전달 된 필터 매개 변수를 알려야 생성 된 링크에 추가 할 수 있습니다. 그렇지 않으면 필터없이 링크를 다시 얻을 수 있으므로 클라이언트가 페이징에 그다지 좋지 않습니다.

따라서 여기에 페이지 매김 링크에 추가 할 수 있도록 필터 매개 변수를 기록하는 더 완전한 예가 있습니다.

public function getIndex(Request $request)
{
    //Create a User object to append WHERE clauses onto
    $user = app('App\Models\User');

    //List of filters we found to append to links later
    $appends = [];

    //Run through our simple text fields
    foreach(['first_name', 'last_name', 'region', 'ip'] as $field) {
        if ($request->has($field)) {
            $appends[$field] = $request->input($field);
            $user->where($field, $request->input($field));
        }
    }

    //This field uses a LIKE match, handle it separately
    if ($request->has('email')) {
        $appends['email'] = $request->input('email');
        $user->where('email', LIKE, '%' . $request->input('email') . '%');
    }

    //This field is a list of IDs
    if ($request->has('id')) {
        $appends['id'] = $request->input('id');
        $ids = explode(',', $request->input('id'));
        $user->whereIn('id', $ids);
    }

    //Use pagination
    $users = $user->paginate(25);

    //Make sure we append our filter parameters onto the pagination object
    $users->appends($appends);

    //Now calling $users->links() will return the correct links with the right filter info

    /**
     * Continue with the rest of response formatting below here
     */
}

페이지 매김 문서는 https://laravel.com/docs/5.2/pagination 에서 찾을 수 있습니다.

페이지 매김 링크가 어떻게 훌륭하게 수행되는지에 대한 예는 Github의 API 문서를 확인하십시오 : https://developer.github.com/v3/#pagination


결국 그것은 당신이하던 일과 개념적으로 그리 멀지 않습니다. 여기서 장점은 다른 메서드가 호출 되더라도 컨트롤러가 초기화 될 때마다 생성자에서 실행되는 대신 코드를 필요한 메서드로 이동한다는 것입니다.

도움이 되었기를 바랍니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관