Pionia 일반 서비스에 대한 최종 가이드.

王林
풀어 주다: 2024-07-16 20:46:49
원래의
639명이 탐색했습니다.

The Ultimate Guide to Pionia Generic Services.

Pionia 프레임워크는 Rest 플랫폼 개발 방식을 바꾸는 PHP Rest 프레임워크입니다. 기존의 모든 프레임워크와 달리 전체 프로세스에 완전히 새로운 모습을 제공하여 API 개발을 훨씬 간단하고 덜 지루하게 만듭니다. 이는 달빛이라는 다른 패턴, 오히려 '새로운' 패턴으로 실행되기 때문입니다.

그 자체로 달빛은 새로운 아키텍처/패턴이 아니며, 대부분의 기관/회사/개발자가 이를 사용하고 있지만 이름은 지정되지 않았습니다. 하지만 오늘 우리는 달빛에 대해 이야기하는 것이 아닙니다. 여기 내 다른 기사에서 이에 대해 읽어보고 의견을 남길 수도 있습니다.

새로운 Pionia 프로젝트를 부트스트랩하려면 이미 작곡가가 설정되어 있다는 가정하에 다음 명령을 실행해야 합니다.

todo_app을 만들어 보겠습니다.

composer create-project pionia/pionia-app todo_app
로그인 후 복사

아래와 같이 pionia 명령을 사용하여 동일한 프로젝트를 실행할 수도 있습니다.

php pionia serve
로그인 후 복사

실시간으로 발생하는 로그를 보려면 두 번째 터미널을 열고 다음 명령을 실행하세요.

tail -f server.log
로그인 후 복사

서비스에 대한 배경.

Pionia 프레임워크의 서비스는 핵심이며 아마도 API를 개발하는 동안 대부분의 시간을 소비하게 될 유일한 부분일 것입니다. Pionia의 모든 일반 서비스는 PioniaRequestBaseRestService를 확장합니다. 피오니아의 일반적인 서비스 모습은 이렇습니다.

namespace application\services;


use Exception;
use Pionia\Request\BaseRestService;
use Pionia\Response\BaseResponse;
use Porm\Porm;

class UserService extends BaseRestService
{
    /**
     * @throws Exception
     */
    protected function login(array $data): BaseResponse
    {
        // password and username are required, without them we won't proceed even
        $this->requires(["username", "password"]);

        $username = $data["username"];
        $password = password_hash($data['password'], PASSWORD_DEFAULT);

        $user = Porm::from('user')->get(['username' => $username, 'password' => $password]);
        //You can do more here, maybe generate a JWT token or add more checks
        // for example if the user is an active or not
        if ($user) {
            return BaseResponse::JsonResponse(0, "Login successful", $user);
        }
        throw new Exception("User with the given username and password not found");
    }

}
로그인 후 복사

서비스를 구축한 후에는 앞으로 서비스를 처리할 스위치에 등록해야 합니다. Pionia의 스위치를 모르는 경우 여기 문서에서 해당 스위치에 대해 읽을 수 있습니다. 아직 다른 스위치를 만들지 않았다면 스위치 폴더(아마도 MainAppSwitch.php에 있음)로 이동하여 아래와 같이 위의 서비스를 RegisterServices 메소드에 등록하세요

     /**
     * Register your services here.
     *
     * @return array
     */
    public function registerServices(): array
    {
        return [
            'user' => new UserService(),
            'todo' => new TodoService()
        ];
    }
로그인 후 복사

지금부터 커널이 서비스를 자동 검색하도록 하는 방법은 다음과 같습니다. 일반적인 설정에서는 이 서비스에 매핑할 라우터와 컨트롤러를 추가했을 것이지만 Pionia는 상황에 다르게 접근합니다. 여러 스위치에 동일한 서비스를 등록할 수 있다는 점을 기억하세요. 모든 스위치가 API 엔드포인트에 의해 처리되므로 이것이 API 버전 관리 개념을 달성하는 방법입니다. 기본적으로 MainAppSwitch는 /api/v1/에서 액세스할 수 있습니다.

요청 시 다음을 보내 이 서비스를 지정할 수 있습니다.

// POST http://localhost:8000/api/v1/
{
    "SERVICE": "user",
    "ACTION": "login",
    "username": "pionia",
    "password": "pionia1234"
}
로그인 후 복사

