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
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: CI

on:
push:
branches:
- master
- 3.next
pull_request:
branches:
- '*'

permissions:
contents: read

jobs:
testsuite:
uses: cakephp/.github/.github/workflows/testsuite-with-db.yml@5.x
secrets: inherit

cs-stan:
uses: cakephp/.github/.github/workflows/cs-stan.yml@5.x
secrets: inherit
5 changes: 5 additions & 0 deletions .phive/phars.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpstan" version="1.10.32" installed="1.10.32" location="./tools/phpstan" copy="false"/>
<phar name="psalm" version="5.15.0" installed="5.15.0" location="./tools/psalm" copy="false"/>
</phive>
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ CakePHP behavior plugin for easily generating some complicated queries like (bul
[![License](https://poser.pugx.org/itosho/easy-query/license)](https://packagist.org/packages/itosho/easy-query)

## Requirements
- PHP 7.2+
- CakePHP 4.0+
- MySQL 5.6+

:warning: For CakePHP3.x, use 1.x branch.
- PHP 8.1+
- CakePHP 5.0+
- MySQL 8.0+ / MariaDB 10.4+

## Installation
```bash
Expand Down
15 changes: 11 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
"source": "https://github.com/itosho/easy-query"
},
"require": {
"php": ">=7.2.0",
"cakephp/orm": "^4.0"
"php": ">=8.1",
"cakephp/orm": "^5.0.0"
},
"require-dev": {
"cakephp/cakephp": "^4.0",
"phpunit/phpunit": "^8.5"
"cakephp/cakephp": "^5.0.0",
"phpunit/phpunit": "^10.1.0",
"cakephp/cakephp-codesniffer": "^5.0",
"vimeo/psalm": "^5.15"
},
"autoload": {
"psr-4": {
Expand All @@ -42,5 +44,10 @@
"psr-4": {
"Itosho\\EasyQuery\\Test\\": "tests"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
5 changes: 5 additions & 0 deletions phpcs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0"?>
<ruleset name="itosho/easy-query">
<config name="installed_paths" value="../../cakephp/cakephp-codesniffer" />
<rule ref="CakePHP" />
</ruleset>
2 changes: 2 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
parameters:
ignoreErrors: []
10 changes: 8 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
includes:
- phpstan-baseline.neon

parameters:
checkMissingIterableValueType: false
ignoreErrors: []
level: 6
checkGenericClassInNonGenericObjectType: false
checkMissingIterableValueType: false
paths:
- src/
38 changes: 12 additions & 26 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,37 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
colors="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="./tests/bootstrap.php"
>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" processIsolation="false" stopOnFailure="false" bootstrap="tests/bootstrap.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" cacheDirectory=".phpunit.cache">
<coverage/>
<php>
<ini name="memory_limit" value="-1"/>
<ini name="apc.enable_cli" value="1"/>
<env name="FIXTURE_SCHEMA_METADATA" value="./tests/schema.php"/>
</php>

<!-- Add any additional test suites you want to run here -->
<testsuites>
<testsuite name="EasyQuery Test Suite">
<directory>./tests/TestCase</directory>
<directory>tests/TestCase/</directory>
</testsuite>
</testsuites>

<!-- Setup a listener for fixtures -->
<listeners>
<listener
class="\Cake\TestSuite\Fixture\FixtureInjector"
file="./vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureInjector.php">
<arguments>
<object class="\Cake\TestSuite\Fixture\FixtureManager" />
</arguments>
</listener>
</listeners>

<filter>
<whitelist>
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>

<extensions>
<bootstrap class="Cake\TestSuite\Fixture\Extension\PHPUnitExtension"/>
</extensions>
<source>
<include>
<directory suffix=".php">src/</directory>
</include>
</source>
</phpunit>
15 changes: 15 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?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"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>
52 changes: 27 additions & 25 deletions src/Model/Behavior/InsertBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,35 @@

use Cake\Database\Expression\QueryExpression;
use Cake\Database\StatementInterface;
use Cake\I18n\FrozenTime;
use Cake\Datasource\EntityInterface;
use Cake\I18n\DateTime;
use Cake\ORM\Behavior;
use Cake\ORM\Entity;
use Cake\ORM\Query;
use Cake\ORM\TableRegistry;
use Cake\ORM\Locator\LocatorAwareTrait;
use Cake\ORM\Query\SelectQuery;
use LogicException;

/**
* Insert Behavior
*/
class InsertBehavior extends Behavior
{
use LocatorAwareTrait;

/**
* Default config
*
* @var array
* @var array<string, mixed>
*/
protected $_defaultConfig = [
protected array $_defaultConfig = [
'event' => ['beforeSave' => true],
];

/**
* execute bulk insert query
*
* @param Entity[] $entities insert entities
* @throws LogicException no save data
* @return StatementInterface query result
* @param array<\Cake\Datasource\EntityInterface> $entities insert entities
* @throws \LogicException no save data
* @return \Cake\Database\StatementInterface query result
*/
public function bulkInsert(array $entities): StatementInterface
{
Expand All @@ -50,7 +52,7 @@ public function bulkInsert(array $entities): StatementInterface
$fields = array_keys($saveData[0]);

$query = $this->_table
->query()
->insertQuery()
->insert($fields);
$query->clause('values')->setValues($saveData);

Expand All @@ -60,31 +62,31 @@ public function bulkInsert(array $entities): StatementInterface
/**
* execute insert select query for saving a record just once
*
* @param Entity $entity insert entity
* @param \Cake\Datasource\EntityInterface $entity insert entity
* @param array|null $conditions search conditions
* @return StatementInterface query result
* @return \Cake\Database\StatementInterface query result
*/
public function insertOnce(Entity $entity, array $conditions = null): StatementInterface
public function insertOnce(EntityInterface $entity, ?array $conditions = null): StatementInterface
{
if ($this->_config['event']['beforeSave']) {
$this->_table->dispatchEvent('Model.beforeSave', compact('entity'));
}

$entity->setVirtual([]);
$insertData = $entity->toArray();
if (isset($insertData['created']) && !is_null($insertData['created'])) {
$insertData['created'] = FrozenTime::now()->toDateTimeString();
if (isset($insertData['created'])) {
$insertData['created'] = DateTime::now()->toDateTimeString();
}
if (isset($insertData['modified']) && !is_null($insertData['modified'])) {
$insertData['modified'] = FrozenTime::now()->toDateTimeString();
if (isset($insertData['modified'])) {
$insertData['modified'] = DateTime::now()->toDateTimeString();
}

$fields = array_keys($insertData);
$existsConditions = $conditions;
if (is_null($existsConditions)) {
$existsConditions = $this->getExistsConditions($insertData);
}
$query = $this->_table->query()->insert($fields);
$query = $this->_table->insertQuery()->insert($fields);
$subQuery = $this
->buildTmpTableSelectQuery($insertData)
->where(function (QueryExpression $exp) use ($existsConditions) {
Expand All @@ -95,7 +97,7 @@ public function insertOnce(Entity $entity, array $conditions = null): StatementI
return $exp->notExists($query);
})
->limit(1);
/* @phpstan-ignore-next-line */

$query = $query->epilog($subQuery);

return $query->execute();
Expand All @@ -105,10 +107,10 @@ public function insertOnce(Entity $entity, array $conditions = null): StatementI
* build tmp table's select query for insert select query
*
* @param array $insertData insert data
* @throws LogicException select query is invalid
* @return Query tmp table's select query
* @return \Cake\ORM\Query\SelectQuery tmp table's select query
* @throws \LogicException select query is invalid
*/
private function buildTmpTableSelectQuery($insertData): Query
private function buildTmpTableSelectQuery(array $insertData): SelectQuery
{
$driver = $this->_table
->getConnection()
Expand All @@ -118,15 +120,15 @@ private function buildTmpTableSelectQuery($insertData): Query
foreach ($insertData as $key => $value) {
$col = $driver->quoteIdentifier($key);
if (is_null($value)) {
$schema[] = "NULL AS {$col}";
$schema[] = "NULL AS $col";
} else {
$bindKey = ':' . strtolower($key);
$binds[$bindKey] = $value;
$schema[] = "{$bindKey} AS {$col}";
$schema[] = "$bindKey AS $col";
}
}

$tmpTable = TableRegistry::getTableLocator()->get('tmp', [
$tmpTable = $this->fetchTable('tmp', [
'schema' => $this->_table->getSchema(),
]);
$query = $tmpTable
Expand Down
29 changes: 13 additions & 16 deletions src/Model/Behavior/UpsertBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use Cake\Database\StatementInterface;
use Cake\Datasource\EntityInterface;
use Cake\ORM\Behavior;
use Cake\ORM\Entity;
use LogicException;

/**
Expand All @@ -17,9 +16,9 @@ class UpsertBehavior extends Behavior
/**
* Default config
*
* @var array
* @var array<string, mixed>
*/
protected $_defaultConfig = [
protected array $_defaultConfig = [
'updateColumns' => null,
'uniqueColumns' => null,
'event' => ['beforeSave' => true],
Expand All @@ -28,11 +27,11 @@ class UpsertBehavior extends Behavior
/**
* execute upsert query
*
* @param Entity $entity upsert entity
* @return EntityInterface|array|null result entity
* @throws LogicException invalid config
* @param \Cake\Datasource\EntityInterface $entity upsert entity
* @return \Cake\Datasource\EntityInterface|array|null result entity
* @throws \LogicException invalid config
*/
public function upsert(Entity $entity)
public function upsert(EntityInterface $entity): array|EntityInterface|null
{
if (!$this->isValidArrayConfig('updateColumns')) {
throw new LogicException('config updateColumns is invalid.');
Expand All @@ -52,13 +51,13 @@ public function upsert(Entity $entity)

$updateValues = [];
foreach ($updateColumns as $column) {
$updateValues[] = "`{$column}`=VALUES(`{$column}`)";
$updateValues[] = "`$column`=VALUES(`$column`)";
}
$updateStatement = implode(', ', $updateValues);
$expression = 'ON DUPLICATE KEY UPDATE ' . $updateStatement;

$this->_table
->query()
->insertQuery()
->insert($fields)
->values($upsertData)
->epilog($expression)
Expand All @@ -80,9 +79,9 @@ public function upsert(Entity $entity)
/**
* execute bulk upsert query
*
* @param Entity[] $entities upsert entities
* @return StatementInterface query result
* @throws LogicException invalid config or no save data
* @param array<\Cake\Datasource\EntityInterface> $entities upsert entities
* @return \Cake\Database\StatementInterface query result
* @throws \LogicException invalid config or no save data
*/
public function bulkUpsert(array $entities): StatementInterface
{
Expand All @@ -107,13 +106,12 @@ public function bulkUpsert(array $entities): StatementInterface
$updateColumns = $this->_config['updateColumns'];
$updateValues = [];
foreach ($updateColumns as $column) {
$updateValues[] = "`{$column}`=VALUES(`{$column}`)";
$updateValues[] = "`$column`=VALUES(`$column`)";
}
$updateStatement = implode(', ', $updateValues);
$expression = 'ON DUPLICATE KEY UPDATE ' . $updateStatement;

$query = $this->_table
->query()
->insertQuery()
->insert($fields)
->epilog($expression);
$query->clause('values')->setValues($saveData);
Expand All @@ -125,7 +123,6 @@ public function bulkUpsert(array $entities): StatementInterface
* validate config value
*
* @param string $configName config key
*
* @return bool valid or invalid
*/
private function isValidArrayConfig(string $configName): bool
Expand Down
Loading