Um componente base para integrar Sencha Ext JS Ext.direct em um aplicativo PHP
Esta biblioteca fornece uma implementação do lado do servidor para Sencha Ext.direct, um componente de comunicação estilo RPC que faz parte do Ext JS e Sencha Touch do Sencha.
ext direct é um protocolo de chamada de procedimento remoto (RPC) independente de plataforma e idioma. ext direct permite comunicação perfeita entre o lado do cliente de um aplicativo Ext JS e qualquer plataforma de servidor que esteja em conformidade com a especificação. ext direct é leve e sem estado, suportando recursos como descoberta de API, lote de chamadas e eventos de servidor para cliente.
Atualmente esta biblioteca é usada apenas como base do teqneers/ext-direct-bundle, um pacote Symfony que integra *Ext.direct* em um aplicativo baseado em Symfony. Não tentamos usar a biblioteca como um componente independente ou em qualquer outro contexto que não seja um ambiente Symfony, então o que se segue é apenas como ela deveria funcionar teoricamente sem o pacote. Agradecemos qualquer ajuda e contribuição para tornar a biblioteca mais útil fora do pacote.
Você pode instalar esta biblioteca usando o compositor
composer require teqneers/ext-direct
ou adicione o pacote diretamente ao seu arquivo compositor.json.
A estratégia de nomenclatura determina como os nomes de classes e namespaces PHP são traduzidos em nomes de ações Ext.direct compatíveis com Javascript. A estratégia de nomenclatura padrão traduz o separador namspapce em um arquivo
.
. Então MyNamespaceService
é traduzido em My.namespace.Service
. Observe que a transformação deve ser reversível ( My.namespace.Service
=> MyNamespaceService
).
$ namingStrategy = new TQ ExtDirect Service DefaultNamingStrategy ();
O registro de serviço usa uma fábrica de metadados da biblioteca jms/metadata
e um driver de anotação associado (que por sua vez usa um leitor de anotação doctrine/annotations
) para ler metainformações sobre possíveis classes de serviço anotadas.
$ serviceRegistry = new TQ ExtDirect Service DefaultServiceRegistry (
new Metadata MetadataFactory (
new TQ ExtDirect Metadata Driver AnnotationDriver (
new Doctrine Common Annotations AnnotationReader ()
)
),
$ namingStrategy
);
O registro de serviço pode ser preenchido manualmente chamando addServices()
ou addService()
ou importando serviços usando um TQExtDirectServiceServiceLoader
. A implementação padrão TQExtDirectServicePathServiceLoader
pode ler classes de um conjunto de determinados caminhos.
O despachante de eventos é opcional, mas é necessário para usar recursos como conversão e validação de argumentos, conversão de resultados do ouvinte de criação de perfil.
$ eventDispatcher = new Symfony Component EventDispatcher EventDispatcher ();
O roteador é usado para traduzir solicitações Ext.direct recebidas em chamadas de método PHP para a classe de serviço correta. O ContainerServiceFactory
suporta a recuperação de serviços de um contêiner de injeção de dependência do Symfony ou a instanciação de serviços simples que não aceitam nenhum argumento de construtor. As chamadas de serviço estáticas ignoram a fábrica de serviços.
$ router = new TQ ExtDirect Router Router (
new TQ ExtDirect Router ServiceResolver (
$ serviceRegistry ,
new TQ ExtDirect Service ContainerServiceFactory (
/* a SymfonyComponentDependencyInjectionContainerInterface */
)
),
$ eventDispatcher
);
O objeto endpoint é uma fachada na frente de todos os componentes do lado do servidor Ext.direct . Com seu método createServiceDescription()
pode-se obter uma descrição de API compatível com o padrão enquanto handleRequest()
pega um SymfonyComponentHttpFoundationRequest
e retorna um SymfonyComponentHttpFoundationResponse
que contém a resposta Ext.direct para as chamadas de serviço recebido.
$ endpoint = TQ ExtDirect Service Endpoint (
' default ' , // endpoint id
new TQ ExtDirect Description ServiceDescriptionFactory (
$ serviceRegistry ,
' My.api ' ,
$ router ,
new TQ ExtDirect Router RequestFactory (),
' My.api.REMOTING_API '
)
);
O gerenciador de endpoint é apenas uma coleção simples de endpoints que permite a recuperação usando o ID do endpoint. Isso permite fácil exposição de múltiplas APIs independentes.
$ manager = new TQ ExtDirect Service EndpointManager ();
$ manager -> addEndpoint ( $ endpoint );
$ defaultEndpoint = $ manager -> getEndpoint ( ' default ' );
$ apiResponse = $ defaultEndpoint -> createServiceDescription ( ' /path/to/router ' );
$ apiResponse -> send ();
$ request = Symfony Component HttpFoundation Request:: createFromGlobals ();
$ response = $ defaultEndpoint -> handleRequest ( $ request );
$ response -> send ();
O processo de roteamento pode ser manipulado e aumentado usando ouvintes de eventos no despachante de eventos passado para o roteador. A biblioteca oferece quatro assinantes de eventos que permitem
Os conversores de argumentos e resultados fornecidos usam a biblioteca jms/serializer
para fornecer recursos estendidos de (des)serialização, enquanto o validador de argumentos padrão faz uso da biblioteca symfony/validator
.
$ eventDispatcher -> addSubscriber (
new TQ ExtDirect Router EventListener ArgumentConversionListener (
new TQ ExtDirect Router ArgumentConverter ( /* a JMSSerializerSerializer */ )
)
);
$ eventDispatcher -> addSubscriber (
new TQ ExtDirect Router EventListener ArgumentValidationListener (
new TQ ExtDirect Router ArgumentValidator ( /* a SymfonyComponentValidatorValidatorValidatorInterface */ )
)
);
$ eventDispatcher -> addSubscriber (
new TQ ExtDirect Router EventListener ResultConversionListener (
new TQ ExtDirect Router ResultConverter ( /* a JMSSerializerSerializer */ )
)
);
$ eventDispatcher -> addSubscriber (
new TQ ExtDirect Router EventListener StopwatchListener (
/* a SymfonyComponentStopwatchStopwatch */
)
);
Os serviços a serem expostos por meio da API Ext.direct devem ser decorados com metainformações apropriadas. Atualmente isso só é possível usando anotações (como as conhecidas do Doctrine, Symfony ou outras bibliotecas PHP modernas).
Cada classe de serviço que será exposta como uma ação Ext.direct deve ser anotada com TQExtDirectAnnotationAction
. A anotação Action
opcionalmente usa um parâmetro de ID de serviço para serviços que não são estáticos nem podem ser instanciados com um construtor sem parâmetros.
use TQ ExtDirect Annotation as Direct ;
/**
* @DirectAction()
*/
class Service1
{
// service will be instantiated using the parameter-less constructor if called method is not static
}
/**
* @DirectAction("app.direct.service2")
*/
class Service2
{
// service will be retrieved from the dependency injection container using id "app.direct.service2" if called method is not static
}
Além disso, cada método que será exposto em uma ação Ext.direct deve ser anotado com TQExtDirectAnnotationMethod
. A anotação Method
opcionalmente assume true
para designar o método como sendo um manipulador de formulário (tomando postagens de formulário regulares) ou false
para designar o método como sendo um método Ext.direct regular (este é o padrão).
/**
* @DirectAction("app.direct.service3")
*/
class Service3
{
/**
* @DirectMethod()
*/
public function methodA ()
{
// regular method
}
/**
* @DirectMethod(true)
*/
public function methodB ()
{
// form handler method
}
}
Recursos estendidos, como parâmetros nomeados e parâmetros nomeados estritos descritos na especificação Ext.direct , atualmente não são expostos por meio do sistema de anotação.
Os parâmetros que vão para um método que está sendo chamado por meio de uma solicitação Ext.direct também podem ser anotados para aplicar a validação de parâmetro. Isso requer que TQExtDirectRouterEventListenerArgumentValidationListener
esteja registrado no despachante de eventos apropriado.
use Symfony Component Validator Constraints as Assert ;
/**
* @DirectAction("app.direct.service4")
*/
class Service4
{
/**
* @DirectMethod()
* @DirectParameter("a", { @AssertNotNull(), @AssertType("int") })
*
* @param int $a
*/
public function methodA ( $ a )
{
}
}
Se a assinatura do método que está sendo chamado expõe parâmetro(s) com uma dica de tipo para SymfonyComponentHttpFoundationRequest
e/ou TQExtDirectRouterRequest
, a solicitação HTTP Symfony recebida e/ou o Ext.direct bruto request são injetados na chamada do método automaticamente. Este é um método de manipulação de formulário especialmente importante porque não há outra maneira de acessar os parâmetros de solicitação HTTP recebidos (postagem do formulário).
Assim que TQExtDirectRouterEventListenerArgumentConversionListener
estiver habilitado, pode-se usar parâmetros de objeto estritamente digitados em métodos de serviço. Esses argumentos serão desserializados automaticamente da solicitação JSON recebida e serão injetados na chamada do método.
O mesmo se aplica ao retorno de objetos de uma chamada de método de serviço. Se TQExtDirectRouterEventListenerResultConversionListener
estiver habilitado, os valores de retorno serão serializados automaticamente para JSON, mesmo que sejam objetos não triviais.
Tanto o argumento quanto a conversão do valor de retorno são baseados na excelente biblioteca jms/serializer
de Johannes Schmitt. Consulte a documentação para obter mais informações.
A especificação ext direct pode ser encontrada no site de documentação do Sencha.
A Licença MIT (MIT)
Direitos autorais (c) 2015 TEQneers GmbH & Co.
É concedida permissão, gratuitamente, a qualquer pessoa que obtenha uma cópia deste software e dos arquivos de documentação associados (o "Software"), para negociar o Software sem restrições, incluindo, sem limitação, os direitos de usar, copiar, modificar, mesclar , publicar, distribuir, sublicenciar e/ou vender cópias do Software e permitir que as pessoas a quem o Software seja fornecido o façam, sujeito às seguintes condições:
O aviso de direitos autorais acima e este aviso de permissão serão incluídos em todas as cópias ou partes substanciais do Software.
O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM DETERMINADO FIM E NÃO VIOLAÇÃO. EM HIPÓTESE ALGUMA OS AUTORES OU DETENTORES DE DIREITOS AUTORAIS SERÃO RESPONSÁVEIS POR QUALQUER RECLAMAÇÃO, DANOS OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, ATO ILÍCITO OU DE OUTRA FORMA, DECORRENTE DE, OU EM CONEXÃO COM O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES NO SOFTWARE.