알다시피 ACTION은 등록 시 이름 사용자에게 세례를 준 SERVICE/서비스/클래스에서 만든 작업/메서드의 이름입니다.

피오니아에서는 일반적인 서비스가 이렇게 진행됩니다.

아래는 Piona에서 CRUD를 수행하는 완전한 서비스입니다. 이는 todo_db라는 MySQL 데이터베이스에 있는 todos라는 다음과 같은 간단한 테이블을 기반으로 합니다.

create table todo_db.todos
(
    id          int auto_increment primary key,
    title       varchar(200)                        not null,
    description text                                null,
    created_at  timestamp default CURRENT_TIMESTAMP null
) engine = InnoDB;
로그인 후 복사
use Exception;
use Pionia\Request\BaseRestService;
use Pionia\Request\PaginationCore;
use Pionia\Response\BaseResponse;
use Porm\exceptions\BaseDatabaseException;
use Porm\Porm;

class TodoService extends BaseRestService
{
    /**
     * Returns all todos
     * @throws Exception
     */
    public function list(): BaseResponse
    {
        $result = Porm::table('todos')
            ->using('db')
            ->columns(['id', 'title', 'description', 'created_at'])
            ->all();

        return BaseResponse::JsonResponse(0, null, $result);
    }

    /**
     * Returns a single todo
     * @throws Exception
     */
    public function details(array $data): BaseResponse
    {
        $this->requires(['id']);
        $id = $data['id'];

        $result = Porm::table('todos')
            ->using('db')
            ->columns(['id', 'title', 'description', 'created_at'])
            ->get(['id' => $id]);

        return BaseResponse::JsonResponse(0, null, $result);
    }

    /**
     * Creates a new todo
     * @throws Exception
     */
    public function create(array $data): BaseResponse
    {
        $this->requires(['title', 'description']);
        $title = $data['title'];
        $description = $data['description'];

        $result = Porm::table('todos')
            ->save(['title' => $title, 'description' => $description]);

        return BaseResponse::JsonResponse(0, 'Todo created successfully', $result);
    }

    /**
     * Updates a todo
     * @throws Exception
     */
    public function update(array $data): BaseResponse
    {
        $this->requires(['id']);

        $id = $data['id'];

        $todo = Porm::table('todos')
            ->get($id); // similar to `get(['id' => $id])`

        // if the todo is not found, we throw an exception
        if (!$todo) {
            throw new BaseDatabaseException('Todo not found');
        }

        $description = $data['description'] ?? $todo->description;
        $title = $data['title'] ?? $todo->title;

        // we update in a transaction as below
        $result= null;
        Porm::table('todos')
            ->inTransaction(function () use ($description, $title, $id, &$result) {
                Porm::table('todos')
                    ->update(['description' => $description, 'title' => $title], $id);

                $result = Porm::table('todos')
                    ->get($id);
            });

        return BaseResponse::JsonResponse(0, "Todo $id updated successfully", $result);
    }

    /**
     * Deletes a todo
     * @throws Exception
     */
    public function delete(array $data): BaseResponse
    {
        $this->requires(['id']);
        $id = $data['id'];

        $todo = Porm::table('todos')
            ->get($id);

        if (!$todo) {
            throw new BaseDatabaseException('Todo not found');
        }

        $deleted = false;
        Porm::table('todos')
            ->inTransaction(function () use ($id, &$deleted) {
                Porm::table('todos')
                    ->delete($id);
                $deleted = true;
            });
        if (!$deleted) {
            throw new BaseDatabaseException('Todo not deleted');
        }
        return BaseResponse::JsonResponse(0, "Todo $id deleted successfully");
    }

    /**
     * Returns a random todo object if the size is not defined or 1,
     * else returns an array of random todos
     * @throws Exception
     */
    public function random($data): BaseResponse
    {
        $size = $data['size'] ?? 1;

        $result = Porm::table('todos')
            ->random($size);

        return BaseResponse::JsonResponse(0, null, $result);
    }

