Skip to content

Commit

Permalink
Added code moved from juniwalk/utils:^1.2.38
Browse files Browse the repository at this point in the history
  • Loading branch information
juniwalk committed Dec 5, 2022
1 parent 18fd1f5 commit 058900e
Show file tree
Hide file tree
Showing 20 changed files with 1,011 additions and 0 deletions.
25 changes: 25 additions & 0 deletions composer.json
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"
}
}
176 changes: 176 additions & 0 deletions src/AbstractRepository.php
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);
}
}
22 changes: 22 additions & 0 deletions src/Exceptions/EntityNotFoundException.php
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.');
}
}
22 changes: 22 additions & 0 deletions src/Exceptions/EntityNotValidException.php
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.');
}
}
95 changes: 95 additions & 0 deletions src/Functions/Cast.php
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 . ')';
}
}
47 changes: 47 additions & 0 deletions src/Functions/DatePart.php
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.')';
}
}
Loading

0 comments on commit 058900e

Please sign in to comment.