alberto-leon-crespo/rest-entity-manager

基于symfony实体和fosrestbundle的Web服务的库。

1.2 2018-06-24 20:52 UTC

This package is not auto-updated.

Last update: 2024-09-20 09:32:20 UTC


README

一个面向数据映射的REST实体管理器。当你使用面向创建Web服务的库时,遇到的主要问题是它们都旨在处理标准的连接到数据库的流。许多现代基于Web的API,充当其他企业和非企业API的中间代理。因此出现了“Rest Entity Manager”。

库的基本工作原理

该库包含两个标准序列化器。第一个序列化器负责在实体和不同的REST服务之间转换数据。第二个序列化器用于编码和解码客户端发送和接收的内容,从而填充API中的实体。

内部,实体管理器读取不同连接的配置并执行对各个Web服务的请求。

服务

  • alc_rest_entity_manager.handler:是REST实体管理器。负责读取不同连接的配置并将其加载到REST客户端。
  • alc_rest_entity_manager.jms_event_subscriber:负责读取实体配置并配置到不同的REST WS映射。
  • alc_rest_entity_manager.serializer:是负责映射客户端发送和接收的信息到API中不同实体的序列化器。
  • alc_rest_entity_manager.logger:负责监控和记录管理器的REST请求日志。
  • alc_rest_entity_manager.metadata_class_reader:负责读取用于执行映射所需的类元信息。
  • alc_rest_entity_manager.parameters_procesor:负责根据在REST连接中定义的配置处理过滤参数。
  • alc_rest_request_parameters_name_override:在“request”服务中覆盖URL参数,遵循点表示法。例如:“poliza.id”

预备知识

这是一个旨在与“FOSRestBundle”一起工作的bundle,但也无需它即可使用。

安装

步骤 1:下载bundle

打开命令行界面,进入项目目录,并执行以下命令以下载此bundle的最新稳定版本。

$ composer require alberto-leon-crespo/rest-entity-manager

步骤 2:激活bundle

通过向app/AppKernel.php文件中添加以下行来激活bundle:

<?php
// app/AppKernel.php

// ...
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array(
            // ...
            new ALC\RestEntityManager\ALCRestEntityManagerBundle(),
        );

        // ...
    }
}

配置

要使用面向REST的实体,必须先配置REST连接。

# app/config/config.yml

alc_rest_entity_manager:
    default_manager: default # El nombre de la conexion que usara el manager por defecto.
    managers:
        default:
            name: 'default' # El nombre de la conexion
            host: 'https://jsonplaceholder.typicode.com/' # URL base del servicio rest que se va a consultar
            session_timeout: 7200 # Tiempo de expiración de la sesion que hay entre el cliente rest y el webservice de destino
            avanced:
                filtering:
                    ignored_parameters: [_fields,_sort,_page,_limit] #Parametros ignorados del filtrado, no se consideran parametros de filtrado
                    parameters_map:
                        maps:
                          - { origin: _fields, destination: selection } # El campo de origen se mapea al WS como el campo destino indicado
                          - { origin: _page, destination: _page } # El campo de origen se mapea al WS como el campo destino indicado
                          - { origin: _limit, destination: _limit } # El campo de origen se mapea al WS como el campo destino indicado
                          - { origin: _sort, interceptor: ALC\WebServiceBundle\Interceptors\SortParametersInterceptor::parseSortFields } # El campo de origen se transforma por medio de un ParameterInterceptor
            custom_params: # Bloque de parametros de configuración personalizables
                secret_api_key: example1234
            events_handlers: # Bloque de eventos sobre peticiones.
                tokens_inject_handler: # Nombre del manejador del evento
                    event: before # Evento a interceptar
                    interceptor: 'ALC\WebServiceBundle\Interceptors\TokenInjector::injectToken' # Interceptor de las peticiones

如果您想与FOSRestBundle一起使用序列化器,则需要用以下配置覆盖标准序列化器。

# app/config/config.yml

