-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added code moved from juniwalk/utils:^1.2.38
- Loading branch information
Showing
20 changed files
with
1,011 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "juniwalk/orm", | ||
"description": "Nice to have tools for doctrine/orm in nette framework.", | ||
"type": "library", | ||
"keywords": ["nette","nettefw","doctrine","orm"], | ||
"license": "MIT", | ||
|
||
"authors": [{ | ||
"name": "Martin Procházka", | ||
"email": "[email protected]", | ||
"role": "Developer" | ||
}], | ||
|
||
"autoload": { | ||
"psr-4": {"JuniWalk\\ORM\\": "src/"} | ||
}, | ||
|
||
"require": { | ||
"php": ">=8.1", | ||
"juniwalk/utils": ">=2.0", | ||
"nettrine/migrations": "^0.8", | ||
"nettrine/orm": "^0.8", | ||
"ramsey/uuid": "^4.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
<?php declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Martin Procházka (c) 2022 | ||
* @license MIT License | ||
*/ | ||
|
||
namespace JuniWalk\ORM; | ||
|
||
use Doctrine\DBAL\Connection; | ||
use Doctrine\DBAL\DBALException; | ||
use Doctrine\ORM\EntityManagerInterface as EntityManager; | ||
use Doctrine\ORM\Query; | ||
use Doctrine\ORM\QueryBuilder; | ||
use Doctrine\ORM\NoResultException; | ||
use JuniWalk\ORM\Exceptions\EntityNotFoundException; | ||
use Nette\Application\UI\Form; | ||
|
||
abstract class AbstractRepository | ||
{ | ||
protected readonly EntityManager $entityManager; | ||
protected readonly Connection $connection; | ||
protected string $entityName; | ||
|
||
|
||
/** | ||
* @throws EntityNotFoundException | ||
*/ | ||
public function __construct(EntityManager $entityManager) | ||
{ | ||
$this->connection = $entityManager->getConnection(); | ||
$this->entityManager = $entityManager; | ||
|
||
if (!$this->entityName) { | ||
throw EntityNotFoundException::fromClass($this->entityName); | ||
} | ||
} | ||
|
||
|
||
/** | ||
* @throws NoResultException | ||
*/ | ||
public function getBy(callable $where, ?int $maxResults = null): array | ||
{ | ||
/** @see Hardcoded indexBy might cause issues with entities without $id */ | ||
$qb = $this->createQueryBuilder('e', 'e.id', $where); | ||
$qb->setMaxResults($qb->getMaxResults() ?? $maxResults); | ||
|
||
return $qb->getQuery() | ||
->getResult(); | ||
} | ||
|
||
|
||
/** | ||
* @throws NoResultException | ||
*/ | ||
public function getOneBy(callable $where): object | ||
{ | ||
/** @see Hardcoded indexBy might cause issues with entities without $id */ | ||
$qb = $this->createQueryBuilder('e', 'e.id', $where); | ||
$qb->setMaxResults(1); | ||
|
||
return $qb->getQuery() | ||
->getSingleResult(); | ||
} | ||
|
||
|
||
public function findBy(callable $where, ?int $maxResults = null): array | ||
{ | ||
try { | ||
return $this->getBy($where, $maxResults); | ||
|
||
} catch (NoResultException) { | ||
return []; | ||
} | ||
} | ||
|
||
|
||
public function findOneBy(callable $where): ?object | ||
{ | ||
try { | ||
return $this->getOneBy($where); | ||
|
||
} catch (NoResultException) { | ||
return null; | ||
} | ||
} | ||
|
||
|
||
/** | ||
* @throws NoResultException | ||
*/ | ||
public function getById(int $id): object | ||
{ | ||
return $this->getOneBy(function($qb) use ($id) { | ||
$qb->where('e.id = :id')->setParameter('id', $id); | ||
}); | ||
} | ||
|
||
|
||
public function findById(int $id): ?object | ||
{ | ||
try { | ||
return $this->getById($id); | ||
|
||
} catch (NoResultException) { | ||
return null; | ||
} | ||
} | ||
|
||
|
||
public function createQueryBuilder(string $alias, string $indexBy = null, callable $where = null): QueryBuilder | ||
{ | ||
$qb = $this->entityManager->createQueryBuilder()->select($alias) | ||
->from($this->entityName, $alias, $indexBy); | ||
|
||
if ($where) { | ||
$qb = $where($qb) ?: $qb; | ||
} | ||
|
||
return $qb; | ||
} | ||
|
||
|
||
public function createQuery(string $dql = null): Query | ||
{ | ||
return $this->entityManager->createQuery($dql); | ||
} | ||
|
||
|
||
public function getReference(?int $id, string $entityName = null): ?object | ||
{ | ||
if (!$id || empty($id)) { | ||
return null; | ||
} | ||
|
||
return $this->entityManager->getReference($entityName ?: $this->entityName, $id); | ||
} | ||
|
||
|
||
public function getFormReference(string $field, Form $form): ?object | ||
{ | ||
return $this->getReference( | ||
(int) $form->getHttpData($form::DATA_LINE, $field) ?: null | ||
); | ||
} | ||
|
||
|
||
public function truncateTable(bool $cascade = false, string $entityName = null): void | ||
{ | ||
$this->query('TRUNCATE TABLE "'.$this->getTableName($entityName).'" RESTART IDENTITY'.($cascade == true ? ' CASCADE' : null)); | ||
} | ||
|
||
|
||
public function getTableName(string $entityName = null): string | ||
{ | ||
$entityName = $entityName ?: $this->entityName; | ||
$metaData = $this->entityManager->getClassMetadata($entityName); | ||
$tableName = $metaData->getTableName(); | ||
|
||
if ($schemaName = $metaData->getSchemaName()) { | ||
$tableName = $schemaName.'.'.$tableName; | ||
} | ||
|
||
return $tableName; | ||
} | ||
|
||
|
||
/** | ||
* @throws DBALException | ||
*/ | ||
private function query(string $query): mixed | ||
{ | ||
return $this->connection->query($query); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Martin Procházka (c) 2022 | ||
* @license MIT License | ||
*/ | ||
|
||
namespace JuniWalk\ORM\Exceptions; | ||
|
||
final class EntityNotFoundException extends \RuntimeException | ||
{ | ||
public static function fromEntity(object $entity): static | ||
{ | ||
return static::fromClass(get_class($entity)); | ||
} | ||
|
||
|
||
public static function fromClass(string $entityName): static | ||
{ | ||
return new static('Entity '.$entityName.' was not found.'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Martin Procházka (c) 2022 | ||
* @license MIT License | ||
*/ | ||
|
||
namespace JuniWalk\ORM\Exceptions; | ||
|
||
final class EntityNotValidException extends \RuntimeException | ||
{ | ||
public static function fromEntity(object $entity): static | ||
{ | ||
return static::fromClass(get_class($entity)); | ||
} | ||
|
||
|
||
public static function fromClass(string $entityName): static | ||
{ | ||
return new static('Entity '.$entityName.' is not valid.'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<?php declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Martin Procházka (c) 2022 | ||
* @license MIT License | ||
*/ | ||
|
||
namespace JuniWalk\ORM\Functions; | ||
|
||
use Doctrine\ORM\Query\AST\Functions\FunctionNode; | ||
use Doctrine\ORM\Query\AST\Literal; | ||
use Doctrine\ORM\Query\AST\Node; | ||
use Doctrine\ORM\Query\Lexer; | ||
use Doctrine\ORM\Query\Parser; | ||
use Doctrine\ORM\Query\SqlWalker; | ||
|
||
/** | ||
* "cast" "(" Column, Type ")") | ||
*/ | ||
final class Cast extends FunctionNode | ||
{ | ||
public Node $column; | ||
public Node $type; | ||
|
||
|
||
public function parse(Parser $parser): void | ||
{ | ||
$parser->match(Lexer::T_IDENTIFIER); // (2) | ||
$parser->match(Lexer::T_OPEN_PARENTHESIS); // (3) | ||
$lexer = $parser->getLexer(); | ||
|
||
$this->column = $parser->StringPrimary(); // (4) | ||
|
||
switch (true) { | ||
case $lexer->isNextToken(Lexer::T_COMMA): | ||
$parser->match(Lexer::T_COMMA); // (5) | ||
break; | ||
case $lexer->isNextToken(Lexer::T_AS): | ||
$parser->match(Lexer::T_AS); // (5) | ||
break; | ||
} | ||
|
||
switch (true) { | ||
case $lexer->isNextToken(Lexer::T_STRING): | ||
$this->type = $parser->ScalarExpression(); // (6) | ||
break; | ||
case $lexer->isNextToken(Lexer::T_IDENTIFIER): | ||
$parser->match(Lexer::T_IDENTIFIER); | ||
$this->type = new Literal(Literal::STRING, $lexer->token['value']); // (6) | ||
break; | ||
} | ||
|
||
$parser->match(Lexer::T_CLOSE_PARENTHESIS); // (7) | ||
} | ||
|
||
|
||
/** | ||
* @see https://github.com/oroinc/doctrine-extensions/blob/master/src/Oro/ORM/Query/AST/Platform/Functions/Postgresql/Cast.php | ||
*/ | ||
public function getSql(SqlWalker $sqlWalker): string | ||
{ | ||
/** @var Node $value */ | ||
$column = $sqlWalker->walkSimpleArithmeticExpression($this->column); | ||
$type = $sqlWalker->walkSimpleArithmeticExpression($this->type); | ||
|
||
$type = trim(strtolower($type), '"\''); | ||
if ($type === 'datetime') { | ||
return '"timestamp"(' . $column . ')'; | ||
} | ||
|
||
if ($type === 'json' && !$sqlWalker->getConnection()->getDatabasePlatform()->hasNativeJsonType()) { | ||
$type = 'text'; | ||
} | ||
|
||
if ($type === 'bool') { | ||
$type = 'boolean'; | ||
} | ||
|
||
if ($type === 'binary') { | ||
$type = 'bytea'; | ||
} | ||
|
||
/** | ||
* The notations varchar(n) and char(n) are aliases for character varying(n) and character(n), respectively. | ||
* character without length specifier is equivalent to character(1). If character varying is used | ||
* without length specifier, the type accepts strings of any size. The latter is a PostgreSQL extension. | ||
* http://www.postgresql.org/docs/9.2/static/datatype-character.html | ||
*/ | ||
if ($type === 'string') { | ||
$type = 'varchar'; | ||
} | ||
|
||
return 'cast(' . $column . ' AS ' . $type . ')'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<?php declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Martin Procházka (c) 2022 | ||
* @license MIT License | ||
*/ | ||
|
||
namespace JuniWalk\ORM\Functions; | ||
|
||
use Doctrine\ORM\Query\AST\Functions\FunctionNode; | ||
use Doctrine\ORM\Query\AST\Node; | ||
use Doctrine\ORM\Query\Lexer; | ||
use Doctrine\ORM\Query\Parser; | ||
use Doctrine\ORM\Query\SqlWalker; | ||
|
||
/** | ||
* "date_part" "(" Interval ", " Column ")" | ||
*/ | ||
final class DatePart extends FunctionNode | ||
{ | ||
public Node $interval; | ||
public Node $column; | ||
|
||
|
||
public function parse(Parser $parser): void | ||
{ | ||
$parser->match(Lexer::T_IDENTIFIER); // (2) | ||
$parser->match(Lexer::T_OPEN_PARENTHESIS); // (3) | ||
|
||
$this->interval = $parser->StringPrimary(); // (4) | ||
|
||
$parser->match(Lexer::T_COMMA); // (5) | ||
|
||
$this->column = $parser->StringPrimary(); // (6) | ||
|
||
$parser->match(Lexer::T_CLOSE_PARENTHESIS); // (7) | ||
} | ||
|
||
|
||
public function getSql(SqlWalker $sqlWalker): string | ||
{ | ||
$interval = $sqlWalker->walkSimpleArithmeticExpression($this->interval); | ||
$column = $sqlWalker->walkSimpleArithmeticExpression($this->column); | ||
|
||
return 'date_part('.$interval.', '.$column.')'; | ||
} | ||
} |
Oops, something went wrong.