Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.x] Support Non-Table Models #985

Open
wants to merge 4 commits into
base: 2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/Command/TestCommand.php
Expand Up @@ -24,6 +24,7 @@
use Cake\Core\Configure;
use Cake\Core\Exception\CakeException;
use Cake\Core\Plugin;
use Cake\Datasource\RepositoryInterface;
use Cake\Filesystem\Filesystem;
use Cake\Http\Response;
use Cake\Http\ServerRequest as Request;
Expand Down Expand Up @@ -440,13 +441,13 @@
* Generate the list of fixtures that will be required to run this test based on
* loaded models.
*
* @param \Cake\ORM\Table|\Cake\Controller\Controller $subject The object you want to generate fixtures for.
* @param \Cake\Datasource\RepositoryInterface|\Cake\Controller\Controller $subject The object you want to generate fixtures for.
* @return string[] Array of fixtures to be included in the test.
*/
public function generateFixtureList($subject): array
{
$this->_fixtures = [];
if ($subject instanceof Table) {
if ($subject instanceof RepositoryInterface) {
$this->_processModel($subject);
} elseif ($subject instanceof Controller) {
$this->_processController($subject);
Expand All @@ -459,19 +460,22 @@
/**
* Process a model, pull out model name + associations converted to fixture names.
*
* @param \Cake\ORM\Table $subject A Model class to scan for associations and pull fixtures off of.
* @param \Cake\Datasource\RepositoryInterface $subject A Model class to scan for associations and pull fixtures off of.
* @return void
*/
protected function _processModel(Table $subject): void
protected function _processModel(RepositoryInterface $subject): void
{
$this->_addFixture($subject->getAlias());
if (!method_exists($subject, 'associations')) {
return;
}
foreach ($subject->associations()->keys() as $alias) {
$assoc = $subject->getAssociation($alias);

Check failure on line 473 in src/Command/TestCommand.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

Call to an undefined method Cake\Datasource\RepositoryInterface::getAssociation().
$target = $assoc->getTarget();
$name = $target->getAlias();
$subjectClass = get_class($subject);

if ($subjectClass !== Table::class && $subjectClass === get_class($target)) {

Check failure on line 478 in src/Command/TestCommand.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

Result of && is always false.

Check failure on line 478 in src/Command/TestCommand.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

Strict comparison using === between *NEVER* and class-string|false will always evaluate to false.

Check failure on line 478 in src/Command/TestCommand.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

RedundantCondition

src/Command/TestCommand.php:478:17: RedundantCondition: Cake\ORM\Table::class can never contain class-string<Cake\Datasource\RepositoryInterface&object{associations()}> (see https://psalm.dev/122)
continue;
}
if (!isset($this->_fixtures[$name])) {
Expand Down
35 changes: 35 additions & 0 deletions tests/TestCase/Command/TestCommandTest.php
Expand Up @@ -18,6 +18,8 @@

use Bake\Command\TestCommand;
use Bake\Test\App\Controller\PostsController;
use Bake\Test\App\Model\NonTable\NonTableWithAssociations;
use Bake\Test\App\Model\NonTable\NonTableWithoutAssociations;
use Bake\Test\App\Model\Table\ArticlesTable;
use Bake\Test\App\Model\Table\CategoryThreadsTable;
use Bake\Test\TestCase\TestCase;
Expand Down Expand Up @@ -233,6 +235,39 @@ public function testFixtureArrayGenerationFromModel()
$this->assertEquals($expected, $result);
}

/**
* Test that the generation of fixtures works correctly with a non-table model without associations.
*
* @return void
*/
public function testFixtureArrayGenerationFromNonTableModelWithoutAssociations()
{
$command = new TestCommand();
$subject = new NonTableWithoutAssociations();
$result = $command->generateFixtureList($subject);
$expected = [
'app.NonTableWithoutAssociations',
];
$this->assertEquals($expected, $result);
}

/**
* Test that the generation of fixtures works correctly with a non-table model with associations.
*
* @return void
*/
public function testFixtureArrayGenerationFromNonTableModelWithAssociations()
{
$command = new TestCommand();
$subject = new NonTableWithAssociations();
$result = $command->generateFixtureList($subject);
$expected = [
'app.NonTableWithAssociations',
'app.Users',
];
$this->assertEquals($expected, $result);
}

/**
* test that the generation of fixtures works correctly.
*
Expand Down
86 changes: 86 additions & 0 deletions tests/test_app/App/Model/NonTable/AbstractNonTable.php
@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);

namespace Bake\Test\App\Model\NonTable;

use Cake\Datasource\EntityInterface;
use Cake\Datasource\RepositoryInterface;

/**
* An abstract non-table model with stubbed methods demanded by RepositoryInterface
*/
abstract class AbstractNonTable implements RepositoryInterface
{
public function setAlias(string $alias)
{
}

public function getAlias(): string
{
return substr(static::class, strrpos(static::class, '\\') + 1);
}

public function setRegistryAlias(string $registryAlias)
{
}

public function getRegistryAlias(): string
{
}

public function hasField(string $field): bool
{
}

public function find(string $type = 'all', array $options = [])
{
}

public function get($primaryKey, array $options = []): EntityInterface
{
}

public function query()
{
}

public function updateAll($fields, $conditions): int
{
}

public function deleteAll($conditions): int
{
}

public function exists($conditions): bool
{
}

public function save(EntityInterface $entity, $options = [])
{
}

public function delete(EntityInterface $entity, $options = []): bool
{
}

public function newEmptyEntity(): EntityInterface
{
}

public function newEntity(array $data, array $options = []): EntityInterface
{
}

public function newEntities(array $data, array $options = []): array
{
}

public function patchEntity(EntityInterface $entity, array $data, array $options = []): EntityInterface
{
}

public function patchEntities(iterable $entities, array $data, array $options = []): array
{
}
}
41 changes: 41 additions & 0 deletions tests/test_app/App/Model/NonTable/NonTableWithAssociations.php
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);

namespace Bake\Test\App\Model\NonTable;

use Cake\ORM\Association;
use Cake\ORM\Association\BelongsTo;
use Cake\ORM\AssociationCollection;

/**
* A non-table based model with associations
*/
class NonTableWithAssociations extends AbstractNonTable
{
protected $associations;

/**
* Get the associations collection for this table.
*
* @return \Cake\ORM\AssociationCollection The collection of association objects.
*/
public function associations(): AssociationCollection
{
$this->associations = new AssociationCollection();

$this->associations->load(BelongsTo::class, 'Users');

return $this->associations;
}

/**
* Returns an association object configured for the specified alias.
*
* @param string $name The alias used for the association.
* @return \Cake\ORM\Association The association.
*/
public function getAssociation(string $name): Association
{
return $this->associations->get($name);
}
}
11 changes: 11 additions & 0 deletions tests/test_app/App/Model/NonTable/NonTableWithoutAssociations.php
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);

namespace Bake\Test\App\Model\NonTable;

/**
* A non-table based model without associations
*/
class NonTableWithoutAssociations extends AbstractNonTable
{
}