fos_rest:
    service:
        serializer: alc_rest_entity_manager.serializer

实体配置注解

  • ALC\RestEntityManager\Annotations\Resource:

    指示实体将访问的REST资源。在这种情况下,“users”

  • ALC\RestEntityManager\Annotations\Repository:

    指示与实体关联的存储库。

  • ALC\RestEntityManager\Annotations\Id:

    指示注释前的属性是资源的唯一标识符。

  • ALC\RestEntityManager\Annotations\Field:

    • target:REST服务的目标字段。

    • type:字段的数据类型。

      • 支持的数据类型

        支持的类型与JMSSerializer接受的类型相同。JMSSerializer

  • ALC\RestEntityManager\Annotations\Headers:

    允许指定一个HTTP头数组及其应用于实体REST请求的值。

<?php

namespace ALC\WebServiceBundle\Entity\Users;

use ALC\RestEntityManager\Annotations as Rest;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @Rest\Resource("users")
 * @Rest\Headers({"content-type": "application/json","cache-control": "no-cache"})
 * @Rest\Repository("ALC\WebServiceBundle\Entity\Users\UsersRepository")
 */
class Users
{
    /**
     * @Rest\Id()
     * @Rest\Field(target="id",type="integer")
     */
    private $idUsuario;

    /**
     * @Rest\Field(target="name",type="string")
     * @Assert\NotNull()
     * @Assert\NotBlank()
     */
    private $nombre;

    \\ Some class properties and methods
    \\ ....
}

REST管理器的一般操作

按id搜索

等同于GET /users/:id

  • id:要查询的资源标识符。
  • format:信息的输出格式。
    • json
    • xml
    • object
  • type:如果指定了format object,则输出数据类型。
<?php

$objUsersRepository = $this
    ->get('alc_rest_entity_manager.handler')
    ->getManager('default')
    ->getRepository('AppBundle:Users\Users');

$arrResponse = $objUsersRespository->find( $userId, 'object', 'ALC\\WebServiceBundle\\Entity\\Users\\Users' );

检索列表中的所有记录

等同于GET /users

  • format:信息的输出格式。
    • json
    • xml
    • object
  • type:如果指定了format object,则输出数据类型。
<?php

$objUsersRepository = $this
    ->get('alc_rest_entity_manager.handler')
    ->getManager('default')
    ->getRepository('AppBundle:Users\Users');

$arrResponse = $objUsersRespository->findAll( 'object', 'ALC\\WebServiceBundle\\Entity\\Users\\Users' );

检索过滤后的列表

等同于GET /users?nombre=Alberto

  • filters:应用于列表的过滤器。
  • format:信息的输出格式。
    • json
    • xml
    • object
  • type:如果指定了format object,则输出数据类型。
<?php

$arrFilters = array(
    'nombre' => 'Jhon'
);

$objUsersRepository = $this
    ->get('alc_rest_entity_manager.handler')
    ->getManager('default')
    ->getRepository('AppBundle:Users\Users');

$arrResponse = $objUsersRespository->findBy( $arrFilters, 'object', 'ALC\\WebServiceBundle\\Entity\\Users\\Users' );

检索过滤后列表的第一条记录

等同于GET /users?nombre=Alberto

  • filters:应用于列表的过滤器。
  • format:信息的输出格式。
    • json
    • xml
    • object
  • type:如果指定了format object,则输出数据类型。
<?php

$arrFilters = array(
    'nombre' => 'Jhon'
);

$objUsersRepository = $this
    ->get('alc_rest_entity_manager.handler')
    ->getManager('default')
    ->getRepository('AppBundle:Users\Users');

$arrResponse = $objUsersRespository->findOneBy( $arrFilters, 'object', 'ALC\\WebServiceBundle\\Entity\\Users\\Users' );

保存更改

等同于POST /users或PUT /users

如果实体对象在标记为id的字段中有值,则执行PUT操作;否则执行POST操作。

  • object:要持久化的实体实例。
  • format:信息的输出格式。
    • json
    • xml
    • object
  • type:如果指定了format object,则输出数据类型。
