# Entidades

{% embed url="<https://www.youtube.com/embed/YiahGRWbkQE>" %}

O Mapas Culturais utiliza o [Doctrine](https://www.doctrine-project.org/index.html) como ORM. Para o Doctrine, as entidades representam um mapeamento entre o modelo orientado a objetos e o modelo relacional do banco de dados.&#x20;

Uma classe de entidade representa uma tabela. Enquanto uma instância dessa classe representa uma entrada nesta tabela.

O Mapas Culturais implementa na classe [MapasCulturais\Entity](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Entity.php) uma abstração em cima das entidades do Doctrine.

Essa implementação ocorre de modo a facilitar a validação da entidade, as operações CRUD e, ao mesmo tempo, cuidar das permissões, impedindo que um usuário faça operações e/ou visualize informações que ele não tem permissão. Todas as entidades do mapas estendem esta classe.

Para se aprofundar nas entidades vale a leitura da documentação [Working With Objects](https://www.doctrine-project.org/projects/doctrine-orm/en/2.9/reference/working-with-objects.html#working-with-objects) do Doctrine. Lembrando que o Mapas faz uma abstração em cima do Doctrine.

## Trabalhando com Entidades (CRUD e os Repositórios)

### **Operação de Inserção**

Para inserir uma nova entrada em uma tabela, ou em outras palavras, criar um novo objeto de uma determinada entidade, deve-se instanciar um novo objeto da classe desejada, definir ao menos os atributos obrigatórios e chamar o método `save` do objeto.&#x20;

Você pode também, antes de salvar, verificar se há erros de validação no objeto.

```php
$agent = new \MapasCulturais\Entities\Agent;
$agent->name = 'Fulano';
$agent->type = 1; // agente do tipo individual
$agent->shortDescription = 'Descrição do fulano';

if (!($errors = $agent->getValidationErrors())) {
   $agent->save(true); // passar true para o método save faz o flush do objeto no banco de dados
}
```

### **Operação de Leitura (Recuperando Entidade do Banco de Dados)**

Para recuperar um objeto do banco de dados você deve utilizar o repositório da entidade.&#x20;

O repositório da entidade pode ser acessado pelo método `repo` da aplicação.

```php
$app = MapasCulturais\App::i();

// pega o agente de id 1
$agent = $app->repo('Agent')->find(1);

// pega um agente de nome 'Fulano'
$agent = $app->repo('Agent')->findOneBy(['name' => 'Fulano']);

// pega todos os agentes de nome 'Fulano'
$agents = $app->repo('Agent')->findBy(['name' => 'Fulano']);
```

### **Operação de Atualização**

Para modificar um objeto após recuperá-lo do banco de dados, você deve modificar suas propriedades e utilizar o método `save`.

```php
$app = MapasCulturais\App::i();

// pega o agente de id 1
$agent = $app->repo('Agent')->find(1);
$agent->name = 'Ciclano';
$agent->save(true);
```

### **Operação de Deleção**

Para deletar um objeto você deve utilizar o método `delete`, do mesmo:

```php
$app = MapasCulturais\App::i();

// pega o agente de id 1
$agent = $app->repo('Agent')->find(1);
$agent->delete(true);
```

## Permissões no Nível do Modelo e Diagrama de Permissões

O sistema de permissões do Mapas Culturais é implementado no nível do modelo. Esta abordagem auxilia na prevenção de bugs, uma vez que o controle do que um usuário pode ver, criar, modificar, ou deletar, acontece automaticamente, disparando uma exceção [PermissionDenied](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Exceptions/PermissionDenied.php) quando uma operação não permitida for executada.

Considerando que usuário não está autenticado, o exemplo abaixo disparará a exceção no momento da execução do `save(true)`:

```php
$app = MapasCulturais\App::i();

// pega o agente de id 1
$agent = $app->repo('Agent')->find(1);

if ($app->user->is('guest')) {
   $agent->name = 'Ciclano';
   $agent->save(true); 
}
```

Ou do delete:

```php
$agent = $app->repo('Agent')->find(1);
if ($app->user->is('guest')) {
   $agent->delete(true);
}
```

O mesmo acontece quando um usuário tenta modificar ou apagar um objeto que não lhe pertence e ao qual ele não tem *controle*.

As permissões são implementadas em funções com o prefixo `canUser` (por exemplo, `canUserModify`), e podem ser verificadas através do método `canUser` da entidade.

```php
// se o usuário autenticado pode modificar o objeto $agent, imprime um botão editar
if ($agent->canUser('modify')) {
   echo "<button>editar</button>";
}
```

Os métodos `canUser` recebem o usuário ao qual a permissão está sendo testada e devem ser implementados como protegidos:

```php
class Agent {
   protected function canUserDoSomething($user) {
      if($user->is('admin')) {
         return true;
      } else {
         return false;
      }
   }
}

$agent->canUser('doSomething'); // retorna true se o usuário logado for admin, false de outra forma
```

Pode-se verificar a permissão antes de efetuar uma operação utilizando o método `checkPermission`, que dispara uma exceção de `PermissionDenied` quando o método `canUser` da permissão retornar false. Esta função é muito útil nos controladores, como veremos no próximo capítulo.

```php
$agent->checkPermission('doSomething'); // dispara a exceção se o usuário logado não for um admin
```

### **Agente Relacionado com Controle (permissão @control)**

@todo

## **Diagrama de Permissões**

![](https://raw.githubusercontent.com/mapasculturais/mapasculturais/master/documentation/permiss%C3%B5es.png)

## Metadados, Taxonomias e Termos, e Arquivos

### **Metadados**

Como falado anteriormente, cada entidade principal, agentes, espaços, eventos, projetos, oportunidades e inscrições, conta com uma entidade secundária auxiliar para salvamento de metadados. Diferentemente das outras entidades auxiliares, que veremos em seguida.&#x20;

Para cada entidade principal temos uma tabela própria para a entidade secundária, por exemplo, temos uma tabela `agent_meta` para salvar os metadados dos agentes. A estrutura dessas entidades é a seguinte:

* `id`: int;
* `key`: string;
* `value`: string;
* `owner`: tipo da entidade principal, ou seja Agent, Space, Event, Project, Opportunity ou Registration (mapeado para a coluna `object_id`).

Os metadados das entidades precisam ser registrados antes de serem utilizados. No método `register` de plugins ou temas, podemos registrar metadados da seguinte maneira:

```php
function register() {
   $this->registerAgentMetadata('numeroDeFilhos', [
      'label' => 'Metadado para salvar a informação de quantos filhos o agente tem',
      'type' => 'number',
      // campo privado, somente quem puder ver dados privados ($agent->canUser('viewPrivateData')) poderá ver esta informação
      'private' => true,
      'default' => 0,
      'validations' => [
            'required' => 'O número de filhos é obrigatório',
            // sintaxe do Respect/Validation
            'v::intVal()->positive()' => 'O número de filhos deve ser um número inteiro positivo'
      ],
      'serialize' => function ($val) { 
         return (string) (int) $val;
      },
      'unserialize' => function ($val) {
         return (int) $val;
      }
   ])
}
```

Os seguintes métodos estão disponíveis para utilização em Plugins, Módulos e Temas:

* `registerAgentMetadata`;&#x20;
* `registerEventMetadata`;&#x20;
* `registerOpportunityMetadata`;&#x20;
* `registerProjectMetadata`;&#x20;
* `registerRegistrationMetadata`;&#x20;
* `registerSealMetadata`;&#x20;
* `registerSpaceMetadata`;&#x20;
* `registerUserMetadata`.&#x20;

Após registrar o metadado, você pode utilizá-lo como se fosse um atributo do objeto, usando a chave registrada diretamente:

```php
$agent->numeroDeFilhos = 4;
$agent->save();

echo $agent->numeroDeFilhos;
```

É importante utilizar os metadados dessa maneira, pois é nesta implementação que é feita a verificação das permissões para visualização dos metadados privados.&#x20;

Ou seja, acessar os metadados através do getter `getMetadata` NÃO é uma boa prática&#x20;

### **Taxonomias e Termos**

A implementação das taxonomias é feita em torno das entidades [Term](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Entities/Term.php) e [TermRelation](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Entities/TermRelation.php), e do trait [EntityTaxonomies](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityTaxonomies.php).

Uma vez registrada uma taxonomia, você pode acessar e definir os termos que uma entidade principal utiliza desta taxonomia da seguinte maneira, utilizando como exemplo a taxonomia `tag`:

```php
$tags = $agent->terms['tag'];
$tags[] = 'mapas'; 
$agent->terms['tag'] = $tags;

$agent->save();
```

A operação do exemplo acima adicionará uma entrada na tabela `term` para o termo *mapas* da taxonomia `tag`, isso ocorre somente se ainda não houver o termo. E, adicionará outra entrada na tabela `term_relation` relacionando o termo criado ao agente.

### **Arquivos**

A funcionalidade de anexar arquivos nas entidades é implementada pela entidade secundária [File](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Entities/File.php) e pelos traits [EntityFiles](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityFiles.php), que implementa a parte do modelo. E, pelo [ControllerUploads](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/ControllerUploads.php) que automatiza os uploads dos arquivos.

Cada entidade que utiliza o trait EntityFiles tem uma entidade auxiliar, por exemplo, a entidade `Agent` tem a entidade auxiliar `AgentFile` que tem a propriedade `owner` do tipo `Agent`.&#x20;

Além disso, a entidade principal recebe do trait alguns métodos gets que auxiliam a obtenção dos arquivos anexos. O principal deles é o `getFiles`, acessível pelo magic getter por `->files`.

```php
>>> $agent->files
   [
      "avatar" => MapasCulturais\Entities\AgentFile {#9645
         +__isInitialized__: true,
         …2
      },
      "downloads" => [
         MapasCulturais\Entities\AgentFile {#9654},
         MapasCulturais\Entities\AgentFile {#9656},
      ]
   ]
```

## Traits de Entidades

Os seguintes traits estão disponíveis e são utilizados nas diversas entidades:

* [EntityAgentRelation](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityAgentRelation.php): Implementa a funcionalidade de relacionar agentes na entidade. É utilizado por todas as entidades onde é preciso definir administradores para conceder permissão de controle sobre a entidade;
* [EntityArchive](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityArchive.php): Implementa a funcionalidade de arquivar e desarquivar uma entidade (`Entity::STATUS_ARCHIVE = -2`). É utilizado nas entidades principais;
* [EntityAvatar](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityAvatar.php): Implementa um getter para o grupo de arquivos `avatar`. É utilizado pelas entidades que têm a funcionalidade de avatar;
* [EntityDraft](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityDraft.php): Implementa a funcionalidade de entidades em rascunho. É utilizado pelas entidades principais;
* [EntityFiles](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityFiles.php): Implementa a funcionalidade de arquivos anexos às entidades;
* [EntityGeoLocation](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityGeoLocation.php): Implementa a funcionalidade de geolocalização. É utilizado nas entidades `Agent` e `Space;`
* [EntityMetaLists](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityMetaLists.php): Implementa a funcionalidade de listas (links e vídeos);
* [EntityMetadata](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityMetadata.php): Implementa os metadados para os agentes. É utilizado pelas entidades que possuem a entidade secundária auxiliar para salvamento de metadados;
* [EntityNested](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityNested.php): Implementa a funcionalidade de entidades hierárquicas. É utilizado pelas entidades com a propriedade `parent`, ou seja, `Agent`, `Space`, `Project` e `Opportunity`;
* [EntityOpportunities](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityOpportunities.php): Implementa um getter para retornar as oportunidades vinculadas a entidade. Utilizado nas entidades `Agent`, `Space`, `Project` e `Event`;
* [EntityOriginSubsite](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityOriginSubsite.php): Implementa nas entidades métodos relacionados ao SaaS. É utilizado nas entidades que têm a propriedade `subsite`, mapeamento para a coluna `subsite_id`;
* [EntityOwnerAgent](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityOwnerAgent.php): Implementa a funcionalidade de agente proprietário da entidade. É utilizado pelas entidades que têm um agente `owner` ("Assinado por", no rodapé da página);
* [EntityPermissionCache](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityPermissionCache.php): Implementa a funcionalidade de cache de permissão para a entidade. Como esse cache só é utilizado pela API de busca do Mapas Culturais, este trait é utilizado pelas entidades que disponibilizam a API ou que são utilizadas nas queries da API, a saber, `Agent`, `EvaluationMethodConfiguration`, `Event`, `Notification`, `Opportunity`, `Project`, `Registration`, `Request`, `Seal` e `Space`;
* [EntityRevision](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityRevision.php): Implementa a funcionalidade de revisões para as entidades. É utilizada nas entidades `Agent`, `Space`, `Registration` e `RegistrationEvaluation`;
* [EntitySealRelation](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntitySealRelation.php): Implementa a funcionalidade da aplicação de selos nas entidades. Utilizado em `Agent`, `Event`, `Opportunity`, `Project` e `Space`;
* [EntitySoftDelete](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntitySoftDelete.php): Implementa o soft delete (lixeira) para as entidades. Utilizado em `Agent`, `Event`, `Opportunity`, `Project`, `Seal`, `Space`, `Subsite` e `UserApp`;
* [EntityTaxonomies](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityTaxonomies.php): Implementa a funcionalidade de aplicar termos de taxonomias (tags, linguagem e área de atuação) nas entidades. Utilizado nas entidades `Agent`, `Event`, `Opportunity`, `Project` e `Space`;
* [EntityTypes](https://github.com/mapasculturais/mapasculturais/blob/master/src/protected/application/lib/MapasCulturais/Traits/EntityTypes.php): Implementa o campo `type` nas entidades. Utilizado em `Agent`, `EvaluationMethodConfiguration`, `Event`, `Opportunity`, `Project` e `Space`.
