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

Cake5 #112

Merged
merged 21 commits into from
May 11, 2024
Merged

Cake5 #112

Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
15 changes: 8 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ jobs:
strategy:
fail-fast: false
matrix:
php-version: ['7.4', '8.0', '8.3']
php-version: ['8.2', '8.3']
db-type: ['mysql', 'pgsql']
prefer-lowest: ['']
include:
- php-version: '7.4'
- php-version: '8.3'
JustinRuiter marked this conversation as resolved.
Show resolved Hide resolved
db-type: 'sqlite'
prefer-lowest: 'prefer-lowest'

Expand Down Expand Up @@ -61,14 +61,14 @@ jobs:
if [[ ${{ matrix.db-type }} == 'mysql' ]]; then export DB_URL='mysql://root:[email protected]/cakephp'; fi
if [[ ${{ matrix.db-type }} == 'pgsql' ]]; then export DB_URL='postgres://postgres:[email protected]/postgres'; fi

if [[ ${{ matrix.php-version }} == '7.4' && ${{ matrix.db-type }} == 'mysql' ]]; then
if [[ ${{ matrix.php-version }} == '8.3' && ${{ matrix.db-type }} == 'mysql' ]]; then
vendor/bin/phpunit --coverage-clover=coverage.xml
else
vendor/bin/phpunit
fi

- name: Code Coverage Report
if: success() && matrix.php-version == '7.4' && matrix.db-type == 'mysql'
if: success() && matrix.php-version == '8.3' && matrix.db-type == 'mysql'
uses: codecov/codecov-action@v1

cs-stan:
Expand All @@ -81,16 +81,17 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
php-version: '8.3'
extensions: mbstring, intl
coverage: none
tools: psalm:4, phpstan:1
tools: psalm:5.23.1, phpstan:1.10.65

- name: Composer Install
run: composer require cakephp/cakephp-codesniffer:^4.2

- name: Run phpcs
run: vendor/bin/phpcs --standard=CakePHP src/ tests/
# Exclude Type hint sniffing, as it interferes with psalm
run: vendor/bin/phpcs --standard=CakePHP --exclude=CakePHP.Classes.ReturnTypeHint src/ tests/
JustinRuiter marked this conversation as resolved.
Show resolved Hide resolved