<?php

$objUser = new \AppBundle\Users();

$objUser->setNombre("Jhon");
$objUser->setApellido("Doe");

$em = $this
    ->get('alc_rest_entity_manager.handler')
    ->getManager('default');

$arrResponse = $em->persist( $objUser, 'object', 'ALC\\WebServiceBundle\\Entity\\Users\\Users' );

检查是否存在记录,如果存在则更新,如果不存在则创建。

等同于POST /users或PUT /users

如果实体对象在标记为id的字段中有值且该id存在,则执行PUT操作;否则执行POST操作。

  • object:要持久化的实体实例。
  • format:信息的输出格式。
    • json
    • xml
    • object
  • type:如果指定了format object,则输出数据类型。
<?php

$objUser = new \AppBundle\Users();

$objUser->setNombre("Jhon");
$objUser->setApellido("Doe");

$em = $this
    ->get('alc_rest_entity_manager.handler')
    ->getManager('default');

$arrResponse = $em->merge( $objUser, 'object', 'ALC\\WebServiceBundle\\Entity\\Users\\Users' );

使用webservice的更新值获取实体信息

  • object:要刷新的实体实例。
  • format:信息的输出格式。
    • json
    • xml
    • object
  • type:如果指定了format object,则输出数据类型。
<?php

$objUser = new \AppBundle\Users();

$objUser->setIdUsuario(2);

$em = $this
    ->get('alc_rest_entity_manager.handler')
    ->getManager('default');

$arrResponse = $em->refresh( $objUser, 'object', 'ALC\\WebServiceBundle\\Entity\\Users\\Users' );

REST管理器的自定义操作

当由于各种原因,这些标准操作不能适用于您的用例时,您可以通过仓库或直接在控制器中执行操作(就像处理REST客户端一样)来完全自定义调用。

使用仓库

在实体REST中定义"Repository"注解非常重要。

<?php

// Repository

namespace AppBundle\Entity\Users;

use ALC\RestEntityManager\RestRepository;

class UsersRepository extends RestRepository
{
    public function listadoUsuariosWithVocalA(){

        $response = $this->get( 'users', array() );

        $arrUsers = $this->serializer->deserialize( $response->getBody()->getContents(), 'array<ALC\WebServiceBundle\Entity\Users\Users>', 'json' );

        foreach( $arrUsers as $key => $objUser ){

            if( mb_strpos( $objUser->getNombre(), 'a', null, 'utf8' ) === false ){

                unset( $arrUsers[$key] );

            }

        }

        return array_values( $arrUsers );

    }
}

// Controller

<?php

namespace ALC\WebServiceBundle\Controller;

use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\Request;

