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
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
16 changes: 12 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@
"source": "https://github.com/itosho/easy-query"
},
"require": {
"php": ">=7.2.0",
"cakephp/orm": "^4.0"
"php": ">=8.1",
"cakephp/orm": "5.x-dev"
},
"require-dev": {
"cakephp/cakephp": "^4.0",
"phpunit/phpunit": "^8.5"
"cakephp/cakephp": "5.x-dev",
"phpunit/phpunit": "^10.1.0",
"cakephp/cakephp-codesniffer": "^5.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"Itosho\\EasyQuery\\": "src"
Expand All @@ -42,5 +45,10 @@
"psr-4": {
"Itosho\\EasyQuery\\Test\\": "tests"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
42 changes: 16 additions & 26 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,37 +1,27 @@
<?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"/>
<env name="db_host" value="db"/>
<env name="db_user" value="db"/>
<env name="db_name" value="db"/>
<env name="db_pass" value="db"/>
</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>
47 changes: 24 additions & 23 deletions src/Model/Behavior/InsertBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,34 @@

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
*/
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 \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 +51,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 +61,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 @@ -105,10 +106,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 +119,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
26 changes: 12 additions & 14 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 @@ -19,7 +18,7 @@ class UpsertBehavior extends Behavior
*
* @var array
*/
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 \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 Down
13 changes: 1 addition & 12 deletions tests/Fixture/ArticlesFixture.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,7 @@

class ArticlesFixture extends TestFixture
{
public $fields = [
'id' => ['type' => 'integer'],
'title' => ['type' => 'string', 'length' => 255, 'null' => false],
'body' => 'text',
'published' => ['type' => 'integer', 'default' => '0', 'null' => false],
'created' => 'datetime',
'modified' => 'datetime',
'_constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id']],
],
];
public $records = [
public array $records = [
[
'title' => 'First Article',
'body' => 'First Article Body',
Expand Down
13 changes: 1 addition & 12 deletions tests/Fixture/TagsFixture.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,7 @@

class TagsFixture extends TestFixture
{
public $fields = [
'id' => ['type' => 'integer'],
'name' => ['type' => 'string', 'length' => 255, 'null' => false],
'description' => ['type' => 'string', 'length' => 255, 'null' => false],
'created' => 'datetime',
'modified' => 'datetime',
'_constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id']],
'unique' => ['type' => 'unique', 'columns' => ['name']],
],
];
public $records = [
public array $records = [
[
'name' => 'tag1',
'description' => 'tag1 description',
Expand Down
Loading