Skip to content

Commit

Permalink
Refactored to support attributes and drop annotation support
Browse files Browse the repository at this point in the history
  • Loading branch information
oojacoboo committed Dec 19, 2021
1 parent 59d4933 commit f823d31
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 144 deletions.
16 changes: 7 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,13 @@ In this example, it's assumed that the `Product` table has a column called `comp

```php
use Doctrine\ORM\Mapping as ORM;
use Rentpost\Doctrine\MultiTenancy\Annotation\MultiTenancy;
use Rentpost\Doctrine\MultiTenancy\Attribute\MultiTenancy;

#[ORM\Entity]
#[MultiTenancy(filters: [
new MultiTenancy\Filter(where: '$this.company_id = {companyId}'),
])]

/**
* @ORM\Entity
*
* @MultiTenancy(filters={
* @MultiTenancy\Filter(where="$this.company_id = {companyId}")
* })
*/
class Product
{
// Whatever
Expand All @@ -162,7 +160,7 @@ In the second filter, the `product` table doesn't have access to the necessary i

```php
use Doctrine\ORM\Mapping as ORM;
use Rentpost\Doctrine\MultiTenancy\Annotation\MultiTenancy;
use Rentpost\Doctrine\MultiTenancy\Attribute\MultiTenancy;

/**
* @ORM\Entity
Expand Down
55 changes: 0 additions & 55 deletions src/Annotation/MultiTenancy.php

This file was deleted.

55 changes: 0 additions & 55 deletions src/Annotation/MultiTenancy/Filter.php

This file was deleted.

44 changes: 44 additions & 0 deletions src/Attribute/MultiTenancy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types = 1);

namespace Rentpost\Doctrine\MultiTenancy\Attribute;

use Attribute;

/**
* Attribute service for Multi-tenancy
*
* @author Jacob Thomason <[email protected]>
*/
#[Attribute(Attribute::TARGET_CLASS)]
final class MultiTenancy
{

/**
* Constructor
*
* @param MultiTenancy\Filter[] $filters
*/
public function __construct(protected array $filters = [], protected bool $enable = true) {}


/**
* Checks if MultiTenancy is enabled
*/
public function isEnabled(): bool
{
return $this->enable;
}


/**
* Gets the filters associated with this attribute
*
* @return MultiTenancy\Filter[]
*/
public function getFilters(): array
{
return $this->filters;
}
}
44 changes: 44 additions & 0 deletions src/Attribute/MultiTenancy/Filter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types = 1);

namespace Rentpost\Doctrine\MultiTenancy\Attribute\MultiTenancy;

use Attribute;

/**
* Attribute service for Multi-tenancy filters
*
* @author Jacob Thomason <[email protected]>
*/
#[Attribute(Attribute::TARGET_CLASS|Attribute::IS_REPEATABLE)]
final class Filter
{

/**
* Constructor
*
* @param string[] $context
*/
public function __construct(protected array $context = [], protected string $where = '') {}


/**
* Gets the filter context
*
* @return string[]
*/
public function getContext(): array
{
return $this->context;
}


/**
* Gets the SQL where clause
*/
public function getWhereClause(): string
{
return $this->where;
}
}
4 changes: 2 additions & 2 deletions src/AnnotationException.php → src/AttributeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
namespace Rentpost\Doctrine\MultiTenancy;

/**
* Throw this exception when there is an issue with the MultiTenancy annotation.
* Throw this exception when there is an issue with the MultiTenancy attribute.
*
* @author Jacob Thomason <[email protected]>
*/
class AnnotationException extends \Exception
class AttributeException extends \Exception
{
}
38 changes: 15 additions & 23 deletions src/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@

namespace Rentpost\Doctrine\MultiTenancy;

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\Reader;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter;
use Rentpost\Doctrine\MultiTenancy\Annotation\MultiTenancy;
use Rentpost\Doctrine\MultiTenancy\Attribute\MultiTenancy;

/**
* Multi-tenancy filter to handle filtering by the company
Expand All @@ -21,17 +20,8 @@ class Filter extends SQLFilter

protected ?Listener $listener = null;
protected ?EntityManagerInterface $entityManager = null;
protected ?Reader $annotationReader = null;


/**
* Gets the annotation reader
*/
protected function getAnnotationReader(): Reader
{
return $this->annotationReader ?: new AnnotationReader();
}


/**
* Gets the EntityManager.
Expand Down Expand Up @@ -188,35 +178,37 @@ public function setAnnotationReader(Reader $annotationReader): void
*/
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
// Get our multi-tenancy annotation from the class
$multiTenancy = $this->getAnnotationReader()->getClassAnnotation(
$targetEntity->reflClass,
MultiTenancy::class,
);
$attributes = $targetEntity->reflClass->getAttributes(MultiTenancy::class);

// We get null if the annotation hasn't been defined. That's an issue since, for security
// reasons, we want to ensure that the entity has explicitly been disabled for multi-tenancy.
if (!$multiTenancy instanceof MultiTenancy) {
throw new \LogicException(sprintf(
'%s must have the MultiTenancy annotation added to the class docblock.',
// If no attributes have been defined, this is an issue. For security reasons, we want
// to ensure that the entity has explicitly been disabled for multi-tenancy.
if (count($attributes) === 0) {
throw new AttributeException(sprintf(
'%s must have the MultiTenancy attribute added to the class docblock.',
$targetEntity->rootEntityName,
));
}

$multiTenancy = $attributes[0]->newInstance();
assert($multiTenancy instanceof MultiTenancy);

if (!$multiTenancy->isEnabled()) {
return '';
}

$filters = $multiTenancy->getFilters();
if (!$filters) {
throw new \LogicException(sprintf(
throw new AttributeException(sprintf(
'%s is enabled for MultiTenancy, but there were not any added filters.',
$targetEntity->rootEntityName,
));
}

$defaultMap = $this->getDefaultMap($targetTableAlias);
[$identifiers, $values] = $this->getMergedMaps($defaultMap, ...$this->getValueHolderIdentifiersAndValues());
[$identifiers, $values] = $this->getMergedMaps(
$defaultMap,
...$this->getValueHolderIdentifiersAndValues(),
);

$whereClauses = [];
foreach ($filters as $filter) {
Expand Down

0 comments on commit f823d31

Please sign in to comment.