    /**
     * Returns a paginated list of todos
     * @throws Exception
     */
    public function paginatedList(array $data): BaseResponse
    {
        $offset = $data['offset'] ?? 0;
        $limit = $data['limit'] ?? 3;

        $paginator = new PaginationCore($data, 'todos', $limit, $offset, 'db');
        $result = $paginator->paginate();

        return BaseResponse::JsonResponse(0, null, $result);
    }
}
로그인 후 복사

그리고 TodoService가 이미 등록되었으므로 우리가 해야 할 일은 이것이 전부입니다. 추가 경로를 추가하거나 컨트롤러를 추가하지 않고 요청에 있는 작업을 시작하기만 하면 위의 모든 작업에서 균일한 응답을 얻을 수 있습니다.

그러나 이것은 할 일이 많지 않고 Pionia(서비스 구축)에서 할 수 있는 유일한 작업이므로 TodoService에서 위의 모든 작업을 생략할 수 있으며 여전히 동일한 기능을 얻을 수 있습니다. 일반 서비스가 들어왔습니다!

Todo 서비스, 일반적인 방식.

귀하의 논리가 생성, 삭제, 페이지 매기기, 나열, 업데이트, 삭제 또는 검색 이상의 것이 아니라면 일반 서비스만 있으면 됩니다.

Pionia는 일반 서비스와 사용할 수 있는 믹스인을 모두 제공합니다. 믹스인을 조합하여 전체 새로운 일반 서비스를 구축할 수 있습니다.

제공되는 믹스인에는 ListMixin, CreateMixin, DeleteMixin, UpdateMixin, RandomMixin 및 RetrieveMixin이 포함됩니다. 내부적으로는 일반 서비스도 GenericService를 확장하면서 이러한 믹스인을 결합하고 있습니다.

제공되는 일반 서비스에는 RetrieveCreateUpdateService, RetrieveListCreateService, RetrieveListCreateUpdateDeleteService, RetrieveListDeleteService, RetrieveListRandomService, RetrieveListUpdateDeleteService, RetrieveListUpdateService 및 UniversalGenericService가 포함됩니다.

위 Generics가 원하는 방식으로 믹스인을 결합하지 않는 경우 GenericService를 확장하고 사용하려는 모든 믹스인을 호출하여 사용자 정의 Generic 서비스를 만들 수 있습니다.

믹스인을 사용하려면 이전에 확장한 일반 BaseRestService가 아닌 PioniaGenericsBaseGenericService를 확장해야 한다는 점을 기억하세요. 또한 믹스인은 단지 PHP 특성이므로 그런 식으로 사용해야 한다는 점을 기억하세요.

TodoService를 리팩토링하려면 정의된 모든 믹스인을 사용하므로 마지막으로 언급한 일반 서비스인 UniversalGenericService가 필요합니다.

연장하는 클래스를 변경하는 것부터 시작하겠습니다. 아래와 같이 리팩토링하세요

use Pionia\Generics\UniversalGenericService;
// ... rest of the imports

class TodoService extends UniversalGenericService
{
// ... rest of your actions
}
로그인 후 복사

Before we do anything, let's first define the table we want to target in the database. We use the $table property for this. This is a compulsory feature and must be defined for all generic views.

use Pionia\Generics\UniversalGenericService;
// ... rest of the imports

class TodoService extends UniversalGenericService
{
   public string $table = "todo";
// ... rest of your actions
}
로그인 후 복사

Secondly, from our list action, we are defining columns we want to return, however, we are defining all. If you want to return a certain range of columns only, we define the $listColumns(which defaults to all) and pass the columns we want to return. Let's just still pass all though it is the default behavior of the service.

use Pionia\Generics\UniversalGenericService;
// ... rest of the imports

class TodoService extends UniversalGenericService
{
    public string $table = "todo";
    public ?array $listColumns = ['id', 'title', 'description', 'created_at'];

// ... rest of your actions
}
로그인 후 복사

At this point, we can delete the list action from our service. That's complete!

Our second target action is now details. This one can be replaced by defining the $pk_field which defaults to id. Since our primary key field for our todo table is also id, we don't need to define it, we just need to delete it too! Remember, this one also uses the defined $listColumns for columns to return from the DB.
The RetrieveMixin also defines another sister action to this called retrieve, so in your request, you can use ACTION as details or retrieve, the two will perform the same thing.
Since we already have all we need, we can drop the details action too!

