Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
.PHONY: install qa cs csf phpstan tests coverage

.PHONY: install
install:
composer update

.PHONY: qa
qa: phpstan cs

.PHONY: cs
cs:
ifdef GITHUB_ACTION
vendor/bin/codesniffer -q --report=checkstyle src tests | cs2pr
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp -q --report=checkstyle src tests | cs2pr
else
vendor/bin/codesniffer src tests
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp src tests
endif

.PHONY: csf
csf:
vendor/bin/codefixer src tests
vendor/bin/phpcbf --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp src tests

.PHONY: phpstan
phpstan:
vendor/bin/phpstan analyse -c phpstan.neon src
vendor/bin/phpstan analyse -c phpstan.neon

.PHONY: tests
tests:
vendor/bin/tester -s -p php --colors 1 -C tests/Cases

.PHONY: coverage
coverage:
ifdef GITHUB_ACTION
vendor/bin/tester -s -p phpdbg --colors 1 -C --coverage coverage.xml --coverage-src src tests/Cases
Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
],
"require": {
"php": ">=8.2",
"nextras/dbal": "^4.0.0"
"nextras/dbal": "^5.0.0"
},
"require-dev": {
"ninjify/qa": "^0.13",
"ninjify/nunjuck": "^0.4",
"contributte/qa": "^0.4.0",
"contributte/tester": "^0.3.0",
"nette/di": "^3.0.1",
"nextras/orm": "^4.0.0",
"nextras/orm": "^5.0.0",
"mockery/mockery": "^1.3.0",
"phpstan/phpstan": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
Expand Down
27 changes: 20 additions & 7 deletions ruleset.xml
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
<?xml version="1.0"?>
<ruleset name="Contributte">
<!-- Contributte Coding Standard -->
<rule ref="vendor/ninjify/coding-standard/contributte.xml"/>
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="Contributte" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
<!-- Rulesets -->
<rule ref="./vendor/contributte/qa/ruleset-8.2.xml"/>

<!-- Specific rules -->
<!-- Rules -->
<rule ref="SlevomatCodingStandard.Files.TypeNameMatchesFileName">
<properties>
<property name="rootNamespaces" type="array">
<element key="src" value="Contributte\Nextras\Orm\QueryObject"/>
<element key="tests" value="Tests"/>
</property>
<property name="extensions" type="array" value="php,phpt" />
</properties>
</rule>

<!-- Exclude folders -->
<!-- Exclude rules not applicable to .phpt test cases (inline classes without namespaces) -->
<rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
<exclude-pattern>/tests/Cases</exclude-pattern>
</rule>
<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
<exclude-pattern>/tests/Cases</exclude-pattern>
</rule>
<rule ref="Squiz.Classes.ClassFileName.NoMatch">
<exclude-pattern>/tests/Cases</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.Files.TypeNameMatchesFileName.NoMatchBetweenTypeNameAndFileName">
<exclude-pattern>/tests/Cases</exclude-pattern>
</rule>

<!-- Excludes -->
<exclude-pattern>/tests/tmp</exclude-pattern>
</ruleset>
6 changes: 3 additions & 3 deletions src/DI/NextrasQueryObjectExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Contributte\Nextras\Orm\QueryObject\QueryObjectManager;
use Nette\DI\CompilerExtension;
use Nette\DI\Extensions\InjectExtension;
use Nextras\Orm\Mapper\Mapper;
use Nextras\Orm\Mapper\IMapper;
use Nextras\Orm\Repository\Repository;

final class NextrasQueryObjectExtension extends CompilerExtension
Expand All @@ -31,11 +31,11 @@ public function beforeCompile(): void
{
$builder = $this->getContainerBuilder();

foreach ($builder->findByType(Repository::class) as $name => $def) {
foreach ($builder->findByType(Repository::class) as $def) {
$def->addTag(InjectExtension::TagInject);
}

foreach ($builder->findByType(Mapper::class) as $name => $def) {
foreach ($builder->findByType(IMapper::class) as $def) {
$def->addTag(InjectExtension::TagInject);
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/ExecutableQueryObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
abstract class ExecutableQueryObject extends QueryObject
{

/** @var Connection */
protected $connection;
protected Connection $connection;

public function __construct(Connection $connection)
{
Expand Down
10 changes: 5 additions & 5 deletions src/QueryObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
abstract class QueryObject implements Queryable
{

protected function postQuery(QueryBuilder $builder): QueryBuilder
{
return $builder;
}

public function fetch(QueryBuilder $builder): QueryBuilder
{
// Build query
Expand All @@ -23,4 +18,9 @@ public function fetch(QueryBuilder $builder): QueryBuilder
return $qb;
}

protected function postQuery(QueryBuilder $builder): QueryBuilder
{
return $builder;
}

}
5 changes: 2 additions & 3 deletions src/QueryObjectContextAwareManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
class QueryObjectContextAwareManager implements QueryObjectManager
{

/** @var Container */
protected $context;
protected Container $context;

public function __construct(Container $context)
{
Expand Down Expand Up @@ -45,7 +44,7 @@ public function create(string $class): QueryObject
$obj = $this->context->getByType($class);

if (!($obj instanceof QueryObject)) {
throw new InvalidObjectCreationException(sprintf('Created object must be typed of %s, type of %s given.', QueryObject::class, get_class($obj)));
throw new InvalidObjectCreationException(sprintf('Created object must be typed of %s, type of %s given.', QueryObject::class, $obj::class));
}

return $obj;
Expand Down
10 changes: 3 additions & 7 deletions src/Repository/TRepositoryQueryable.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,19 @@
use Contributte\Nextras\Orm\QueryObject\QueryObject;
use Nextras\Dbal\Connection;
use Nextras\Dbal\Result\Result;
use Nextras\Orm\Entity\IEntity;
use Nextras\Orm\Collection\ICollection;

trait TRepositoryQueryable
{

/** @var Connection */
protected $connection;
protected Connection $connection;

public function injectConnection(Connection $connection): void
{
$this->connection = $connection;
}

/**
* @return Result|IEntity
*/
public function fetch(QueryObject $queryObject, int $hydrationMode = Queryable::HYDRATION_RESULTSET)
public function fetch(QueryObject $queryObject, int $hydrationMode = Queryable::HYDRATION_RESULTSET): Result|ICollection
{
$qb = $queryObject->fetch($this->connection->createQueryBuilder());

Expand Down
23 changes: 13 additions & 10 deletions tests/Cases/E2E/BooksTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use Contributte\Nextras\Orm\QueryObject\QueryObjectManager;
use Nette\DI\Container;
use Nextras\Dbal\IConnection;
use Nextras\Dbal\Result\Result;
use Nextras\Dbal\Utils\FileImporter;
use Nextras\Orm\Collection\ICollection;
use Tester\Assert;
use Tester\TestCase;
Expand All @@ -23,21 +22,13 @@ $container = require_once __DIR__ . '/../../bootstrap.container.php';
final class BooksTest extends TestCase
{

/** @var Container */
private $container;
private Container $container;

public function __construct(Container $container)
{
$this->container = $container;
}

protected function setUp(): void
{
/** @var IConnection $connection */
$connection = $this->container->getByType(IConnection::class);
FileImporter::executeFile($connection, __DIR__ . '/../../Fixtures/mysql.sql');
}

/**
* Test empty results
*/
Expand Down Expand Up @@ -126,6 +117,18 @@ final class BooksTest extends TestCase
}
}

protected function setUp(): void
{
/** @var IConnection $connection */
$connection = $this->container->getByType(IConnection::class);
$sql = file_get_contents(__DIR__ . '/../../Fixtures/mysql.sql');
assert($sql !== false);

foreach (array_filter(array_map('trim', explode(';', $sql))) as $query) {
$connection->query('%raw', $query);
}
}

}

(new BooksTest($container))->run();
12 changes: 4 additions & 8 deletions tests/Cases/Exceptions.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,27 @@ use Tester\Assert;

require_once __DIR__ . '/../bootstrap.php';

// Test: InvalidHydrationModeException extends LogicException
test(function (): void {
test('InvalidHydrationModeException extends LogicException', function (): void {
$exception = new InvalidHydrationModeException('Test message');

Assert::type(LogicException::class, $exception);
Assert::same('Test message', $exception->getMessage());
});

// Test: InvalidObjectCreationException extends LogicException
test(function (): void {
test('InvalidObjectCreationException extends LogicException', function (): void {
$exception = new InvalidObjectCreationException('Creation failed');

Assert::type(LogicException::class, $exception);
Assert::same('Creation failed', $exception->getMessage());
});

// Test: InvalidHydrationModeException can be thrown and caught
test(function (): void {
test('InvalidHydrationModeException can be thrown and caught', function (): void {
Assert::exception(function (): void {
throw new InvalidHydrationModeException('Invalid hydration mode "99"');
}, InvalidHydrationModeException::class, 'Invalid hydration mode "99"');
});

// Test: InvalidObjectCreationException can be thrown and caught
test(function (): void {
test('InvalidObjectCreationException can be thrown and caught', function (): void {
Assert::exception(function (): void {
throw new InvalidObjectCreationException('Created object must be typed of QueryObject');
}, InvalidObjectCreationException::class, 'Created object must be typed of QueryObject');
Expand Down
13 changes: 6 additions & 7 deletions tests/Cases/ExecutableQueryObject.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class TestExecutableQueryObject extends ExecutableQueryObject

public function doQuery(QueryBuilder $builder): QueryBuilder
{
return $builder->select('[*]')->from('[test_table]');
return $builder->select('*')->from('[test_table]');
}

}
Expand All @@ -37,6 +37,7 @@ class TestExecutableQueryObjectWithPostResult extends ExecutableQueryObject
public function postResult(Result $result): Result
{
$this->postResultCalled = true;

return parent::postResult($result);
}

Expand All @@ -47,13 +48,12 @@ class TestExecutableQueryObjectWithPostResult extends ExecutableQueryObject

}

// Test: ExecutableQueryObject builds query via fetch method
test(function (): void {
test('ExecutableQueryObject builds query via fetch method', function (): void {
$connection = Mockery::mock(Connection::class);
$queryBuilder = Mockery::mock(QueryBuilder::class);

$queryBuilder->shouldReceive('select')
->with('[*]')
->with('*')
->once()
->andReturnSelf();

Expand All @@ -70,14 +70,13 @@ test(function (): void {
Mockery::close();
});

// Test: ExecutableQueryObject execute method uses connection
test(function (): void {
test('ExecutableQueryObject execute method uses connection', function (): void {
$connection = Mockery::mock(Connection::class);
$queryBuilder = Mockery::mock(QueryBuilder::class);
$result = Mockery::mock(Result::class);

$queryBuilder->shouldReceive('select')
->with('[*]')
->with('*')
->once()
->andReturnSelf();

Expand Down
11 changes: 7 additions & 4 deletions tests/Cases/QueryObject.phpt
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
<?php declare(strict_types = 1);

use Nextras\Dbal\Drivers\Mysqli\MysqliDriver;
use Nextras\Dbal\Platforms\IPlatform;
use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Tester\Assert;
use Tests\Mocks\SimpleQueryObject;

require_once __DIR__ . '/../bootstrap.php';

test(function (): void {
test('QueryObject builds query via fetch method', function (): void {
$platform = Mockery::mock(IPlatform::class);
$qo = new SimpleQueryObject();
$qb = $qo->fetch(new QueryBuilder(new MysqliDriver()));
$qb = $qo->fetch(new QueryBuilder($platform));

Assert::type(QueryBuilder::class, $qb);
Assert::equal('SELECT [*] FROM [foobar]', $qb->getQuerySql());
Assert::equal('SELECT * FROM [foobar]', $qb->getQuerySql());

Mockery::close();
});
11 changes: 4 additions & 7 deletions tests/Cases/QueryObjectContextAwareManager.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ use Tests\Mocks\SimpleQueryObject;

require_once __DIR__ . '/../bootstrap.php';

// Test: QueryObjectContextAwareManager create returns QueryObject
test(function (): void {
test('QueryObjectContextAwareManager create returns QueryObject', function (): void {
$queryObject = new SimpleQueryObject();

$container = Mockery::mock(Container::class);
Expand All @@ -31,8 +30,7 @@ test(function (): void {
Mockery::close();
});

// Test: QueryObjectContextAwareManager create throws InvalidObjectCreationException for non-QueryObject
test(function (): void {
test('QueryObjectContextAwareManager create throws InvalidObjectCreationException for non-QueryObject', function (): void {
$nonQueryObject = new stdClass();

$container = Mockery::mock(Container::class);
Expand All @@ -50,14 +48,13 @@ test(function (): void {
Mockery::close();
});

// Test: QueryObjectContextAwareManager fetch returns Result
test(function (): void {
test('QueryObjectContextAwareManager fetch returns Result', function (): void {
$connection = Mockery::mock(Connection::class);
$queryBuilder = Mockery::mock(QueryBuilder::class);
$result = Mockery::mock(Result::class);

$queryBuilder->shouldReceive('select')
->with('[*]')
->with('*')
->once()
->andReturnSelf();

Expand Down
Loading