class UsersController extends FOSRestController
{
    public function getUsersAction(Request $objRequest){

        $objEntityManager = $this->get('alc_rest_entity_manager.handler')->getManager();

        /**
         * @var $objUsersRespository \ALC\RestEntityManager\Services\RestEntityHandler\RestEntityHandler|\ALC\WebServiceBundle\Entity\Users\UsersRepository
         */
        $objUsersRespository = $objEntityManager->getRepository('ALCWebServiceBundle:Users\Users');

        $arrUsersWithAVocal = $objEntityManager->listadoUsuariosWithVocalA();

        // If use FOSRestBundle
        return $arrUsersWithAVocal;

        // If dont use FOSRestBundle

        $strUsersSerialized = $this->get('alc_rest_entity_manager.serializer')->serialize( $arrUsersWithAVocal, 'json' );

        $objResponse = new Response( $strUsersSerialized, 200, ['Content-Type'=>'application/json'] );

        return $objResponse;

高级过滤选项

有时,我们传递给URL的参数不是过滤参数(排序、分页等)。

为此,只需指定哪些参数将忽略过滤以及它们在目标WS中的等效项。

直接等效

在这种情况下,与目标WS的等效是直接的,即源字段与目标字段之间的等效。

# app/config/config.yml
...
            name: 'default'
            host: 'https://jsonplaceholder.typicode.com/'
            session_timeout: 7200
            avanced:
                filtering:
                    ignored_parameters: [_fields,_sort,_page,_limit] # Parametros especiales que deben de ser ignorados en los filtrados.
                    parameters_map: # Mapeo de parametros especiales origen - destino
                        maps:
                          - { origin: page, destination: _page } # Campor de origen page, campo de destino _page
                          - { origin: limit, destination: _limit } # Campor de origen limit, campo de destino _limit

因此,如果您的WS中输入的URL是{{URL_BASE}}/usuarios?page=1&limit=5,则将按照以下方式向目标WS发出请求{{URL_BASE}}/users?_page=1&_limit=5

间接等效

您可能会遇到一些情况,其中与目标参数的特殊等效不是直接的,即一个参数可能对应两个,如下例所示。

在这种情况下,您可以创建以下方式的参数拦截器

<?php
namespace ALC\WebServiceBundle\Interceptors;
use ALC\RestEntityManager\ParameterInterceptor;
class SortParametersInterceptor extends ParameterInterceptor
{
    public function parseSortFields($value)
    {
        $firstCharacter = $value[0];
        $fieldName = substr($value, 1);
        $order = null;
        if ($firstCharacter === '-') {
            $order = 'desc';
        } elseif ($firstCharacter === '+' || $firstCharacter === ' ') {
            $order = 'asc';
        }
        // Busca las equivalencias entre los parametros de entrada de tu WS y el WS de destino
        $arrFinalParams = $this->getMetadataClassReader()->matchEntityFieldsWithResourcesFieldsRecursive( [ $fieldName => $order ] );
        $arrayMatch = array();
        foreach( $arrFinalParams as $campoOrdenar => $metodoOrdenacion ){
            $arrayMatch['_sort'] = $campoOrdenar;
            $arrayMatch['_order'] = $metodoOrdenacion;
        };
        return $arrayMatch;
    }
}

为了注册,只需在"parameters_map"部分注册以下配置即可

# app/config/config.yml
...
            name: 'default'
            host: 'https://jsonplaceholder.typicode.com/'
            session_timeout: 7200
            avanced:
                filtering:
                    ignored_parameters: [_fields,_sort,_page,_limit] # Parametros especiales que deben de ser ignorados en los filtrados.
                    parameters_map: # Mapeo de parametros especiales origen - destino
                        maps:
                           - { origin: _sort, interceptor: ALC\WebServiceBundle\Interceptors\SortParametersInterceptor::parseSortFields }

事件拦截器

如果需要拦截请求事件以注入API令牌到头或执行类似操作,只需创建以下方式的需求拦截器

<?php

namespace ALC\WebServiceBundle\Interceptors;

use ALC\RestEntityManager\Interceptors\RequestInterceptor;
use GuzzleHttp\Event\BeforeEvent;

// La clase debe de extender al objecto ALC\RestEntityManager\Interceptors\RequestInterceptor

class TokenInjector extends RequestInterceptor
{
    public function injectToken(BeforeEvent $event, array $arrManagerConfig){

        $apiKey = $arrManagerConfig['custom_params']['secret_api_key'];

        $event->getRequest()->setHeader('X-Api-Key', $apiKey);

        return $event;
    }
}

创建拦截器后,您必须按照以下配置进行注册

# app/config/config.yml
...
            name: 'default'
            host: 'https://jsonplaceholder.typicode.com/'
            session_timeout: 7200
            avanced:
                ...
            events_handlers:
                tokens_inject_handler:
                    event: before
                    interceptor: 'ALC\WebServiceBundle\Interceptors\TokenInjector::injectToken'

您必须指定要拦截的事件以及拦截请求的类和方法。

可以拦截的事件与Guzzle Http Client接受的事件相同。Guzzle Http Client

示例

要查看更多示例,请参阅示例捆绑包ALC\WebServiceBundle