- name: Run psalm
if: success() || failure()
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/plugins
/vendor
.phpunit.result.cache
/.idea
15 changes: 11 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,19 @@
"irc": "irc://irc.freenode.org/muffin"
},
"require": {
"cakephp/orm": "^4.5"
"cakephp/orm": "^5.0"
},
"require-dev": {
"cakephp/cakephp": "^4.5",
"cakephp/cakephp-codesniffer": "^4.2",
"phpunit/phpunit": "^9.3"
"cakephp/cakephp": "^5.0",
"cakephp/cakephp-codesniffer": "^5.0",
"phpunit/phpunit": "^10.1",
JustinRuiter marked this conversation as resolved.
Show resolved Hide resolved
"ext-mbstring": "*",
"vimeo/psalm": "5.23.1",
"phpstan/phpstan": "1.10.65"
},
"scripts": {
"cs-check": "phpcs --colors --parallel=16 -p src/ tests/",
"cs-fix": "phpcbf --colors --parallel=16 -p src/ tests/"
},
"autoload": {
"psr-4": {
Expand Down
18 changes: 2 additions & 16 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
parameters:
level: 6
level: 8
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
treatPhpDocTypesAsCertain: false
paths:
- src/
ignoreErrors:
-
message: "#^Call to an undefined method Cake\\\\Datasource\\\\RepositoryInterface\\:\\:callFinder\\(\\)\\.$#"
count: 1
path: src/Datasource/Query.php

-
message: "#^Call to an undefined method Cake\\\\Datasource\\\\RepositoryInterface\\:\\:getName\\(\\)\\.$#"
count: 1
path: src/Datasource/Query.php

-
message: "#^Method Muffin\\\\Webservice\\\\Datasource\\\\Query\\:\\:execute\\(\\) should return bool\\|int\\|Muffin\\\\Webservice\\\\Datasource\\\\ResultSet\\|Muffin\\\\Webservice\\\\Model\\\\Resource but returns Cake\\\\Datasource\\\\ResultSetInterface\\.$#"
count: 1
path: src/Datasource/Query.php
25 changes: 11 additions & 14 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="./tests/bootstrap.php"
colors="true"
stopOnFailure="false"
>

<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">
<testsuites>
<testsuite name="Webservice Test Cases">
<testsuite name="Slug Test Cases">
JustinRuiter marked this conversation as resolved.
Show resolved Hide resolved
<directory>./tests/</directory>
</testsuite>
</testsuites>

<extensions>
<extension class="Cake\TestSuite\Fixture\PHPUnitExtension"/>
<bootstrap class="Cake\TestSuite\Fixture\Extension\PHPUnitExtension"/>
</extensions>

<filter>
<whitelist>
<php>
<ini name="memory_limit" value="-1"/>
<env name="FIXTURE_SCHEMA_METADATA" value="./tests/schema.php"/>
</php>
<source>
<include>
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>
</include>
</source>
</phpunit>
18 changes: 7 additions & 11 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<?xml version="1.0"?>
<psalm
errorLevel="2"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedCode="false"
findUnusedBaselineEntry="true"
>
<projectFiles>
<directory name="src" />
Expand All @@ -13,16 +16,9 @@
</projectFiles>

<issueHandlers>

<PropertyNotSetInConstructor errorLevel="info" />
<MissingClosureReturnType errorLevel="info" />
<MissingClosureParamType errorLevel="info" />

<DocblockTypeContradiction errorLevel="info" />
<RedundantConditionGivenDocblockType errorLevel="info" />

<UnsafeInstantiation errorLevel="info" />

<UnresolvableInclude errorLevel="info" />
<RedundantConditionGivenDocblockType errorLevel="suppress"/>
<MissingClosureParamType errorLevel="suppress"/>
<MissingClosureReturnType errorLevel="suppress"/>
<PropertyNotSetInConstructor errorLevel="suppress"/>
</issueHandlers>
</psalm>
78 changes: 69 additions & 9 deletions src/Datasource/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,34 @@
namespace Muffin\Webservice\Datasource;

use Cake\Core\App;
use Cake\Datasource\ConnectionInterface;
use Muffin\Webservice\Datasource\Exception\MissingConnectionException;
use Muffin\Webservice\Webservice\Driver\AbstractDriver;
use Muffin\Webservice\Webservice\Exception\MissingDriverException;
use Muffin\Webservice\Webservice\Exception\UnexpectedDriverException;
use Psr\SimpleCache\CacheInterface;

/**
* Class Connection
*
* @method \Muffin\Webservice\Webservice\Driver\AbstractDriver setWebservice(string $name, \Muffin\Webservice\Webservice\WebserviceInterface $webservice) Proxy method through to the Driver
* @method \Muffin\Webservice\Webservice\WebserviceInterface getWebservice(string $name) Proxy method through to the Driver
* @method string configName() Proxy method through to the Driver
*/
class Connection
class Connection implements ConnectionInterface
{
/**
* Driver
*
* @var \Muffin\Webservice\Webservice\Driver\AbstractDriver
*/
protected $_driver;
protected AbstractDriver $_driver;

protected CacheInterface $cacher;

/**
* The connection name in the connection manager.
*/
protected string $configName = '';

/**
* Constructor
Expand All @@ -33,17 +41,68 @@
*/
public function __construct(array $config)
{
if (isset($config['name'])) {
$this->configName = $config['name'];
ADmad marked this conversation as resolved.
Show resolved Hide resolved
}
$config = $this->_normalizeConfig($config);
/** @psalm-var class-string<\Muffin\Webservice\Webservice\Driver\AbstractDriver> */
$driver = $config['driver'];
unset($config['driver'], $config['service']);

$this->_driver = new $driver($config);
$tempDriver = new $driver($config);

/** @psalm-suppress TypeDoesNotContainType */
if (!($this->_driver instanceof AbstractDriver)) {
if (!($tempDriver instanceof AbstractDriver)) {
JustinRuiter marked this conversation as resolved.
Show resolved Hide resolved
throw new UnexpectedDriverException(['driver' => $driver]);
}
$this->_driver = $tempDriver;
}

/**
* @param \Psr\SimpleCache\CacheInterface $cacher The cacher instance to use for query caching.
* @return $this
*/
public function setCacher(CacheInterface $cacher): ConnectionInterface

Check warning on line 63 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L63

Added line #L63 was not covered by tests
{
$this->cacher = $cacher;

Check warning on line 65 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L65

Added line #L65 was not covered by tests

return $this;

Check warning on line 67 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L67

Added line #L67 was not covered by tests
}

/** @return \Psr\SimpleCache\CacheInterface */
public function getCacher(): CacheInterface

Check warning on line 71 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L71

Added line #L71 was not covered by tests
{
return $this->cacher;

Check warning on line 73 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L73

Added line #L73 was not covered by tests
}

/**
* {@inheritDoc}
*
* @param string $role Parameter is not used
* @see \Cake\Datasource\ConnectionInterface::getDriver()
* @return \Muffin\Webservice\Webservice\Driver\AbstractDriver
*/
public function getDriver(string $role = self::ROLE_WRITE): AbstractDriver

Check warning on line 83 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L83

Added line #L83 was not covered by tests
{
return $this->_driver;

Check warning on line 85 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L85

Added line #L85 was not covered by tests
}

/**
* Get the configuration name for this connection.
*
* @return string
*/
public function configName(): string
{
return $this->configName;
ADmad marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Get the config data for this connection.
*
* @return array<string, mixed>
*/
public function config(): array

Check warning on line 103 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L103

Added line #L103 was not covered by tests
{
return $this->_driver->getConfig();

Check warning on line 105 in src/Datasource/Connection.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Connection.php#L105

Added line #L105 was not covered by tests
}

/**
Expand All @@ -61,7 +120,7 @@
throw new MissingConnectionException(['name' => $config['name']]);
}

$config['driver'] = App::className($config['service'], 'Webservice/Driver');
$config['driver'] = App::className($config['service'], 'Webservice/Driver', 'Driver');
JustinRuiter marked this conversation as resolved.
Show resolved Hide resolved
if (!$config['driver']) {
throw new MissingDriverException(['driver' => $config['driver']]);
}
Expand All @@ -77,8 +136,9 @@
* @param array $args Arguments to pass-through
* @return mixed
*/
public function __call($method, $args)
public function __call(string $method, array $args): mixed
{
/* @phpstan-ignore-next-line This is supported behavior for now: https://www.php.net/manual/en/function.call-user-func-array.php (example 1) */
return call_user_func_array([$this->_driver, $method], $args);
}
}
2 changes: 1 addition & 1 deletion src/Datasource/Exception/MissingConnectionException.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ class MissingConnectionException extends CakeException
*
* @var string
*/
protected $_messageTemplate = 'No `%s` connection configured.';
protected string $_messageTemplate = 'No `%s` connection configured.';
}
33 changes: 14 additions & 19 deletions src/Datasource/Marshaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*
* @var \Muffin\Webservice\Model\Endpoint
*/
protected $_endpoint;
protected Endpoint $_endpoint;

/**
* Constructor.
Expand Down Expand Up @@ -53,7 +53,6 @@
[$data, $options] = $this->_prepareDataAndOptions($data, $options);

$primaryKey = (array)$this->_endpoint->getPrimaryKey();
/** @psalm-var class-string<\Muffin\Webservice\Model\Resource> */
$resourceClass = $this->_endpoint->getResourceClass();
$entity = new $resourceClass();
$entity->setSource($this->_endpoint->getRegistryAlias());
Expand Down Expand Up @@ -110,25 +109,21 @@
if (!$options['validate']) {
return [];
}

$validator = null;
if ($options['validate'] === true) {
$validator = $this->_endpoint->getValidator('default');
JustinRuiter marked this conversation as resolved.
Show resolved Hide resolved
} elseif (is_string($options['validate'])) {
$validator = $this->_endpoint->getValidator($options['validate']);
} else {
/** @var \Cake\Validation\Validator $validator */
$validator = $options['validator'];
$options['validate'] = $this->_endpoint->getValidator('default');
}

if (!is_callable([$validator, 'errors'])) {
throw new RuntimeException(sprintf(
'"validate" must be a boolean, a string or an object with method "errors()". Got %s instead.',
gettype($options['validate'])
));
if (is_string($options['validate'])) {
$options['validate'] = $this->_endpoint->getValidator($options['validate']);

Check warning on line 117 in src/Datasource/Marshaller.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Marshaller.php#L117

Added line #L117 was not covered by tests
}
if (!is_object($options['validate'])) {
throw new RuntimeException(
sprintf('validate must be a boolean, a string or an object. Got %s.', gettype($options['validate']))

Check warning on line 121 in src/Datasource/Marshaller.php

View check run for this annotation

Codecov / codecov/patch

src/Datasource/Marshaller.php#L120-L121

Added lines #L120 - L121 were not covered by tests
);
}

return $validator->validate($data, $isNew);
/* @phpstan-ignore-next-line Magic method */
return $options['validate']->validate($data, $isNew);
}

/**
Expand Down Expand Up @@ -165,7 +160,7 @@
*
* @param array $data The data to hydrate.
* @param array $options List of options
* @return \Cake\Datasource\EntityInterface[] An array of hydrated records.
* @return array<\Cake\Datasource\EntityInterface> An array of hydrated records.
* @see \Muffin\Webservice\Model\Endpoint::newEntities()
*/
public function many(array $data, array $options = []): array
Expand Down Expand Up @@ -264,9 +259,9 @@
* data merged in
* @param array $data list of arrays to be merged into the entities
* @param array $options List of options.
* @return \Cake\Datasource\EntityInterface[]
* @return array<\Cake\Datasource\EntityInterface>
*/
public function mergeMany($entities, array $data, array $options = []): array
public function mergeMany(iterable $entities, array $data, array $options = []): array
{
$primary = (array)$this->_endpoint->getPrimaryKey();

Expand Down
Loading
Loading