# 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`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mapasculturais.gitbook.io/documentacao-para-desenvolvedores/formacao-para-desenvolvedores/entidades.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
