Uma classe Service
é um contêiner para armazenar métodos reutilizáveis. Ele coordena Entities, DAO
s e outros utilitários para ler e escrever a partir do banco de dados, enviar e-mails e disparar eventos.
As classes Service isolam a lógica de negócios das ações realizadas na aplicações dos handlers que recebem e respondem à solicitação. Deve ser possível usar um método da classe service de um PageHandler
, APIHandler
ou até mesmo um comando CLI.
Os Services são novos para a aplicação e ainda não estão disponíveis para todas as entities. Leia sobre a estratégia de refatoração.
Um service pode ser recuperado de qualquer lugar na aplicação.
$contextService = Services::get('context');
Os services disponíveis podem ser encontrados em OJSServiceProvider
e OMPServiceProvider
.
Uma classe Service
geralmente é emparelhada com uma Entity e fornece todos os métodos para obter, adicionar, editar e excluir essa Entity.
Cada classe entity service implementará uma ou mais interfaces que determinam quais métodos estão disponíveis.
A EntityReadInterface
fornece o método get()
para obter um objeto.
$context = Services::get('context')->get($contextId);
Ele também fornece vários métodos que podem ser usados para recuperar resultados filtrados por um ou mais parâmetros.
Use o método getCount()
para recuperar uma contagem de objetos que correspondem aos parâmetros especificados.
$numberOfEnabledContexts = Services::get('context')->getCount([
'isEnabled' => true,
]);
Use o método getIds()
para recuperar uma matriz de ids de objeto.
$enabledContextIds = Services::get('context')->getIds([
'isEnabled' => true,
]);
Use o método getMany()
para recuperar um iterador de objetos.
$contextsIterator = Services::get('context')->getMany([
'isEnabled' => true,
]);
Passe os parâmetros count
e offset
para paginar os resultados. O exemplo abaixo mostra como obter dez itens começando com a segunda página de resultados.
$contextsIterator = Services::get('context')->getMany([
'count' => 10,
'offset' => 10,
]);
Os métodos getCount()
, getIds()
e getMany()
aceitam os mesmos parâmetros. Eles são diferentes para cada entity e podem ser descobertos lendo a documentação do método getMany()
da classe service.
O método getMany()
retorna um DAOResultIterator
(consulte Iterators). Iterators podem ser usados como um array em loops foreach
:
$contextsIterator = Services::get('context')->getMany(['isEnabled' => true]);
$names = [];
foreach ($contextsIterator as $context) {
$names[] = $context->getLocalizedData('name');
}
No entanto, um DAOResultIterator
não pode ser repetido duas vezes. Isso causará um erro fatal.
$names = [];
$paths = [];
$contextsIterator = Services::get('contexts')->getMany(['isEnabled' => true]);
foreach ($contextsIterator as $context) {
$names[] = $context->getLocalizedData('name');
}
// O iterador já passou por um loop
// antes, então isso causará um erro
foreach ($contextsIterator as $context) {
$paths[] = $context->getData('urlPath');
}
Para verificar se nenhum resultado foi retornado, use count()
em vez de !empty()
.
$contextsIterator = Services::get('contexts')->getMany(['isEnabled' => true]);
if (!empty($contextsIterator)) {
// Isso sempre será verdade
}
if (count($contextsIterator)) {
// Verdadeiro somente se um ou mais contextos foram encontrados
}
O DAOResultIterator
não pode ser usado com as funções array_map
, array_filter
ou array_reduce
.
Se necessário, um DAOResultIterator
pode ser convertido em um array.
$contextsIterator = Services::get('contexts')->getMany(['isEnabled' => true]);
$contexts = iterator_to_array($contextsIterator);
No entanto, isso deve ser evitado, a menos que seja absolutamente necessário. Armazenar uma grande coleção de objetos na memória tornará a aplicação lenta. Se você não tiver certeza, pergunte a um desenvolvedor mais experiente da equipe.
A EntityWriteInterface
fornece métodos para validar, adicionar, editar e excluir objetos.
Antes de adicionar ou editar um objeto, você deve validar suas propriedades. Consulte Validação.
$props = ['path' => 'publicknowledge'];
$errors = Services::get('context')->validate(
VALIDATE_ACTION_ADD,
$props,
Application::get()->getSite()->getSupportedLocales(),
Application::get()->getSite()->getPrimaryLocale(),
);
if (!empty($errors)) {
// Falha na validação de props: requer uma prop `name`
}
Depois que as propriedades forem validadas, elas podem ser mescladas com o objeto e salvas.
Editar um objeto existente.
$editedContext = Services::get('context')->edit(
$context,
$props,
Application::get()->getRequest()
);
Para adicionar um objeto, use o DAO para instanciar um novo objeto, injetar as props e salvá-lo no banco de dados.
$context = Application::get()->getContextDAO()->newDataObject();
$context->_data = $props;
$newContext = Services::get('context')->add(
$context,
Application::get()->getRequest()
);
Excluir um objeto.
Services::get('context')->delete($context);
A EntityPropertyInterface
fornece métodos para converter um objeto em um array associativo. Isso é usado antes que os dados sejam retornados como JSON na API REST e na CLI.
Use o método getSummaryProperties()
para recuperar um resumo do objeto.
$contextProps = Services::get('context')
->getSummaryProperties(
$context,
['request' => Application::get()->getRequest()]
);
Use o método getFullProperties()
para recuperar uma representação completa do objeto.
$contextProps = Services::get('context')
->getFullProperties(
$context,
['request' => Application::get()->getRequest()]
);
As propriedades completas às vezes incluem detalhes sobre objetos anexados. Por exemplo, um objeto de submissão irá anexar objetos de autor.
Você pode solicitar as propriedades que deseja com o método getProperties()
.
$contextProps = Services::get('context')
->getProperties(
$context,
['name', 'path', 'url']
['request' => Application::get()->getRequest()]
);
Isso retornará uma matriz associativa.
[
'name' => [
'en_US' => 'Journal of Public Knowledge'
]
'path' => 'publicKnowledge',
'url' => 'http://localhost:8000/publicknowledge'
]
Cada classe service pode incluir métodos adicionais conforme necessidade. Por exemplo, a classe PKPContextService
inclui um método para restaurar todas as configurações padrão para uma localidade.
$updatedContext = Services::get('context')
->restoreLocaleDefaults(
$context,
$request,
$locale
);
Em casos raros, uma classe de Service
pode não ser pareada com uma entity. Por exemplo, o SchemaService
fornece métodos para compilar e trabalhar com esquemas de entity.
// Preencher um objeto com os valores padrão de seu esquema
$contextWithDefaults = Services::get('schema')
->setDefaults(
SCHEMA_CONTEXT,
$newContext,
$supportedLocales,
$primaryLocale
);
Outros services podem estar relacionados a uma entity, mas ainda não suportam as interfaces de entity. Consulte a estratégia de refatoração.
Uma boa classe Service
deve ser:
$this
. Todas as dependências de um método da classe Service devem ser injetadas como parâmetro para esse método.Os Services são novos para a aplicação. Nossa intenção é mover o código para as classes de service que existem atualmente em Page Handlers, Controller Handlers e Forms. O principal caso de uso para essa mudança é oferecer suporte à API REST.
Esta refatoração tem três objetivos:
As classes service ainda não estão disponíveis para todas as entities. Eles serão desenvolvidos à medida que mais de nossa interface do usuário for convertida para usar a API REST.
Saiba mais sobre como as entities são definidas e tratadas.