Our third action is create. For this, we must define the $createColumns to define those columns we shall be looking for from the request(required) to create a record. Let's add the property now.

use Pionia\Generics\UniversalGenericService;
// ... rest of the imports

class TodoService extends UniversalGenericService
{
    public string $table = "todo";
    public ?array $listColumns = ['id', 'title', 'description', 'created_at'];
    public ?array $createColumns = ['title', 'description'];

// ... rest of your actions
}
로그인 후 복사

After adding, go ahead and delete it too!

Our fourth action is update. For this, we require the $pk_field and can also optionally define the $updateColumns. If undefined, the responsible mixin checks if any of the properties were defined in the request, and will update only those.
Let's add the $updateColumns and give it the only properties we intend to update.

use Pionia\Generics\UniversalGenericService;
// ... rest of the imports

class TodoService extends UniversalGenericService
{
    public string $table = "todo";
    public ?array $listColumns = ['id', 'title', 'description', 'created_at'];
    public ?array $createColumns = ['title', 'description'];
    public ?array $updateColumns = ['title', 'description'];

// ... rest of your actions
}
로그인 후 복사

We can now drop the update action too!

For our fifth action, delete, we only need the $pk_field which is by default id, so we shall be checking if id was passed in the request, and then we delete the associated record. So, just delete it, we already have all we need!

Now to our sixth action, random, this also uses the $listColumns to determine the columns to fetch from the DB per record. We already have out property defined, so, just drop it too!

For our seventh action, paginatedList, we can drop it, and in any request, we target our list action, but we define any of the following pairs of keys in our request.

  1. limit and offset on the request object level.
{
   "SERVICE": "todo",
   "ACTION": "list",
   "limit": 3,
   "offset": 0
}
로그인 후 복사
  1. PAGINATION or pagination object on the request with limit and offset keys.
{
   "SERVICE": "todo",
   "ACTION": "list",
   "PAGINATION": {
      "limit": 3,
      "offset": 0,
   }
}
로그인 후 복사
  1. SEARCH or search object on the request object with limit and offset keys.
{
   "SERVICE": "todo",
   "ACTION": "list",
   "SEARCH": {
      "limit": 3,
      "offset": 0
   }
}
로그인 후 복사

Note: Both the limit and offset keys must be defined for pagination to kick in.

And just like that, our service now has been reduced to the following.

use Pionia\Generics\UniversalGenericService;

class TodoService extends UniversalGenericService
{
    public string $table = "todo";
    public ?array $listColumns = ['id', 'title', 'description', 'created_at'];
    public ?array $createColumns = ['title', 'description'];
    public ?array $updateColumns = ['title', 'description'];
}
로그인 후 복사

Let's do a little more cleanup. As we had mentioned earlier, if we are listing all columns from our table, then we don't need to define the $listColumns property, let's remove that too.

use Pionia\Generics\UniversalGenericService;

class TodoService extends UniversalGenericService
{
    public string $table = "todo";
    public ?array $createColumns = ['title', 'description'];
    public ?array $updateColumns = ['title', 'description'];
}
로그인 후 복사

Also, since our update can also discover the columns to update from the request data, let's remove the $updateColumns too!

And we are left with the following as our new TodoService but still exposing the actions of list(all and paginated), create, update, delete, retrieve or details and random

use Pionia\Generics\UniversalGenericService;

class TodoService extends UniversalGenericService
{
    public string $table = "todo";
    public ?array $createColumns = ['title', 'description'];
}
로그인 후 복사

You can also override how we get a single record and multiple records. You might not need it, but sometimes you may need to add where clauses and other conditions as you see fit. For that, you can read about it in this section in the docs.

Also, you may want to add your other actions in the same generic service, this is fully supported and will work as if you're in normal services, however, make sure none of those actions share the names with the provided mixin actions or otherwise you stand a chance of overriding the provided actions.

This also drives to the last point, what if you intend to override the default action? that's also okay! You can also look into it under this section of the docs.

Welcome to Pionia Framework, where we believe in both developer and program performance, writing precise and maintainable codebase with simplicity both at the front end and the back end!

Let me hear what you say about the Pionia Framework specifically about generic services. Happy coding!

위 내용은 Pionia 일반 서비스에 대한 최종 가이드.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