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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ permissions:

jobs:
testsuite:
uses: ADmad/.github/.github/workflows/testsuite-with-db.yml@master
uses: ADmad/.github/.github/workflows/testsuite-with-db.yml@cake6
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

cs-stan:
uses: ADmad/.github/.github/workflows/cs-stan.yml@master
uses: ADmad/.github/.github/workflows/cs-stan.yml@cake6
secrets: inherit
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Add the `FootprintMiddleware` to the middleware queue in your `Application::midd
method:

```php
$middleware->add('Muffin/Footprint.Footprint');
$middleware->add(new \Muffin\Footprint\Middleware\FootprintMiddleware());
```

It must be added **after** `AuthenticationMiddleware` to ensure that it can read
Expand Down
9 changes: 6 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@
"source": "https://github.com/usemuffin/footprint"
},
"require": {
"cakephp/cakephp": "^5.0"
"php": ">=8.5",
"cakephp/cakephp": "^6.0"
},
"require-dev": {
"cakephp/cakephp-codesniffer": "^5.0",
"phpunit/phpunit": "^11.5.3 || ^12.4 || ^13.0"
"cakephp/cakephp-codesniffer": "^6.0",
"phpunit/phpunit": "^13.0"
},
"scripts": {
"cs-check": "phpcs --colors --parallel=16 -p src/ tests/",
Expand All @@ -52,6 +53,8 @@
"Cake\\Test\\Fixture\\": "vendor/cakephp/cakephp/tests/Fixture"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
Expand Down
5 changes: 0 additions & 5 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,3 @@ parameters:
treatPhpDocTypesAsCertain: false
paths:
- src/
ignoreErrors:
-
message: "#^Call to an undefined method object\\:\\:getEventManager\\(\\)\\.$#"
count: 1
path: src/FootprintPlugin.php
4 changes: 2 additions & 2 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="./tests/bootstrap.php" colors="true" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" cacheDirectory=".phpunit.cache">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="./tests/bootstrap.php" colors="true" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/13.0/phpunit.xsd" cacheDirectory=".phpunit.cache">
<testsuites>
<testsuite name="Slug Test Cases">
<testsuite name="Footprint Test Cases">
<directory>./tests/</directory>
</testsuite>
</testsuites>
Expand Down
6 changes: 0 additions & 6 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="6.16.1@f1f5de594dc76faf8784e02d3dc4716c91c6f6ac">
<file src="src/FootprintPlugin.php">
<MoreSpecificImplementedParamType>
<code><![CDATA[$app]]></code>
<code><![CDATA[$app]]></code>
</MoreSpecificImplementedParamType>
</file>
<file src="src/Model/Behavior/FootprintBehavior.php">
<InvalidArgument>
<code><![CDATA[$options]]></code>
Expand Down
14 changes: 7 additions & 7 deletions src/Event/FootprintListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class FootprintListener implements EventListenerInterface
*
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
protected array $defaultConfig = [
'events' => [
'Model.beforeFind' => -100,
'Model.beforeRules' => -100,
Expand All @@ -34,7 +34,7 @@ class FootprintListener implements EventListenerInterface
*
* @var \Cake\Datasource\EntityInterface|null
*/
protected ?EntityInterface $_currentUser;
protected ?EntityInterface $currentUser;

/**
* Constructor.
Expand All @@ -45,7 +45,7 @@ class FootprintListener implements EventListenerInterface
public function __construct(?EntityInterface $user = null, array $config = [])
{
$this->setConfig($config);
$this->_currentUser = $user;
$this->currentUser = $user;
}

/**
Expand All @@ -70,7 +70,7 @@ public function implementedEvents(): array
*/
public function setUser(EntityInterface $entity): void
{
$this->_currentUser = $entity;
$this->currentUser = $entity;
}

/**
Expand All @@ -80,7 +80,7 @@ public function setUser(EntityInterface $entity): void
*/
public function getUser(): ?EntityInterface
{
return $this->_currentUser;
return $this->currentUser;
}

/**
Expand All @@ -97,8 +97,8 @@ public function handleEvent(
ArrayObject $options,
): void {
$key = $this->getConfig('optionKey');
if ($this->_currentUser && empty($options[$key])) {
$options[$key] = $this->_currentUser;
if ($this->currentUser && empty($options[$key])) {
$options[$key] = $this->currentUser;
}
}
}
8 changes: 6 additions & 2 deletions src/FootprintPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Cake\Core\BasePlugin;
use Cake\Core\PluginApplicationInterface;
use Cake\Event\EventInterface;
use Cake\ORM\Table;
use Muffin\Footprint\Event\FootprintListener;

class FootprintPlugin extends BasePlugin
Expand All @@ -25,7 +26,7 @@ class FootprintPlugin extends BasePlugin
/**
* Bootstrap hook
*
* @param \Cake\Core\PluginApplicationInterface<self> $app Application instance.
* @param \Cake\Core\PluginApplicationInterface $app Application instance.
* @return void
*/
public function bootstrap(PluginApplicationInterface $app): void
Expand All @@ -34,7 +35,10 @@ public function bootstrap(PluginApplicationInterface $app): void
'Model.initialize',
/** @param \Cake\Event\EventInterface<\Cake\ORM\Table> $event */
function (EventInterface $event): void {
$event->getSubject()->getEventManager()->on(static::getListener());
$table = $event->getSubject();
if ($table instanceof Table) {
$table->getEventManager()->on(static::getListener());
}
},
);
}
Expand Down
26 changes: 13 additions & 13 deletions src/Model/Behavior/FootprintBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class FootprintBehavior extends Behavior
*
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
protected array $defaultConfig = [
'events' => [
'Model.beforeSave' => [
'created_by' => 'new',
Expand All @@ -34,9 +34,9 @@ class FootprintBehavior extends Behavior
];

/**
* Intialize the behavior.
* Initialize the behavior.
*
* @param array<string, mixeD> $config Config options.
* @param array<string, mixed> $config Config options.
* @return void
*/
public function initialize(array $config): void
Expand All @@ -54,7 +54,7 @@ public function initialize(array $config): void
$config['propertiesMap'][] = $field;
}
}
$this->_config['events'][$name] = $options;
$this->config['events'][$name] = $options;
}

foreach ($config['propertiesMap'] as $property => $map) {
Expand Down Expand Up @@ -82,7 +82,7 @@ public function implementedEvents(): array
{
/** @phpstan-ignore-next-line */
return array_fill_keys(
array_keys($this->_config['events']),
array_keys($this->config['events']),
'dispatch',
);
}
Expand All @@ -100,19 +100,19 @@ public function implementedEvents(): array
public function dispatch(EventInterface $event, EntityInterface|SelectQuery $data, ArrayObject $options): void
{
$eventName = $event->getName();
if (empty($this->_config['events'][$eventName])) {
if (empty($this->config['events'][$eventName])) {
return;
}

$fields = $this->_config['events'][$eventName];
$fields = $this->config['events'][$eventName];

if ($data instanceof EntityInterface) {
$this->_injectEntity($data, $options, $fields);
$this->injectEntity($data, $options, $fields);

return;
}

$this->_injectConditions($data, $options, $fields);
$this->injectConditions($data, $options, $fields);
}

/**
Expand All @@ -123,7 +123,7 @@ public function dispatch(EventInterface $event, EntityInterface|SelectQuery $dat
* @param array<string, mixed> $fields Field configuration.
* @return void
*/
protected function _injectConditions(SelectQuery $query, ArrayObject $options, array $fields): void
protected function injectConditions(SelectQuery $query, ArrayObject $options, array $fields): void
{
foreach (array_keys($fields) as $field) {
$path = $this->getConfig('propertiesMap.' . $field);
Expand All @@ -135,7 +135,7 @@ protected function _injectConditions(SelectQuery $query, ArrayObject $options, a

return;
}
$alias = $this->_table->aliasField($field);
$alias = $this->table->aliasField($field);
!$check && $check = preg_match(
'/^' . $alias . '/',
// TODO: Add test to show that cloning is necessary here to avoid issue mentioned in
Expand All @@ -146,7 +146,7 @@ protected function _injectConditions(SelectQuery $query, ArrayObject $options, a

$value = Hash::get((array)$options, $path);
if (!$check && $value) {
$query->where([$this->_table->aliasField($field) => $value]);
$query->where([$this->table->aliasField($field) => $value]);
}
}
}
Expand All @@ -159,7 +159,7 @@ protected function _injectConditions(SelectQuery $query, ArrayObject $options, a
* @param array<string, string|\Closure> $fields Field configuration.
* @return void
*/
protected function _injectEntity(EntityInterface $entity, ArrayObject $options, array $fields): void
protected function injectEntity(EntityInterface $entity, ArrayObject $options, array $fields): void
{
$new = $entity->isNew() !== false;

Expand Down
76 changes: 76 additions & 0 deletions tests/TestCase/FootprintPluginTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php
declare(strict_types=1);

namespace Muffin\Footprint\Test\TestCase;

use Cake\Core\PluginApplicationInterface;
use Cake\Datasource\ConnectionManager;
use Cake\Event\Event;
use Cake\Event\EventManager;
use Cake\Http\Response;
use Cake\Http\ServerRequest;
use Cake\ORM\Entity;
use Cake\ORM\Table;
use Cake\TestSuite\TestCase;
use Muffin\Footprint\FootprintPlugin;
use Muffin\Footprint\Middleware\FootprintMiddleware;
use Psr\Http\Server\RequestHandlerInterface;
use ReflectionProperty;

class FootprintPluginTest extends TestCase
{
protected array $fixtures = [
'plugin.Muffin/Footprint.Articles',
];

public function tearDown(): void
{
(new ReflectionProperty(FootprintPlugin::class, 'listener'))->setValue(null, null);

parent::tearDown();
}

public function testMiddlewarePassesIdentityToDefaultBehavior(): void
{
$eventManager = new EventManager();
$app = $this->createStub(PluginApplicationInterface::class);
$app->method('getEventManager')->willReturn($eventManager);
(new FootprintPlugin())->bootstrap($app);

$table = new Table([
'table' => 'articles',
'alias' => 'Articles',
'connection' => ConnectionManager::get('test'),
'eventManager' => $eventManager,
]);
$table->addBehavior('Muffin/Footprint.Footprint');

$user = new Entity(['id' => 42]);
$request = (new ServerRequest())->withAttribute('identity', $user);
$response = new Response();
$handler = $this->createMock(RequestHandlerInterface::class);
$handler->expects($this->once())->method('handle')->with($request)
->willReturnCallback(function () use ($table, $response): Response {
$entity = $table->newEntity(['title' => 'With request identity']);
$saved = $table->saveOrFail($entity);

$this->assertSame(42, $saved->created_by);
$this->assertSame(42, $saved->modified_by);

return $response;
});

$this->assertSame($response, (new FootprintMiddleware())->process($request, $handler));
}

public function testInitializeWithoutSubject(): void
{
$eventManager = new EventManager();
$app = $this->createStub(PluginApplicationInterface::class);
$app->method('getEventManager')->willReturn($eventManager);
(new FootprintPlugin())->bootstrap($app);

$event = new Event('Model.initialize');
$this->assertSame($event, $eventManager->dispatch($event));
}
}
Loading