FILES_CI4_SYSTEM_ALL_FILES_PUSH : RV
This commit is contained in:
parent
e83f2dad9e
commit
1ea98b2b26
61
README.md
61
README.md
@ -1,4 +1,59 @@
|
|||||||
# nHance
|
# CodeIgniter 4 Framework
|
||||||
|
|
||||||
## Tech Stack
|
## What is CodeIgniter?
|
||||||
**Please** read the dev guide
|
|
||||||
|
CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure.
|
||||||
|
More information can be found at the [official site](https://codeigniter.com).
|
||||||
|
|
||||||
|
This repository holds the distributable version of the framework.
|
||||||
|
It has been built from the
|
||||||
|
[development repository](https://github.com/codeigniter4/CodeIgniter4).
|
||||||
|
|
||||||
|
More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums.
|
||||||
|
|
||||||
|
The user guide corresponding to the latest version of the framework can be found
|
||||||
|
[here](https://codeigniter4.github.io/userguide/).
|
||||||
|
|
||||||
|
## Important Change with index.php
|
||||||
|
|
||||||
|
`index.php` is no longer in the root of the project! It has been moved inside the *public* folder,
|
||||||
|
for better security and separation of components.
|
||||||
|
|
||||||
|
This means that you should configure your web server to "point" to your project's *public* folder, and
|
||||||
|
not to the project root. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the
|
||||||
|
framework are exposed.
|
||||||
|
|
||||||
|
**Please** read the user guide for a better explanation of how CI4 works!
|
||||||
|
|
||||||
|
## Repository Management
|
||||||
|
|
||||||
|
We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages.
|
||||||
|
We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss
|
||||||
|
FEATURE REQUESTS.
|
||||||
|
|
||||||
|
This repository is a "distribution" one, built by our release preparation script.
|
||||||
|
Problems with it can be raised on our forum, or as issues in the main repository.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We welcome contributions from the community.
|
||||||
|
|
||||||
|
Please read the [*Contributing to CodeIgniter*](https://github.com/codeigniter4/CodeIgniter4/blob/develop/CONTRIBUTING.md) section in the development repository.
|
||||||
|
|
||||||
|
## Server Requirements
|
||||||
|
|
||||||
|
PHP version 7.4 or higher is required, with the following extensions installed:
|
||||||
|
|
||||||
|
- [intl](http://php.net/manual/en/intl.requirements.php)
|
||||||
|
- [mbstring](http://php.net/manual/en/mbstring.installation.php)
|
||||||
|
|
||||||
|
> **Warning**
|
||||||
|
> The end of life date for PHP 7.4 was November 28, 2022. If you are
|
||||||
|
> still using PHP 7.4, you should upgrade immediately. The end of life date
|
||||||
|
> for PHP 8.0 will be November 26, 2023.
|
||||||
|
|
||||||
|
Additionally, make sure that the following extensions are enabled in your PHP:
|
||||||
|
|
||||||
|
- json (enabled by default - don't turn it off)
|
||||||
|
- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL
|
||||||
|
- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class App extends BaseConfig
|
|||||||
*
|
*
|
||||||
* http://example.com/
|
* http://example.com/
|
||||||
*/
|
*/
|
||||||
public string $baseURL = 'http://localhost:8080/';
|
public string $baseURL = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allowed Hostnames in the Site URL other than the hostname in the baseURL.
|
* Allowed Hostnames in the Site URL other than the hostname in the baseURL.
|
||||||
@ -27,8 +27,7 @@ class App extends BaseConfig
|
|||||||
* 'http://accounts.example.com/':
|
* 'http://accounts.example.com/':
|
||||||
* ['media.example.com', 'accounts.example.com']
|
* ['media.example.com', 'accounts.example.com']
|
||||||
*
|
*
|
||||||
* @var string[]
|
* @var list<string>
|
||||||
* @phpstan-var list<string>
|
|
||||||
*/
|
*/
|
||||||
public array $allowedHostnames = [];
|
public array $allowedHostnames = [];
|
||||||
|
|
||||||
@ -41,7 +40,7 @@ class App extends BaseConfig
|
|||||||
* something else. If you are using mod_rewrite to remove the page set this
|
* something else. If you are using mod_rewrite to remove the page set this
|
||||||
* variable so that it is blank.
|
* variable so that it is blank.
|
||||||
*/
|
*/
|
||||||
public string $indexPage = '';
|
public string $indexPage = 'index.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|||||||
0
app/Config/Autoload.php
Normal file → Executable file
0
app/Config/Autoload.php
Normal file → Executable file
@ -10,7 +10,7 @@
|
|||||||
|
|
|
|
||||||
| If you set 'display_errors' to '1', CI4's detailed error report will show.
|
| If you set 'display_errors' to '1', CI4's detailed error report will show.
|
||||||
*/
|
*/
|
||||||
error_reporting(-1);
|
error_reporting(E_ALL);
|
||||||
ini_set('display_errors', '1');
|
ini_set('display_errors', '1');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
| make sure they don't make it to production. And save us hours of
|
| make sure they don't make it to production. And save us hours of
|
||||||
| painful debugging.
|
| painful debugging.
|
||||||
*/
|
*/
|
||||||
error_reporting(-1);
|
error_reporting(E_ALL);
|
||||||
ini_set('display_errors', '1');
|
ini_set('display_errors', '1');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -158,8 +158,7 @@ class Cache extends BaseConfig
|
|||||||
* This is an array of cache engine alias' and class names. Only engines
|
* This is an array of cache engine alias' and class names. Only engines
|
||||||
* that are listed here are allowed to be used.
|
* that are listed here are allowed to be used.
|
||||||
*
|
*
|
||||||
* @var array<string, string>
|
* @var array<string, class-string<CacheInterface>>
|
||||||
* @phpstan-var array<string, class-string<CacheInterface>>
|
|
||||||
*/
|
*/
|
||||||
public array $validHandlers = [
|
public array $validHandlers = [
|
||||||
'dummy' => DummyHandler::class,
|
'dummy' => DummyHandler::class,
|
||||||
|
|||||||
0
app/Config/DocTypes.php
Normal file → Executable file
0
app/Config/DocTypes.php
Normal file → Executable file
@ -26,7 +26,7 @@ class Email extends BaseConfig
|
|||||||
public string $mailPath = '/usr/sbin/sendmail';
|
public string $mailPath = '/usr/sbin/sendmail';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SMTP Server Address
|
* SMTP Server Hostname
|
||||||
*/
|
*/
|
||||||
public string $SMTPHost = '';
|
public string $SMTPHost = '';
|
||||||
|
|
||||||
|
|||||||
@ -27,8 +27,7 @@ class Kint extends BaseConfig
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<int, ConstructablePluginInterface|string>
|
* @var list<class-string<ConstructablePluginInterface>|ConstructablePluginInterface>|null
|
||||||
* @phpstan-var list<class-string<ConstructablePluginInterface>|ConstructablePluginInterface>
|
|
||||||
*/
|
*/
|
||||||
public $plugins;
|
public $plugins;
|
||||||
|
|
||||||
@ -46,14 +45,12 @@ class Kint extends BaseConfig
|
|||||||
public int $richSort = AbstractRenderer::SORT_FULL;
|
public int $richSort = AbstractRenderer::SORT_FULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<string, string>
|
* @var array<string, class-string<ValuePluginInterface>>|null
|
||||||
* @phpstan-var array<string, class-string<ValuePluginInterface>>
|
|
||||||
*/
|
*/
|
||||||
public $richObjectPlugins;
|
public $richObjectPlugins;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<string, string>
|
* @var array<string, class-string<TabPluginInterface>>|null
|
||||||
* @phpstan-var array<string, class-string<TabPluginInterface>>
|
|
||||||
*/
|
*/
|
||||||
public $richTabPlugins;
|
public $richTabPlugins;
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,7 @@ class Modules extends BaseModules
|
|||||||
* ],
|
* ],
|
||||||
* ]
|
* ]
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array{only?: list<string>, exclude?: list<string>}
|
||||||
*/
|
*/
|
||||||
public $composerPackages = [];
|
public $composerPackages = [];
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ class Modules extends BaseModules
|
|||||||
*
|
*
|
||||||
* If it is not listed, only the base application elements will be used.
|
* If it is not listed, only the base application elements will be used.
|
||||||
*
|
*
|
||||||
* @var string[]
|
* @var list<string>
|
||||||
*/
|
*/
|
||||||
public $aliases = [
|
public $aliases = [
|
||||||
'events',
|
'events',
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class Publisher extends BasePublisher
|
|||||||
* result in a PublisherException. Files that do no fit the
|
* result in a PublisherException. Files that do no fit the
|
||||||
* pattern will cause copy/merge to fail.
|
* pattern will cause copy/merge to fail.
|
||||||
*
|
*
|
||||||
* @var array<string,string>
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
public $restrictions = [
|
public $restrictions = [
|
||||||
ROOTPATH => '*',
|
ROOTPATH => '*',
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class Session extends BaseConfig
|
|||||||
* - `CodeIgniter\Session\Handlers\MemcachedHandler`
|
* - `CodeIgniter\Session\Handlers\MemcachedHandler`
|
||||||
* - `CodeIgniter\Session\Handlers\RedisHandler`
|
* - `CodeIgniter\Session\Handlers\RedisHandler`
|
||||||
*
|
*
|
||||||
* @phpstan-var class-string<BaseHandler>
|
* @var class-string<BaseHandler>
|
||||||
*/
|
*/
|
||||||
public string $driver = FileHandler::class;
|
public string $driver = FileHandler::class;
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ class Home extends PublicController
|
|||||||
{
|
{
|
||||||
echo base_url();
|
echo base_url();
|
||||||
//echo ($_SERVER['SERVER_PORT'] == 443 ? 'https' : 'http') . "://{$_SERVER['SERVER_NAME']}".str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']);
|
//echo ($_SERVER['SERVER_PORT'] == 443 ? 'https' : 'http') . "://{$_SERVER['SERVER_NAME']}".str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']);
|
||||||
|
return view('welcome_message');
|
||||||
return view('test');
|
return view('test');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,8 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
public function login()
|
public function login()
|
||||||
{
|
{
|
||||||
$this->session->set('isLoggedIn',true);
|
// $this->session->set('isLoggedIn',true);
|
||||||
$this->session->set('userid','10');
|
// $this->session->set('userid','10');
|
||||||
return view('login');
|
return view('login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class UserController extends AdminController
|
|||||||
// Get the ID of the inserted record
|
// Get the ID of the inserted record
|
||||||
$insertedId = $userModel->insertID();
|
$insertedId = $userModel->insertID();
|
||||||
|
|
||||||
return view('userlist');
|
redirect('user/list');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,9 +87,9 @@ class UserController extends AdminController
|
|||||||
|
|
||||||
// Fetch all users from the 'users' table
|
// Fetch all users from the 'users' table
|
||||||
$users = $userModel
|
$users = $userModel
|
||||||
->join('users as updater', 'updater.id = users.updated_by', 'left')
|
->join('users3 as updater', 'updater.id = users3.updated_by', 'left')
|
||||||
->join('users as creator', 'creator.id = users.created_by', 'left')
|
->join('users3 as creator', 'creator.id = users3.created_by', 'left')
|
||||||
->select('users.*, updater.username as updated_by_name,creator.username as created_by_name'); // Assuming
|
->select('users3.*, updater.username as updated_by_name,creator.username as created_by_name'); // Assuming
|
||||||
if(!empty($userid) && is_numeric($userid))
|
if(!empty($userid) && is_numeric($userid))
|
||||||
{
|
{
|
||||||
$result = $users->find($userid);
|
$result = $users->find($userid);
|
||||||
|
|||||||
@ -11,7 +11,7 @@ class AuthMVC implements FilterInterface
|
|||||||
{
|
{
|
||||||
if (!check_session()) {
|
if (!check_session()) {
|
||||||
|
|
||||||
return redirect()->to(site_url('login'));
|
return redirect()->to(base_url('login'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use CodeIgniter\Model;
|
|||||||
class User extends Model
|
class User extends Model
|
||||||
{
|
{
|
||||||
protected $DBGroup = 'default';
|
protected $DBGroup = 'default';
|
||||||
protected $table = 'users';
|
protected $table = 'users3';
|
||||||
protected $primaryKey = 'id';
|
protected $primaryKey = 'id';
|
||||||
protected $useAutoIncrement = true;
|
protected $useAutoIncrement = true;
|
||||||
protected $insertID = 0;
|
protected $insertID = 0;
|
||||||
|
|||||||
@ -106,28 +106,28 @@ span.psw {
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<h1 class="mt-4">New/Edit User</h1>
|
<h1 class="mt-4">New/Edit User</h1>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<form action=<?php echo base_url()."user/edit" ?> method="post">
|
<form action=<?php echo base_url()."user/create" ?> method="post">
|
||||||
<label for="username">Username:</label>
|
<label for="username">Username:</label>
|
||||||
<input type="text" id="id" name="id" value= <?=$user['id']?> >
|
<input type="text" id="id" name="id" value= >
|
||||||
<input type="text" id="username" name="username" value= <?=$user['username']?> required><br>
|
<input type="text" id="username" name="username" value= required><br>
|
||||||
|
|
||||||
<label for="firstname">First Name:</label>
|
<label for="firstname">First Name:</label>
|
||||||
<input type="text" id="firstname" name="firstname" value= <?=$user['firstname']?> required><br>
|
<input type="text" id="firstname" name="firstname" value= required><br>
|
||||||
|
|
||||||
<label for="lastname">Last Name:</label>
|
<label for="lastname">Last Name:</label>
|
||||||
<input type="text" id="lastname" name="lastname" value= <?=$user['lastname']?> required><br>
|
<input type="text" id="lastname" name="lastname" value= required><br>
|
||||||
|
|
||||||
<label for="email">Email:</label>
|
<label for="email">Email:</label>
|
||||||
<input type="email" id="email" name="email" value= <?=$user['email']?> required><br>
|
<input type="email" id="email" name="email" value= required><br>
|
||||||
|
|
||||||
<label for="mobile_no">Mobile Number:</label>
|
<label for="mobile_no">Mobile Number:</label>
|
||||||
<input type="text" id="mobile_no" name="mobile_no" value= <?=$user['mobile_no']?>><br>
|
<input type="text" id="mobile_no" name="mobile_no" value= ><br>
|
||||||
|
|
||||||
<label for="password">Password:</label>
|
<label for="password">Password:</label>
|
||||||
<input type="password" id="password" name="password" value="" required><br>
|
<input type="password" id="password" name="password" value="" required><br>
|
||||||
|
|
||||||
<label for="is_active">Active:</label>
|
<label for="is_active">Active:</label>
|
||||||
<input type="checkbox" id="is_active" name="is_active" checked= <?=$user['is_active']?> ><br>
|
<input type="checkbox" id="is_active" name="is_active" checked= ><br>
|
||||||
|
|
||||||
<button type="submit" value="Submit">submit</button>
|
<button type="submit" value="Submit">submit</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -18,9 +18,9 @@
|
|||||||
"psr/log": "^1.1"
|
"psr/log": "^1.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"codeigniter/coding-standard": "^1.5",
|
"codeigniter/coding-standard": "^1.7",
|
||||||
"fakerphp/faker": "^1.9",
|
"fakerphp/faker": "^1.9",
|
||||||
"friendsofphp/php-cs-fixer": "3.13.0",
|
"friendsofphp/php-cs-fixer": "^3.47.1",
|
||||||
"kint-php/kint": "^5.0.4",
|
"kint-php/kint": "^5.0.4",
|
||||||
"mikey179/vfsstream": "^1.6",
|
"mikey179/vfsstream": "^1.6",
|
||||||
"nexusphp/cs-config": "^3.6",
|
"nexusphp/cs-config": "^3.6",
|
||||||
@ -43,6 +43,7 @@
|
|||||||
"ext-readline": "Improves CLI::input() usability",
|
"ext-readline": "Improves CLI::input() usability",
|
||||||
"ext-redis": "If you use Cache class RedisHandler",
|
"ext-redis": "If you use Cache class RedisHandler",
|
||||||
"ext-simplexml": "If you format XML",
|
"ext-simplexml": "If you format XML",
|
||||||
|
"ext-sodium": "If you use Encryption SodiumHandler",
|
||||||
"ext-sqlite3": "If you use SQLite3",
|
"ext-sqlite3": "If you use SQLite3",
|
||||||
"ext-sqlsrv": "If you use SQL Server",
|
"ext-sqlsrv": "If you use SQL Server",
|
||||||
"ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()"
|
"ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()"
|
||||||
|
|||||||
@ -14,6 +14,9 @@ if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
|||||||
|
|
||||||
// Path to the front controller (this file)
|
// Path to the front controller (this file)
|
||||||
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR);
|
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR);
|
||||||
|
// echo FCPATH;
|
||||||
|
// echo getcwd();
|
||||||
|
// die();
|
||||||
|
|
||||||
// Ensure the current directory is pointing to the front controller's directory
|
// Ensure the current directory is pointing to the front controller's directory
|
||||||
if (getcwd() . DIRECTORY_SEPARATOR !== FCPATH) {
|
if (getcwd() . DIRECTORY_SEPARATOR !== FCPATH) {
|
||||||
@ -35,6 +38,7 @@ require FCPATH . '../app/Config/Paths.php';
|
|||||||
// ^^^ Change this line if you move your application folder
|
// ^^^ Change this line if you move your application folder
|
||||||
|
|
||||||
$paths = new Config\Paths();
|
$paths = new Config\Paths();
|
||||||
|
// print_r($paths);
|
||||||
|
|
||||||
// Location of the framework bootstrap file.
|
// Location of the framework bootstrap file.
|
||||||
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php';
|
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php';
|
||||||
@ -43,12 +47,11 @@ require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstra
|
|||||||
require_once SYSTEMPATH . 'Config/DotEnv.php';
|
require_once SYSTEMPATH . 'Config/DotEnv.php';
|
||||||
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
|
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
|
||||||
|
|
||||||
|
|
||||||
// Define ENVIRONMENT
|
// Define ENVIRONMENT
|
||||||
if (! defined('ENVIRONMENT')) {
|
if (! defined('ENVIRONMENT')) {
|
||||||
define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production'));
|
define('ENVIRONMENT', env('CI_ENVIRONMENT', 'development'));
|
||||||
}
|
}
|
||||||
// init_set('display_errors', 1);
|
error_reporting(E_ALL ^ E_NOTICE);
|
||||||
// Load Config Cache
|
// Load Config Cache
|
||||||
// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();
|
// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();
|
||||||
// $factoriesCache->load('config');
|
// $factoriesCache->load('config');
|
||||||
@ -63,7 +66,7 @@ if (! defined('ENVIRONMENT')) {
|
|||||||
* the application run, and does all the dirty work to get
|
* the application run, and does all the dirty work to get
|
||||||
* the pieces all working together.
|
* the pieces all working together.
|
||||||
*/
|
*/
|
||||||
|
// echo ENVIRONMENT;
|
||||||
$app = Config\Services::codeigniter();
|
$app = Config\Services::codeigniter();
|
||||||
$app->initialize();
|
$app->initialize();
|
||||||
$context = is_cli() ? 'php-cli' : 'web';
|
$context = is_cli() ? 'php-cli' : 'web';
|
||||||
@ -76,7 +79,7 @@ $app->setContext($context);
|
|||||||
* Now that everything is set up, it's time to actually fire
|
* Now that everything is set up, it's time to actually fire
|
||||||
* up the engines and make this app do its thang.
|
* up the engines and make this app do its thang.
|
||||||
*/
|
*/
|
||||||
|
//echo 'run';die('sample');
|
||||||
$app->run();
|
$app->run();
|
||||||
|
|
||||||
// Save Config Cache
|
// Save Config Cache
|
||||||
|
|||||||
2
spark
Normal file → Executable file
2
spark
Normal file → Executable file
@ -39,7 +39,7 @@ if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We want errors to be shown when using it from the CLI.
|
// We want errors to be shown when using it from the CLI.
|
||||||
error_reporting(-1);
|
error_reporting(E_ALL);
|
||||||
ini_set('display_errors', '1');
|
ini_set('display_errors', '1');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -94,7 +94,7 @@ trait ResponseTrait
|
|||||||
$output = null;
|
$output = null;
|
||||||
$this->format($data);
|
$this->format($data);
|
||||||
} else {
|
} else {
|
||||||
$status = empty($status) ? 200 : $status;
|
$status ??= 200;
|
||||||
$output = $this->format($data);
|
$output = $this->format($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +318,7 @@ trait ResponseTrait
|
|||||||
|
|
||||||
// Determine correct response type through content negotiation if not explicitly declared
|
// Determine correct response type through content negotiation if not explicitly declared
|
||||||
if (
|
if (
|
||||||
(empty($this->format) || ! in_array($this->format, ['json', 'xml'], true))
|
! in_array($this->format, ['json', 'xml'], true)
|
||||||
&& $this->request instanceof IncomingRequest
|
&& $this->request instanceof IncomingRequest
|
||||||
) {
|
) {
|
||||||
$mime = $this->request->negotiate(
|
$mime = $this->request->negotiate(
|
||||||
|
|||||||
@ -75,8 +75,7 @@ class Autoloader
|
|||||||
/**
|
/**
|
||||||
* Stores files as a list.
|
* Stores files as a list.
|
||||||
*
|
*
|
||||||
* @var string[]
|
* @var list<string>
|
||||||
* @phpstan-var list<string>
|
|
||||||
*/
|
*/
|
||||||
protected $files = [];
|
protected $files = [];
|
||||||
|
|
||||||
@ -84,8 +83,7 @@ class Autoloader
|
|||||||
* Stores helper list.
|
* Stores helper list.
|
||||||
* Always load the URL helper, it should be used in most apps.
|
* Always load the URL helper, it should be used in most apps.
|
||||||
*
|
*
|
||||||
* @var string[]
|
* @var list<string>
|
||||||
* @phpstan-var list<string>
|
|
||||||
*/
|
*/
|
||||||
protected $helpers = ['url'];
|
protected $helpers = ['url'];
|
||||||
|
|
||||||
@ -119,7 +117,7 @@ class Autoloader
|
|||||||
$this->files = $config->files;
|
$this->files = $config->files;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($config->helpers)) { // @phpstan-ignore-line
|
if (isset($config->helpers)) {
|
||||||
$this->helpers = [...$this->helpers, ...$config->helpers];
|
$this->helpers = [...$this->helpers, ...$config->helpers];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,8 +183,7 @@ class Autoloader
|
|||||||
/**
|
/**
|
||||||
* Registers namespaces with the autoloader.
|
* Registers namespaces with the autoloader.
|
||||||
*
|
*
|
||||||
* @param array<string, array<int, string>|string>|string $namespace
|
* @param array<string, list<string>|string>|string $namespace
|
||||||
* @phpstan-param array<string, list<string>|string>|string $namespace
|
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -35,14 +35,14 @@ class FileLocator
|
|||||||
* Attempts to locate a file by examining the name for a namespace
|
* Attempts to locate a file by examining the name for a namespace
|
||||||
* and looking through the PSR-4 namespaced files that we know about.
|
* and looking through the PSR-4 namespaced files that we know about.
|
||||||
*
|
*
|
||||||
* @param string $file The relative file path or namespaced file to
|
* @param string $file The relative file path or namespaced file to
|
||||||
* locate. If not namespaced, search in the app
|
* locate. If not namespaced, search in the app
|
||||||
* folder.
|
* folder.
|
||||||
* @param string|null $folder The folder within the namespace that we should
|
* @param non-empty-string|null $folder The folder within the namespace that we should
|
||||||
* look for the file. If $file does not contain
|
* look for the file. If $file does not contain
|
||||||
* this value, it will be appended to the namespace
|
* this value, it will be appended to the namespace
|
||||||
* folder.
|
* folder.
|
||||||
* @param string $ext The file extension the file should have.
|
* @param string $ext The file extension the file should have.
|
||||||
*
|
*
|
||||||
* @return false|string The path to the file, or false if not found.
|
* @return false|string The path to the file, or false if not found.
|
||||||
*/
|
*/
|
||||||
@ -51,7 +51,7 @@ class FileLocator
|
|||||||
$file = $this->ensureExt($file, $ext);
|
$file = $this->ensureExt($file, $ext);
|
||||||
|
|
||||||
// Clears the folder name if it is at the beginning of the filename
|
// Clears the folder name if it is at the beginning of the filename
|
||||||
if (! empty($folder) && strpos($file, $folder) === 0) {
|
if ($folder !== null && strpos($file, $folder) === 0) {
|
||||||
$file = substr($file, strlen($folder . '/'));
|
$file = substr($file, strlen($folder . '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class FileLocator
|
|||||||
$segments = explode('\\', $file);
|
$segments = explode('\\', $file);
|
||||||
|
|
||||||
// The first segment will be empty if a slash started the filename.
|
// The first segment will be empty if a slash started the filename.
|
||||||
if (empty($segments[0])) {
|
if ($segments[0] === '') {
|
||||||
unset($segments[0]);
|
unset($segments[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ class FileLocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if no namespaces matched then quit
|
// if no namespaces matched then quit
|
||||||
if (empty($paths)) {
|
if ($paths === []) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ class FileLocator
|
|||||||
// If we have a folder name, then the calling function
|
// If we have a folder name, then the calling function
|
||||||
// expects this file to be within that folder, like 'Views',
|
// expects this file to be within that folder, like 'Views',
|
||||||
// or 'libraries'.
|
// or 'libraries'.
|
||||||
if (! empty($folder) && strpos($path . $filename, '/' . $folder . '/') === false) {
|
if ($folder !== null && strpos($path . $filename, '/' . $folder . '/') === false) {
|
||||||
$path .= trim($folder, '/') . '/';
|
$path .= trim($folder, '/') . '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +119,10 @@ class FileLocator
|
|||||||
*/
|
*/
|
||||||
public function getClassname(string $file): string
|
public function getClassname(string $file): string
|
||||||
{
|
{
|
||||||
|
if (is_dir($file)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
$php = file_get_contents($file);
|
$php = file_get_contents($file);
|
||||||
$tokens = token_get_all($php);
|
$tokens = token_get_all($php);
|
||||||
$dlm = false;
|
$dlm = false;
|
||||||
@ -150,7 +154,7 @@ class FileLocator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($className)) {
|
if ($className === '') {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +196,7 @@ class FileLocator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $prioritizeApp && ! empty($appPaths)) {
|
if (! $prioritizeApp && $appPaths !== []) {
|
||||||
$foundPaths = [...$foundPaths, ...$appPaths];
|
$foundPaths = [...$foundPaths, ...$appPaths];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +272,7 @@ class FileLocator
|
|||||||
foreach ($this->getNamespaces() as $namespace) {
|
foreach ($this->getNamespaces() as $namespace) {
|
||||||
$namespace['path'] = realpath($namespace['path']) ?: $namespace['path'];
|
$namespace['path'] = realpath($namespace['path']) ?: $namespace['path'];
|
||||||
|
|
||||||
if (empty($namespace['path'])) {
|
if ($namespace['path'] === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +305,7 @@ class FileLocator
|
|||||||
*/
|
*/
|
||||||
public function listFiles(string $path): array
|
public function listFiles(string $path): array
|
||||||
{
|
{
|
||||||
if (empty($path)) {
|
if ($path === '') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +322,7 @@ class FileLocator
|
|||||||
|
|
||||||
$tempFiles = get_filenames($fullPath, true, false, false);
|
$tempFiles = get_filenames($fullPath, true, false, false);
|
||||||
|
|
||||||
if (! empty($tempFiles)) {
|
if ($tempFiles !== []) {
|
||||||
$files = array_merge($files, $tempFiles);
|
$files = array_merge($files, $tempFiles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -334,7 +338,7 @@ class FileLocator
|
|||||||
*/
|
*/
|
||||||
public function listNamespaceFiles(string $prefix, string $path): array
|
public function listNamespaceFiles(string $prefix, string $path): array
|
||||||
{
|
{
|
||||||
if (empty($path) || empty($prefix)) {
|
if ($path === '' || ($prefix === '')) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,7 +356,7 @@ class FileLocator
|
|||||||
|
|
||||||
$tempFiles = get_filenames($fullPath, true, false, false);
|
$tempFiles = get_filenames($fullPath, true, false, false);
|
||||||
|
|
||||||
if (! empty($tempFiles)) {
|
if ($tempFiles !== []) {
|
||||||
$files = array_merge($files, $tempFiles);
|
$files = array_merge($files, $tempFiles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,11 +368,13 @@ class FileLocator
|
|||||||
* Checks the app folder to see if the file can be found.
|
* Checks the app folder to see if the file can be found.
|
||||||
* Only for use with filenames that DO NOT include namespacing.
|
* Only for use with filenames that DO NOT include namespacing.
|
||||||
*
|
*
|
||||||
|
* @param non-empty-string|null $folder
|
||||||
|
*
|
||||||
* @return false|string The path to the file, or false if not found.
|
* @return false|string The path to the file, or false if not found.
|
||||||
*/
|
*/
|
||||||
protected function legacyLocate(string $file, ?string $folder = null)
|
protected function legacyLocate(string $file, ?string $folder = null)
|
||||||
{
|
{
|
||||||
$path = APPPATH . (empty($folder) ? $file : $folder . '/' . $file);
|
$path = APPPATH . ($folder === null ? $file : $folder . '/' . $file);
|
||||||
$path = realpath($path) ?: $path;
|
$path = realpath($path) ?: $path;
|
||||||
|
|
||||||
if (is_file($path)) {
|
if (is_file($path)) {
|
||||||
|
|||||||
@ -41,6 +41,16 @@ use stdClass;
|
|||||||
* - ensure validation is run against objects when saving items
|
* - ensure validation is run against objects when saving items
|
||||||
* - process various callbacks
|
* - process various callbacks
|
||||||
* - allow intermingling calls to the db connection
|
* - allow intermingling calls to the db connection
|
||||||
|
*
|
||||||
|
* @phpstan-type row_array array<int|string, float|int|null|string>
|
||||||
|
* @phpstan-type event_data_beforeinsert array{data: row_array}
|
||||||
|
* @phpstan-type event_data_afterinsert array{id: int|string, data: row_array, result: bool}
|
||||||
|
* @phpstan-type event_data_beforefind array{id?: int|string, method: string, singleton: bool, limit?: int, offset?: int}
|
||||||
|
* @phpstan-type event_data_afterfind array{id: int|string|null|list<int|string>, data: row_array|list<row_array>|object|null, method: string, singleton: bool}
|
||||||
|
* @phpstan-type event_data_beforeupdate array{id: null|list<int|string>, data: row_array}
|
||||||
|
* @phpstan-type event_data_afterupdate array{id: null|list<int|string>, data: row_array|object, result: bool}
|
||||||
|
* @phpstan-type event_data_beforedelete array{id: null|list<int|string>, purge: bool}
|
||||||
|
* @phpstan-type event_data_afterdelete array{id: null|list<int|string>, data: null, purge: bool, result: bool}
|
||||||
*/
|
*/
|
||||||
abstract class BaseModel
|
abstract class BaseModel
|
||||||
{
|
{
|
||||||
@ -63,8 +73,7 @@ abstract class BaseModel
|
|||||||
* The Database connection group that
|
* The Database connection group that
|
||||||
* should be instantiated.
|
* should be instantiated.
|
||||||
*
|
*
|
||||||
* @var string|null
|
* @var non-empty-string|null
|
||||||
* @phpstan-var non-empty-string|null
|
|
||||||
*/
|
*/
|
||||||
protected $DBGroup;
|
protected $DBGroup;
|
||||||
|
|
||||||
@ -391,11 +400,12 @@ abstract class BaseModel
|
|||||||
* Inserts data into the current database.
|
* Inserts data into the current database.
|
||||||
* This method works only with dbCalls.
|
* This method works only with dbCalls.
|
||||||
*
|
*
|
||||||
* @param array $data Data
|
* @param array $row Row data
|
||||||
|
* @phpstan-param row_array $row
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
abstract protected function doInsert(array $data);
|
abstract protected function doInsert(array $row);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles batch insert and runs the queries, validating each row prior.
|
* Compiles batch insert and runs the queries, validating each row prior.
|
||||||
@ -414,10 +424,11 @@ abstract class BaseModel
|
|||||||
* Updates a single record in the database.
|
* Updates a single record in the database.
|
||||||
* This method works only with dbCalls.
|
* This method works only with dbCalls.
|
||||||
*
|
*
|
||||||
* @param array|int|string|null $id ID
|
* @param array|int|string|null $id ID
|
||||||
* @param array|null $data Data
|
* @param array|null $row Row data
|
||||||
|
* @phpstan-param row_array|null $row
|
||||||
*/
|
*/
|
||||||
abstract protected function doUpdate($id = null, $data = null): bool;
|
abstract protected function doUpdate($id = null, $row = null): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles an update and runs the query.
|
* Compiles an update and runs the query.
|
||||||
@ -469,12 +480,13 @@ abstract class BaseModel
|
|||||||
* Compiles a replace and runs the query.
|
* Compiles a replace and runs the query.
|
||||||
* This method works only with dbCalls.
|
* This method works only with dbCalls.
|
||||||
*
|
*
|
||||||
* @param array|null $data Data
|
* @param array|null $row Row data
|
||||||
* @param bool $returnSQL Set to true to return Query String
|
* @phpstan-param row_array|null $row
|
||||||
|
* @param bool $returnSQL Set to true to return Query String
|
||||||
*
|
*
|
||||||
* @return BaseResult|false|Query|string
|
* @return BaseResult|false|Query|string
|
||||||
*/
|
*/
|
||||||
abstract protected function doReplace(?array $data = null, bool $returnSQL = false);
|
abstract protected function doReplace(?array $row = null, bool $returnSQL = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grabs the last error(s) that occurred from the Database connection.
|
* Grabs the last error(s) that occurred from the Database connection.
|
||||||
@ -499,15 +511,16 @@ abstract class BaseModel
|
|||||||
* Public getter to return the id value using the idValue() method.
|
* Public getter to return the id value using the idValue() method.
|
||||||
* For example with SQL this will return $data->$this->primaryKey.
|
* For example with SQL this will return $data->$this->primaryKey.
|
||||||
*
|
*
|
||||||
* @param array|object $data
|
* @param array|object $row Row data
|
||||||
|
* @phpstan-param row_array|object $row
|
||||||
*
|
*
|
||||||
* @return array|int|string|null
|
* @return array|int|string|null
|
||||||
*
|
*
|
||||||
* @todo: Make abstract in version 5.0
|
* @todo: Make abstract in version 5.0
|
||||||
*/
|
*/
|
||||||
public function getIdValue($data)
|
public function getIdValue($row)
|
||||||
{
|
{
|
||||||
return $this->idValue($data);
|
return $this->idValue($row);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -540,6 +553,7 @@ abstract class BaseModel
|
|||||||
* @param array|int|string|null $id One primary key or an array of primary keys
|
* @param array|int|string|null $id One primary key or an array of primary keys
|
||||||
*
|
*
|
||||||
* @return array|object|null The resulting row of data, or null.
|
* @return array|object|null The resulting row of data, or null.
|
||||||
|
* @phpstan-return ($id is int|string ? row_array|object|null : list<row_array|object>)
|
||||||
*/
|
*/
|
||||||
public function find($id = null)
|
public function find($id = null)
|
||||||
{
|
{
|
||||||
@ -553,7 +567,7 @@ abstract class BaseModel
|
|||||||
'singleton' => $singleton,
|
'singleton' => $singleton,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! empty($eventData['returnData'])) {
|
if (isset($eventData['returnData']) && $eventData['returnData'] === true) {
|
||||||
return $eventData['data'];
|
return $eventData['data'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -615,7 +629,7 @@ abstract class BaseModel
|
|||||||
'singleton' => false,
|
'singleton' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! empty($eventData['returnData'])) {
|
if (isset($eventData['returnData']) && $eventData['returnData'] === true) {
|
||||||
return $eventData['data'];
|
return $eventData['data'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -653,7 +667,7 @@ abstract class BaseModel
|
|||||||
'singleton' => true,
|
'singleton' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! empty($eventData['returnData'])) {
|
if (isset($eventData['returnData']) && $eventData['returnData'] === true) {
|
||||||
return $eventData['data'];
|
return $eventData['data'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,20 +696,21 @@ abstract class BaseModel
|
|||||||
* you must ensure that the class will provide access to the class
|
* you must ensure that the class will provide access to the class
|
||||||
* variables, even if through a magic method.
|
* variables, even if through a magic method.
|
||||||
*
|
*
|
||||||
* @param array|object $data Data
|
* @param array|object $row Row data
|
||||||
|
* @phpstan-param row_array|object $row
|
||||||
*
|
*
|
||||||
* @throws ReflectionException
|
* @throws ReflectionException
|
||||||
*/
|
*/
|
||||||
public function save($data): bool
|
public function save($row): bool
|
||||||
{
|
{
|
||||||
if (empty($data)) {
|
if ((array) $row === []) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->shouldUpdate($data)) {
|
if ($this->shouldUpdate($row)) {
|
||||||
$response = $this->update($this->getIdValue($data), $data);
|
$response = $this->update($this->getIdValue($row), $row);
|
||||||
} else {
|
} else {
|
||||||
$response = $this->insert($data, false);
|
$response = $this->insert($row, false);
|
||||||
|
|
||||||
if ($response !== false) {
|
if ($response !== false) {
|
||||||
$response = true;
|
$response = true;
|
||||||
@ -709,11 +724,14 @@ abstract class BaseModel
|
|||||||
* This method is called on save to determine if entry have to be updated.
|
* This method is called on save to determine if entry have to be updated.
|
||||||
* If this method returns false insert operation will be executed
|
* If this method returns false insert operation will be executed
|
||||||
*
|
*
|
||||||
* @param array|object $data Data
|
* @param array|object $row Row data
|
||||||
|
* @phpstan-param row_array|object $row
|
||||||
*/
|
*/
|
||||||
protected function shouldUpdate($data): bool
|
protected function shouldUpdate($row): bool
|
||||||
{
|
{
|
||||||
return ! empty($this->getIdValue($data));
|
$id = $this->getIdValue($row);
|
||||||
|
|
||||||
|
return ! ($id === null || $id === []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -730,14 +748,16 @@ abstract class BaseModel
|
|||||||
* Inserts data into the database. If an object is provided,
|
* Inserts data into the database. If an object is provided,
|
||||||
* it will attempt to convert it to an array.
|
* it will attempt to convert it to an array.
|
||||||
*
|
*
|
||||||
* @param array|object|null $data Data
|
* @param array|object|null $row Row data
|
||||||
* @param bool $returnID Whether insert ID should be returned or not.
|
* @phpstan-param row_array|object|null $row
|
||||||
|
* @param bool $returnID Whether insert ID should be returned or not.
|
||||||
*
|
*
|
||||||
* @return bool|int|string insert ID or true on success. false on failure.
|
* @return bool|int|string insert ID or true on success. false on failure.
|
||||||
|
* @phpstan-return ($returnID is true ? int|string|false : bool)
|
||||||
*
|
*
|
||||||
* @throws ReflectionException
|
* @throws ReflectionException
|
||||||
*/
|
*/
|
||||||
public function insert($data = null, bool $returnID = true)
|
public function insert($row = null, bool $returnID = true)
|
||||||
{
|
{
|
||||||
$this->insertID = 0;
|
$this->insertID = 0;
|
||||||
|
|
||||||
@ -745,10 +765,10 @@ abstract class BaseModel
|
|||||||
$cleanValidationRules = $this->cleanValidationRules;
|
$cleanValidationRules = $this->cleanValidationRules;
|
||||||
$this->cleanValidationRules = false;
|
$this->cleanValidationRules = false;
|
||||||
|
|
||||||
$data = $this->transformDataToArray($data, 'insert');
|
$row = $this->transformDataToArray($row, 'insert');
|
||||||
|
|
||||||
// Validate data before saving.
|
// Validate data before saving.
|
||||||
if (! $this->skipValidation && ! $this->validate($data)) {
|
if (! $this->skipValidation && ! $this->validate($row)) {
|
||||||
// Restore $cleanValidationRules
|
// Restore $cleanValidationRules
|
||||||
$this->cleanValidationRules = $cleanValidationRules;
|
$this->cleanValidationRules = $cleanValidationRules;
|
||||||
|
|
||||||
@ -760,26 +780,20 @@ abstract class BaseModel
|
|||||||
|
|
||||||
// Must be called first, so we don't
|
// Must be called first, so we don't
|
||||||
// strip out created_at values.
|
// strip out created_at values.
|
||||||
$data = $this->doProtectFieldsForInsert($data);
|
$row = $this->doProtectFieldsForInsert($row);
|
||||||
|
|
||||||
// doProtectFields() can further remove elements from
|
// doProtectFields() can further remove elements from
|
||||||
// $data so we need to check for empty dataset again
|
// $row, so we need to check for empty dataset again
|
||||||
if (! $this->allowEmptyInserts && empty($data)) {
|
if (! $this->allowEmptyInserts && $row === []) {
|
||||||
throw DataException::forEmptyDataset('insert');
|
throw DataException::forEmptyDataset('insert');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set created_at and updated_at with same time
|
// Set created_at and updated_at with same time
|
||||||
$date = $this->setDate();
|
$date = $this->setDate();
|
||||||
|
$row = $this->setCreatedField($row, $date);
|
||||||
|
$row = $this->setUpdatedField($row, $date);
|
||||||
|
|
||||||
if ($this->useTimestamps && $this->createdField && ! array_key_exists($this->createdField, $data)) {
|
$eventData = ['data' => $row];
|
||||||
$data[$this->createdField] = $date;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $data)) {
|
|
||||||
$data[$this->updatedField] = $date;
|
|
||||||
}
|
|
||||||
|
|
||||||
$eventData = ['data' => $data];
|
|
||||||
|
|
||||||
if ($this->tempAllowCallbacks) {
|
if ($this->tempAllowCallbacks) {
|
||||||
$eventData = $this->trigger('beforeInsert', $eventData);
|
$eventData = $this->trigger('beforeInsert', $eventData);
|
||||||
@ -809,13 +823,44 @@ abstract class BaseModel
|
|||||||
return $returnID ? $this->insertID : $result;
|
return $returnID ? $this->insertID : $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set datetime to created field.
|
||||||
|
*
|
||||||
|
* @phpstan-param row_array $row
|
||||||
|
* @param int|string $date timestamp or datetime string
|
||||||
|
*/
|
||||||
|
protected function setCreatedField(array $row, $date): array
|
||||||
|
{
|
||||||
|
if ($this->useTimestamps && $this->createdField !== '' && ! array_key_exists($this->createdField, $row)) {
|
||||||
|
$row[$this->createdField] = $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set datetime to updated field.
|
||||||
|
*
|
||||||
|
* @phpstan-param row_array $row
|
||||||
|
* @param int|string $date timestamp or datetime string
|
||||||
|
*/
|
||||||
|
protected function setUpdatedField(array $row, $date): array
|
||||||
|
{
|
||||||
|
if ($this->useTimestamps && $this->updatedField !== '' && ! array_key_exists($this->updatedField, $row)) {
|
||||||
|
$row[$this->updatedField] = $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles batch insert runs the queries, validating each row prior.
|
* Compiles batch insert runs the queries, validating each row prior.
|
||||||
*
|
*
|
||||||
* @param array|null $set an associative array of insert values
|
* @param list<array|object>|null $set an associative array of insert values
|
||||||
* @param bool|null $escape Whether to escape values
|
* @phpstan-param list<row_array|object>|null $set
|
||||||
* @param int $batchSize The size of the batch to run
|
* @param bool|null $escape Whether to escape values
|
||||||
* @param bool $testing True means only number of records is returned, false will execute the query
|
* @param int $batchSize The size of the batch to run
|
||||||
|
* @param bool $testing True means only number of records is returned, false will execute the query
|
||||||
*
|
*
|
||||||
* @return bool|int Number of rows inserted or FALSE on failure
|
* @return bool|int Number of rows inserted or FALSE on failure
|
||||||
*
|
*
|
||||||
@ -829,7 +874,7 @@ abstract class BaseModel
|
|||||||
|
|
||||||
if (is_array($set)) {
|
if (is_array($set)) {
|
||||||
foreach ($set as &$row) {
|
foreach ($set as &$row) {
|
||||||
// If $data is using a custom class with public or protected
|
// If $row is using a custom class with public or protected
|
||||||
// properties representing the collection elements, we need to grab
|
// properties representing the collection elements, we need to grab
|
||||||
// them as an array.
|
// them as an array.
|
||||||
if (is_object($row) && ! $row instanceof stdClass) {
|
if (is_object($row) && ! $row instanceof stdClass) {
|
||||||
@ -857,14 +902,8 @@ abstract class BaseModel
|
|||||||
|
|
||||||
// Set created_at and updated_at with same time
|
// Set created_at and updated_at with same time
|
||||||
$date = $this->setDate();
|
$date = $this->setDate();
|
||||||
|
$row = $this->setCreatedField($row, $date);
|
||||||
if ($this->useTimestamps && $this->createdField && ! array_key_exists($this->createdField, $row)) {
|
$row = $this->setUpdatedField($row, $date);
|
||||||
$row[$this->createdField] = $date;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $row)) {
|
|
||||||
$row[$this->updatedField] = $date;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -899,11 +938,12 @@ abstract class BaseModel
|
|||||||
* it will attempt to convert it into an array.
|
* it will attempt to convert it into an array.
|
||||||
*
|
*
|
||||||
* @param array|int|string|null $id
|
* @param array|int|string|null $id
|
||||||
* @param array|object|null $data
|
* @param array|object|null $row Row data
|
||||||
|
* @phpstan-param row_array|object|null $row
|
||||||
*
|
*
|
||||||
* @throws ReflectionException
|
* @throws ReflectionException
|
||||||
*/
|
*/
|
||||||
public function update($id = null, $data = null): bool
|
public function update($id = null, $row = null): bool
|
||||||
{
|
{
|
||||||
if (is_bool($id)) {
|
if (is_bool($id)) {
|
||||||
throw new InvalidArgumentException('update(): argument #1 ($id) should not be boolean.');
|
throw new InvalidArgumentException('update(): argument #1 ($id) should not be boolean.');
|
||||||
@ -913,30 +953,28 @@ abstract class BaseModel
|
|||||||
$id = [$id];
|
$id = [$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->transformDataToArray($data, 'update');
|
$row = $this->transformDataToArray($row, 'update');
|
||||||
|
|
||||||
// Validate data before saving.
|
// Validate data before saving.
|
||||||
if (! $this->skipValidation && ! $this->validate($data)) {
|
if (! $this->skipValidation && ! $this->validate($row)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be called first, so we don't
|
// Must be called first, so we don't
|
||||||
// strip out updated_at values.
|
// strip out updated_at values.
|
||||||
$data = $this->doProtectFields($data);
|
$row = $this->doProtectFields($row);
|
||||||
|
|
||||||
// doProtectFields() can further remove elements from
|
// doProtectFields() can further remove elements from
|
||||||
// $data, so we need to check for empty dataset again
|
// $row, so we need to check for empty dataset again
|
||||||
if (empty($data)) {
|
if ($row === []) {
|
||||||
throw DataException::forEmptyDataset('update');
|
throw DataException::forEmptyDataset('update');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $data)) {
|
$row = $this->setUpdatedField($row, $this->setDate());
|
||||||
$data[$this->updatedField] = $this->setDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
$eventData = [
|
$eventData = [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'data' => $data,
|
'data' => $row,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($this->tempAllowCallbacks) {
|
if ($this->tempAllowCallbacks) {
|
||||||
@ -961,7 +999,8 @@ abstract class BaseModel
|
|||||||
/**
|
/**
|
||||||
* Compiles an update and runs the query.
|
* Compiles an update and runs the query.
|
||||||
*
|
*
|
||||||
* @param array|null $set An associative array of update values
|
* @param list<array|object>|null $set an associative array of insert values
|
||||||
|
* @phpstan-param list<row_array|object>|null $set
|
||||||
* @param string|null $index The where key
|
* @param string|null $index The where key
|
||||||
* @param int $batchSize The size of the batch to run
|
* @param int $batchSize The size of the batch to run
|
||||||
* @param bool $returnSQL True means SQL is returned, false will execute the query
|
* @param bool $returnSQL True means SQL is returned, false will execute the query
|
||||||
@ -975,7 +1014,7 @@ abstract class BaseModel
|
|||||||
{
|
{
|
||||||
if (is_array($set)) {
|
if (is_array($set)) {
|
||||||
foreach ($set as &$row) {
|
foreach ($set as &$row) {
|
||||||
// If $data is using a custom class with public or protected
|
// If $row is using a custom class with public or protected
|
||||||
// properties representing the collection elements, we need to grab
|
// properties representing the collection elements, we need to grab
|
||||||
// them as an array.
|
// them as an array.
|
||||||
if (is_object($row) && ! $row instanceof stdClass) {
|
if (is_object($row) && ! $row instanceof stdClass) {
|
||||||
@ -1015,9 +1054,7 @@ abstract class BaseModel
|
|||||||
$row[$index] = $updateIndex;
|
$row[$index] = $updateIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $row)) {
|
$row = $this->setUpdatedField($row, $this->setDate());
|
||||||
$row[$this->updatedField] = $this->setDate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1136,23 +1173,22 @@ abstract class BaseModel
|
|||||||
/**
|
/**
|
||||||
* Compiles a replace and runs the query.
|
* Compiles a replace and runs the query.
|
||||||
*
|
*
|
||||||
* @param array|null $data Data
|
* @param array|null $row Row data
|
||||||
* @param bool $returnSQL Set to true to return Query String
|
* @phpstan-param row_array|null $row
|
||||||
|
* @param bool $returnSQL Set to true to return Query String
|
||||||
*
|
*
|
||||||
* @return BaseResult|false|Query|string
|
* @return BaseResult|false|Query|string
|
||||||
*/
|
*/
|
||||||
public function replace(?array $data = null, bool $returnSQL = false)
|
public function replace(?array $row = null, bool $returnSQL = false)
|
||||||
{
|
{
|
||||||
// Validate data before saving.
|
// Validate data before saving.
|
||||||
if ($data && ! $this->skipValidation && ! $this->validate($data)) {
|
if (($row !== null) && ! $this->skipValidation && ! $this->validate($row)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, (array) $data)) {
|
$row = $this->setUpdatedField((array) $row, $this->setDate());
|
||||||
$data[$this->updatedField] = $this->setDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->doReplace($data, $returnSQL);
|
return $this->doReplace($row, $returnSQL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1240,46 +1276,48 @@ abstract class BaseModel
|
|||||||
* Ensures that only the fields that are allowed to be updated are
|
* Ensures that only the fields that are allowed to be updated are
|
||||||
* in the data array.
|
* in the data array.
|
||||||
*
|
*
|
||||||
* Used by update() and updateBatch() to protect against mass assignment
|
* @used-by update() to protect against mass assignment vulnerabilities.
|
||||||
* vulnerabilities.
|
* @used-by updateBatch() to protect against mass assignment vulnerabilities.
|
||||||
*
|
*
|
||||||
* @param array $data Data
|
* @param array $row Row data
|
||||||
|
* @phpstan-param row_array $row
|
||||||
*
|
*
|
||||||
* @throws DataException
|
* @throws DataException
|
||||||
*/
|
*/
|
||||||
protected function doProtectFields(array $data): array
|
protected function doProtectFields(array $row): array
|
||||||
{
|
{
|
||||||
if (! $this->protectFields) {
|
if (! $this->protectFields) {
|
||||||
return $data;
|
return $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->allowedFields)) {
|
if ($this->allowedFields === []) {
|
||||||
throw DataException::forInvalidAllowedFields(static::class);
|
throw DataException::forInvalidAllowedFields(static::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array_keys($data) as $key) {
|
foreach (array_keys($row) as $key) {
|
||||||
if (! in_array($key, $this->allowedFields, true)) {
|
if (! in_array($key, $this->allowedFields, true)) {
|
||||||
unset($data[$key]);
|
unset($row[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that only the fields that are allowed to be inserted are in
|
* Ensures that only the fields that are allowed to be inserted are in
|
||||||
* the data array.
|
* the data array.
|
||||||
*
|
*
|
||||||
* Used by insert() and insertBatch() to protect against mass assignment
|
* @used-by insert() to protect against mass assignment vulnerabilities.
|
||||||
* vulnerabilities.
|
* @used-by insertBatch() to protect against mass assignment vulnerabilities.
|
||||||
*
|
*
|
||||||
* @param array $data Data
|
* @param array $row Row data
|
||||||
|
* @phpstan-param row_array $row
|
||||||
*
|
*
|
||||||
* @throws DataException
|
* @throws DataException
|
||||||
*/
|
*/
|
||||||
protected function doProtectFieldsForInsert(array $data): array
|
protected function doProtectFieldsForInsert(array $row): array
|
||||||
{
|
{
|
||||||
return $this->doProtectFields($data);
|
return $this->doProtectFields($row);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1464,35 +1502,36 @@ abstract class BaseModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the data against the validation rules (or the validation group)
|
* Validate the row data against the validation rules (or the validation group)
|
||||||
* specified in the class property, $validationRules.
|
* specified in the class property, $validationRules.
|
||||||
*
|
*
|
||||||
* @param array|object $data Data
|
* @param array|object $row Row data
|
||||||
|
* @phpstan-param row_array|object $row
|
||||||
*/
|
*/
|
||||||
public function validate($data): bool
|
public function validate($row): bool
|
||||||
{
|
{
|
||||||
$rules = $this->getValidationRules();
|
$rules = $this->getValidationRules();
|
||||||
|
|
||||||
if ($this->skipValidation || empty($rules) || empty($data)) {
|
// Validation requires array, so cast away.
|
||||||
|
if (is_object($row)) {
|
||||||
|
$row = (array) $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->skipValidation || $rules === [] || $row === []) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation requires array, so cast away.
|
$rules = $this->cleanValidationRules ? $this->cleanValidationRules($rules, $row) : $rules;
|
||||||
if (is_object($data)) {
|
|
||||||
$data = (array) $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
$rules = $this->cleanValidationRules ? $this->cleanValidationRules($rules, $data) : $rules;
|
|
||||||
|
|
||||||
// If no data existed that needs validation
|
// If no data existed that needs validation
|
||||||
// our job is done here.
|
// our job is done here.
|
||||||
if (empty($rules)) {
|
if ($rules === []) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->validation->reset()->setRules($rules, $this->validationMessages);
|
$this->validation->reset()->setRules($rules, $this->validationMessages);
|
||||||
|
|
||||||
return $this->validation->run($data, null, $this->DBGroup);
|
return $this->validation->run($row, null, $this->DBGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1536,17 +1575,18 @@ abstract class BaseModel
|
|||||||
* currently so that rules don't block updating when only updating
|
* currently so that rules don't block updating when only updating
|
||||||
* a partial row.
|
* a partial row.
|
||||||
*
|
*
|
||||||
* @param array $rules Array containing field name and rule
|
* @param array $rules Array containing field name and rule
|
||||||
* @param array|null $data Data
|
* @param array $row Row data (@TODO Remove null in param type)
|
||||||
|
* @phpstan-param row_array $row
|
||||||
*/
|
*/
|
||||||
protected function cleanValidationRules(array $rules, ?array $data = null): array
|
protected function cleanValidationRules(array $rules, ?array $row = null): array
|
||||||
{
|
{
|
||||||
if (empty($data)) {
|
if ($row === null || $row === []) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array_keys($rules) as $field) {
|
foreach (array_keys($rules) as $field) {
|
||||||
if (! array_key_exists($field, $data)) {
|
if (! array_key_exists($field, $row)) {
|
||||||
unset($rules[$field]);
|
unset($rules[$field]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1594,7 +1634,7 @@ abstract class BaseModel
|
|||||||
protected function trigger(string $event, array $eventData)
|
protected function trigger(string $event, array $eventData)
|
||||||
{
|
{
|
||||||
// Ensure it's a valid event
|
// Ensure it's a valid event
|
||||||
if (! isset($this->{$event}) || empty($this->{$event})) {
|
if (! isset($this->{$event}) || $this->{$event} === []) {
|
||||||
return $eventData;
|
return $eventData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1644,52 +1684,63 @@ abstract class BaseModel
|
|||||||
* This method uses objectToRawArray() internally and does conversion
|
* This method uses objectToRawArray() internally and does conversion
|
||||||
* to string on all Time instances
|
* to string on all Time instances
|
||||||
*
|
*
|
||||||
* @param object|string $data Data
|
* @param object $object Object
|
||||||
* @param bool $onlyChanged Only Changed Property
|
* @param bool $onlyChanged Only Changed Property
|
||||||
* @param bool $recursive If true, inner entities will be cast as array as well
|
* @param bool $recursive If true, inner entities will be cast as array as well
|
||||||
*
|
*
|
||||||
* @return array Array
|
* @return array<string, mixed>
|
||||||
*
|
*
|
||||||
* @throws ReflectionException
|
* @throws ReflectionException
|
||||||
*/
|
*/
|
||||||
protected function objectToArray($data, bool $onlyChanged = true, bool $recursive = false): array
|
protected function objectToArray($object, bool $onlyChanged = true, bool $recursive = false): array
|
||||||
{
|
{
|
||||||
$properties = $this->objectToRawArray($data, $onlyChanged, $recursive);
|
$properties = $this->objectToRawArray($object, $onlyChanged, $recursive);
|
||||||
|
|
||||||
assert(is_array($properties));
|
|
||||||
|
|
||||||
// Convert any Time instances to appropriate $dateFormat
|
// Convert any Time instances to appropriate $dateFormat
|
||||||
if ($properties !== []) {
|
return $this->timeToString($properties);
|
||||||
$properties = array_map(function ($value) {
|
}
|
||||||
if ($value instanceof Time) {
|
|
||||||
return $this->timeToDate($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
/**
|
||||||
}, $properties);
|
* Convert any Time instances to appropriate $dateFormat.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $properties
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
protected function timeToString(array $properties): array
|
||||||
|
{
|
||||||
|
if ($properties === []) {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $properties;
|
return array_map(function ($value) {
|
||||||
|
if ($value instanceof Time) {
|
||||||
|
return $this->timeToDate($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}, $properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a class and returns an array of its public and protected
|
* Takes a class and returns an array of its public and protected
|
||||||
* properties as an array with raw values.
|
* properties as an array with raw values.
|
||||||
*
|
*
|
||||||
* @param object|string $data Data
|
* @param object $object Object
|
||||||
* @param bool $onlyChanged Only Changed Property
|
* @param bool $onlyChanged Only Changed Property
|
||||||
* @param bool $recursive If true, inner entities will be casted as array as well
|
* @param bool $recursive If true, inner entities will be casted as array as well
|
||||||
*
|
*
|
||||||
* @return array|null Array
|
* @return array<string, mixed>
|
||||||
*
|
*
|
||||||
* @throws ReflectionException
|
* @throws ReflectionException
|
||||||
*/
|
*/
|
||||||
protected function objectToRawArray($data, bool $onlyChanged = true, bool $recursive = false): ?array
|
protected function objectToRawArray($object, bool $onlyChanged = true, bool $recursive = false): array
|
||||||
{
|
{
|
||||||
if (method_exists($data, 'toRawArray')) {
|
// Entity::toRawArray() returns array.
|
||||||
$properties = $data->toRawArray($onlyChanged, $recursive);
|
if (method_exists($object, 'toRawArray')) {
|
||||||
|
$properties = $object->toRawArray($onlyChanged, $recursive);
|
||||||
} else {
|
} else {
|
||||||
$mirror = new ReflectionClass($data);
|
$mirror = new ReflectionClass($object);
|
||||||
$props = $mirror->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);
|
$props = $mirror->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);
|
||||||
|
|
||||||
$properties = [];
|
$properties = [];
|
||||||
@ -1699,7 +1750,7 @@ abstract class BaseModel
|
|||||||
foreach ($props as $prop) {
|
foreach ($props as $prop) {
|
||||||
// Must make protected values accessible.
|
// Must make protected values accessible.
|
||||||
$prop->setAccessible(true);
|
$prop->setAccessible(true);
|
||||||
$properties[$prop->getName()] = $prop->getValue($data);
|
$properties[$prop->getName()] = $prop->getValue($object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1709,47 +1760,48 @@ abstract class BaseModel
|
|||||||
/**
|
/**
|
||||||
* Transform data to array.
|
* Transform data to array.
|
||||||
*
|
*
|
||||||
* @param array|object|null $data Data
|
* @param array|object|null $row Row data
|
||||||
* @param string $type Type of data (insert|update)
|
* @phpstan-param row_array|object|null $row
|
||||||
|
* @param string $type Type of data (insert|update)
|
||||||
*
|
*
|
||||||
* @throws DataException
|
* @throws DataException
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @throws ReflectionException
|
* @throws ReflectionException
|
||||||
*/
|
*/
|
||||||
protected function transformDataToArray($data, string $type): array
|
protected function transformDataToArray($row, string $type): array
|
||||||
{
|
{
|
||||||
if (! in_array($type, ['insert', 'update'], true)) {
|
if (! in_array($type, ['insert', 'update'], true)) {
|
||||||
throw new InvalidArgumentException(sprintf('Invalid type "%s" used upon transforming data to array.', $type));
|
throw new InvalidArgumentException(sprintf('Invalid type "%s" used upon transforming data to array.', $type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->allowEmptyInserts && empty($data)) {
|
if (! $this->allowEmptyInserts && ($row === null || (array) $row === [])) {
|
||||||
throw DataException::forEmptyDataset($type);
|
throw DataException::forEmptyDataset($type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If $data is using a custom class with public or protected
|
// If $row is using a custom class with public or protected
|
||||||
// properties representing the collection elements, we need to grab
|
// properties representing the collection elements, we need to grab
|
||||||
// them as an array.
|
// them as an array.
|
||||||
if (is_object($data) && ! $data instanceof stdClass) {
|
if (is_object($row) && ! $row instanceof stdClass) {
|
||||||
// If it validates with entire rules, all fields are needed.
|
// If it validates with entire rules, all fields are needed.
|
||||||
$onlyChanged = ($this->skipValidation === false && $this->cleanValidationRules === false)
|
$onlyChanged = ($this->skipValidation === false && $this->cleanValidationRules === false)
|
||||||
? false : ($type === 'update');
|
? false : ($type === 'update');
|
||||||
|
|
||||||
$data = $this->objectToArray($data, $onlyChanged, true);
|
$row = $this->objectToArray($row, $onlyChanged, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's still a stdClass, go ahead and convert to
|
// If it's still a stdClass, go ahead and convert to
|
||||||
// an array so doProtectFields and other model methods
|
// an array so doProtectFields and other model methods
|
||||||
// don't have to do special checks.
|
// don't have to do special checks.
|
||||||
if (is_object($data)) {
|
if (is_object($row)) {
|
||||||
$data = (array) $data;
|
$row = (array) $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's still empty here, means $data is no change or is empty object
|
// If it's still empty here, means $row is no change or is empty object
|
||||||
if (! $this->allowEmptyInserts && empty($data)) {
|
if (! $this->allowEmptyInserts && ($row === null || $row === [])) {
|
||||||
throw DataException::forEmptyDataset($type);
|
throw DataException::forEmptyDataset($type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1829,7 +1881,7 @@ abstract class BaseModel
|
|||||||
$replacements['{' . $key . '}'] = $value;
|
$replacements['{' . $key . '}'] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($replacements)) {
|
if ($replacements !== []) {
|
||||||
foreach ($rules as &$rule) {
|
foreach ($rules as &$rule) {
|
||||||
if (is_array($rule)) {
|
if (is_array($rule)) {
|
||||||
foreach ($rule as &$row) {
|
foreach ($rule as &$row) {
|
||||||
|
|||||||
@ -19,14 +19,14 @@ use Throwable;
|
|||||||
/**
|
/**
|
||||||
* BaseCommand is the base class used in creating CLI commands.
|
* BaseCommand is the base class used in creating CLI commands.
|
||||||
*
|
*
|
||||||
* @property array $arguments
|
* @property array<string, string> $arguments
|
||||||
* @property Commands $commands
|
* @property Commands $commands
|
||||||
* @property string $description
|
* @property string $description
|
||||||
* @property string $group
|
* @property string $group
|
||||||
* @property LoggerInterface $logger
|
* @property LoggerInterface $logger
|
||||||
* @property string $name
|
* @property string $name
|
||||||
* @property array $options
|
* @property array<string, string> $options
|
||||||
* @property string $usage
|
* @property string $usage
|
||||||
*/
|
*/
|
||||||
abstract class BaseCommand
|
abstract class BaseCommand
|
||||||
{
|
{
|
||||||
@ -62,14 +62,14 @@ abstract class BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's options description
|
* the Command's options description
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [];
|
protected $options = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the Command's Arguments description
|
* the Command's Arguments description
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [];
|
protected $arguments = [];
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ abstract class BaseCommand
|
|||||||
} else {
|
} else {
|
||||||
$usage = $this->name;
|
$usage = $this->name;
|
||||||
|
|
||||||
if (! empty($this->arguments)) {
|
if ($this->arguments !== []) {
|
||||||
$usage .= ' [arguments]';
|
$usage .= ' [arguments]';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ abstract class BaseCommand
|
|||||||
CLI::write($this->setPad($this->description, 0, 0, 2));
|
CLI::write($this->setPad($this->description, 0, 0, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($this->arguments)) {
|
if ($this->arguments !== []) {
|
||||||
CLI::newLine();
|
CLI::newLine();
|
||||||
CLI::write(lang('CLI.helpArguments'), 'yellow');
|
CLI::write(lang('CLI.helpArguments'), 'yellow');
|
||||||
$length = max(array_map('strlen', array_keys($this->arguments)));
|
$length = max(array_map('strlen', array_keys($this->arguments)));
|
||||||
@ -166,7 +166,7 @@ abstract class BaseCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($this->options)) {
|
if ($this->options !== []) {
|
||||||
CLI::newLine();
|
CLI::newLine();
|
||||||
CLI::write(lang('CLI.helpOptions'), 'yellow');
|
CLI::write(lang('CLI.helpOptions'), 'yellow');
|
||||||
$length = max(array_map('strlen', array_keys($this->options)));
|
$length = max(array_map('strlen', array_keys($this->options)));
|
||||||
|
|||||||
@ -252,7 +252,7 @@ class CLI
|
|||||||
|
|
||||||
unset($opts[0]);
|
unset($opts[0]);
|
||||||
|
|
||||||
if (empty($opts)) {
|
if ($opts === []) {
|
||||||
$extraOutput = $extraOutputDefault;
|
$extraOutput = $extraOutputDefault;
|
||||||
} else {
|
} else {
|
||||||
$extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $opts) . ']';
|
$extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $opts) . ']';
|
||||||
@ -324,7 +324,7 @@ class CLI
|
|||||||
$opts = $options;
|
$opts = $options;
|
||||||
unset($opts[0]);
|
unset($opts[0]);
|
||||||
|
|
||||||
if (empty($opts)) {
|
if ($opts === []) {
|
||||||
$extraOutput = $extraOutputDefault;
|
$extraOutput = $extraOutputDefault;
|
||||||
} else {
|
} else {
|
||||||
$optsKey = [];
|
$optsKey = [];
|
||||||
@ -849,7 +849,7 @@ class CLI
|
|||||||
*/
|
*/
|
||||||
public static function wrap(?string $string = null, int $max = 0, int $padLeft = 0): string
|
public static function wrap(?string $string = null, int $max = 0, int $padLeft = 0): string
|
||||||
{
|
{
|
||||||
if (empty($string)) {
|
if ($string === null || $string === '') {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,7 +1000,7 @@ class CLI
|
|||||||
*/
|
*/
|
||||||
public static function getOptionString(bool $useLongOpts = false, bool $trim = false): string
|
public static function getOptionString(bool $useLongOpts = false, bool $trim = false): string
|
||||||
{
|
{
|
||||||
if (empty(static::$options)) {
|
if (static::$options === []) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1041,7 +1041,7 @@ class CLI
|
|||||||
$tableRows = [];
|
$tableRows = [];
|
||||||
|
|
||||||
// We need only indexes and not keys
|
// We need only indexes and not keys
|
||||||
if (! empty($thead)) {
|
if ($thead !== []) {
|
||||||
$tableRows[] = array_values($thead);
|
$tableRows[] = array_values($thead);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,7 +1115,7 @@ class CLI
|
|||||||
$table .= '| ' . implode(' | ', $tableRows[$row]) . ' |' . PHP_EOL;
|
$table .= '| ' . implode(' | ', $tableRows[$row]) . ' |' . PHP_EOL;
|
||||||
|
|
||||||
// Set the thead and table borders-bottom
|
// Set the thead and table borders-bottom
|
||||||
if (($row === 0 && ! empty($thead)) || ($row + 1 === $totalRows)) {
|
if (($row === 0 && $thead !== []) || ($row + 1 === $totalRows)) {
|
||||||
$table .= $cols . PHP_EOL;
|
$table .= $cols . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,9 @@ class CacheFactory
|
|||||||
/**
|
/**
|
||||||
* Attempts to create the desired cache handler, based upon the
|
* Attempts to create the desired cache handler, based upon the
|
||||||
*
|
*
|
||||||
|
* @param non-empty-string|null $handler
|
||||||
|
* @param non-empty-string|null $backup
|
||||||
|
*
|
||||||
* @return CacheInterface
|
* @return CacheInterface
|
||||||
*/
|
*/
|
||||||
public static function getHandler(Cache $config, ?string $handler = null, ?string $backup = null)
|
public static function getHandler(Cache $config, ?string $handler = null, ?string $backup = null)
|
||||||
@ -52,8 +55,8 @@ class CacheFactory
|
|||||||
throw CacheException::forNoBackup();
|
throw CacheException::forNoBackup();
|
||||||
}
|
}
|
||||||
|
|
||||||
$handler = ! empty($handler) ? $handler : $config->handler;
|
$handler ??= $config->handler;
|
||||||
$backup = ! empty($backup) ? $backup : $config->backupHandler;
|
$backup ??= $config->backupHandler;
|
||||||
|
|
||||||
if (! array_key_exists($handler, $config->validHandlers) || ! array_key_exists($backup, $config->validHandlers)) {
|
if (! array_key_exists($handler, $config->validHandlers) || ! array_key_exists($backup, $config->validHandlers)) {
|
||||||
throw CacheException::forHandlerNotFound();
|
throw CacheException::forHandlerNotFound();
|
||||||
|
|||||||
@ -76,10 +76,9 @@ abstract class BaseHandler implements CacheInterface
|
|||||||
/**
|
/**
|
||||||
* Get an item from the cache, or execute the given Closure and store the result.
|
* Get an item from the cache, or execute the given Closure and store the result.
|
||||||
*
|
*
|
||||||
* @param string $key Cache item name
|
* @param string $key Cache item name
|
||||||
* @param int $ttl Time to live
|
* @param int $ttl Time to live
|
||||||
* @param Closure $callback Callback return value
|
* @param Closure(): mixed $callback Callback return value
|
||||||
* @phpstan-param Closure(): mixed $callback
|
|
||||||
*
|
*
|
||||||
* @return array|bool|float|int|object|string|null
|
* @return array|bool|float|int|object|string|null
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -150,8 +150,8 @@ class FileHandler extends BaseHandler
|
|||||||
*/
|
*/
|
||||||
public function increment(string $key, int $offset = 1)
|
public function increment(string $key, int $offset = 1)
|
||||||
{
|
{
|
||||||
$key = static::validateKey($key, $this->prefix);
|
$prefixedKey = static::validateKey($key, $this->prefix);
|
||||||
$tmp = $this->getItem($key);
|
$tmp = $this->getItem($prefixedKey);
|
||||||
|
|
||||||
if ($tmp === false) {
|
if ($tmp === false) {
|
||||||
$tmp = ['data' => 0, 'ttl' => 60];
|
$tmp = ['data' => 0, 'ttl' => 60];
|
||||||
@ -222,8 +222,7 @@ class FileHandler extends BaseHandler
|
|||||||
* Does the heavy lifting of actually retrieving the file and
|
* Does the heavy lifting of actually retrieving the file and
|
||||||
* verifying it's age.
|
* verifying it's age.
|
||||||
*
|
*
|
||||||
* @return array<string, mixed>|false
|
* @return array{data: mixed, ttl: int, time: int}|false
|
||||||
* @phpstan-return array{data: mixed, ttl: int, time: int}|false
|
|
||||||
*/
|
*/
|
||||||
protected function getItem(string $filename)
|
protected function getItem(string $filename)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -245,6 +245,7 @@ class RedisHandler extends BaseHandler
|
|||||||
if ($value !== null) {
|
if ($value !== null) {
|
||||||
$time = Time::now()->getTimestamp();
|
$time = Time::now()->getTimestamp();
|
||||||
$ttl = $this->redis->ttl(static::validateKey($key, $this->prefix));
|
$ttl = $this->redis->ttl(static::validateKey($key, $this->prefix));
|
||||||
|
assert(is_int($ttl));
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'expire' => $ttl > 0 ? $time + $ttl : null,
|
'expire' => $ttl > 0 ? $time + $ttl : null,
|
||||||
|
|||||||
@ -54,7 +54,7 @@ class CodeIgniter
|
|||||||
/**
|
/**
|
||||||
* The current version of CodeIgniter Framework
|
* The current version of CodeIgniter Framework
|
||||||
*/
|
*/
|
||||||
public const CI_VERSION = '4.4.3';
|
public const CI_VERSION = '4.4.5';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* App startup time.
|
* App startup time.
|
||||||
@ -108,7 +108,7 @@ class CodeIgniter
|
|||||||
/**
|
/**
|
||||||
* Controller to use.
|
* Controller to use.
|
||||||
*
|
*
|
||||||
* @var Closure|string
|
* @var (Closure(mixed...): ResponseInterface|string)|string|null
|
||||||
*/
|
*/
|
||||||
protected $controller;
|
protected $controller;
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ class CodeIgniter
|
|||||||
/**
|
/**
|
||||||
* Request path to use.
|
* Request path to use.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string|null
|
||||||
*
|
*
|
||||||
* @deprecated No longer used.
|
* @deprecated No longer used.
|
||||||
*/
|
*/
|
||||||
@ -302,7 +302,7 @@ class CodeIgniter
|
|||||||
Kint::$display_called_from = $config->displayCalledFrom;
|
Kint::$display_called_from = $config->displayCalledFrom;
|
||||||
Kint::$expanded = $config->expanded;
|
Kint::$expanded = $config->expanded;
|
||||||
|
|
||||||
if (! empty($config->plugins) && is_array($config->plugins)) {
|
if (isset($config->plugins) && is_array($config->plugins)) {
|
||||||
Kint::$plugins = $config->plugins;
|
Kint::$plugins = $config->plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,10 +315,10 @@ class CodeIgniter
|
|||||||
RichRenderer::$theme = $config->richTheme;
|
RichRenderer::$theme = $config->richTheme;
|
||||||
RichRenderer::$folder = $config->richFolder;
|
RichRenderer::$folder = $config->richFolder;
|
||||||
RichRenderer::$sort = $config->richSort;
|
RichRenderer::$sort = $config->richSort;
|
||||||
if (! empty($config->richObjectPlugins) && is_array($config->richObjectPlugins)) {
|
if (isset($config->richObjectPlugins) && is_array($config->richObjectPlugins)) {
|
||||||
RichRenderer::$value_plugins = $config->richObjectPlugins;
|
RichRenderer::$value_plugins = $config->richObjectPlugins;
|
||||||
}
|
}
|
||||||
if (! empty($config->richTabPlugins) && is_array($config->richTabPlugins)) {
|
if (isset($config->richTabPlugins) && is_array($config->richTabPlugins)) {
|
||||||
RichRenderer::$tab_plugins = $config->richTabPlugins;
|
RichRenderer::$tab_plugins = $config->richTabPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,11 +848,10 @@ class CodeIgniter
|
|||||||
*/
|
*/
|
||||||
protected function determinePath()
|
protected function determinePath()
|
||||||
{
|
{
|
||||||
if (! empty($this->path)) {
|
return $this->path ??
|
||||||
return $this->path;
|
(method_exists($this->request, 'getPath')
|
||||||
}
|
? $this->request->getPath()
|
||||||
|
: $this->request->getUri()->getPath());
|
||||||
return method_exists($this->request, 'getPath') ? $this->request->getPath() : $this->request->getUri()->getPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -892,7 +891,7 @@ class CodeIgniter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No controller specified - we don't know what to do now.
|
// No controller specified - we don't know what to do now.
|
||||||
if (empty($this->controller)) {
|
if (! isset($this->controller)) {
|
||||||
throw PageNotFoundException::forEmptyController();
|
throw PageNotFoundException::forEmptyController();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1091,7 +1090,7 @@ class CodeIgniter
|
|||||||
|
|
||||||
$method = $this->request->getPost('_method');
|
$method = $this->request->getPost('_method');
|
||||||
|
|
||||||
if (empty($method)) {
|
if ($method === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class ClearCache extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Arguments
|
* the Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'driver' => 'The cache driver to use',
|
'driver' => 'The cache driver to use',
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class Migrate extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Options
|
* the Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'-n' => 'Set migration namespace',
|
'-n' => 'Set migration namespace',
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class MigrateRefresh extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Options
|
* the Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'-n' => 'Set migration namespace',
|
'-n' => 'Set migration namespace',
|
||||||
|
|||||||
@ -54,7 +54,7 @@ class MigrateRollback extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Options
|
* the Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'-b' => 'Specify a batch to roll back to; e.g. "3" to return to batch #3',
|
'-b' => 'Specify a batch to roll back to; e.g. "3" to return to batch #3',
|
||||||
|
|||||||
@ -84,7 +84,7 @@ class ShowTableInfo extends BaseCommand
|
|||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-var list<list<string|int>> Table Data.
|
* @var list<list<int|string>> Table Data.
|
||||||
*/
|
*/
|
||||||
private array $tbody;
|
private array $tbody;
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ class ShowTableInfo extends BaseCommand
|
|||||||
$limitRows = (int) ($params['limit-rows'] ?? 10);
|
$limitRows = (int) ($params['limit-rows'] ?? 10);
|
||||||
$limitFieldValue = (int) ($params['limit-field-value'] ?? 15);
|
$limitFieldValue = (int) ($params['limit-field-value'] ?? 15);
|
||||||
|
|
||||||
if (! in_array($tableName, $tables, true)) {
|
while (! in_array($tableName, $tables, true)) {
|
||||||
$tableNameNo = CLI::promptByKey(
|
$tableNameNo = CLI::promptByKey(
|
||||||
['Here is the list of your database tables:', 'Which table do you want to see?'],
|
['Here is the list of your database tables:', 'Which table do you want to see?'],
|
||||||
$tables,
|
$tables,
|
||||||
@ -133,7 +133,7 @@ class ShowTableInfo extends BaseCommand
|
|||||||
);
|
);
|
||||||
CLI::newLine();
|
CLI::newLine();
|
||||||
|
|
||||||
$tableName = $tables[$tableNameNo];
|
$tableName = $tables[$tableNameNo] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('metadata', $params)) {
|
if (array_key_exists('metadata', $params)) {
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class GenerateKey extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The command's options
|
* The command's options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--force' => 'Force overwrite existing key in `.env` file.',
|
'--force' => 'Force overwrite existing key in `.env` file.',
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class CellGenerator extends BaseCommand
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $description = 'Generates a new Cell file and its view.';
|
protected $description = 'Generates a new Controlled Cell file and its view.';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Command's Usage
|
* The Command's Usage
|
||||||
@ -52,16 +52,16 @@ class CellGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The cell class name.',
|
'name' => 'The Controlled Cell class name.',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class CommandGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The command class name.',
|
'name' => 'The command class name.',
|
||||||
@ -62,12 +62,12 @@ class CommandGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--command' => 'The command name. Default: "command:name"',
|
'--command' => 'The command name. Default: "command:name"',
|
||||||
'--type' => 'The command type. Options [basic, generator]. Default: "basic".',
|
'--type' => 'The command type. Options [basic, generator]. Default: "basic".',
|
||||||
'--group' => 'The command group. Default: [basic -> "CodeIgniter", generator -> "Generators"].',
|
'--group' => 'The command group. Default: [basic -> "App", generator -> "Generators"].',
|
||||||
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
||||||
'--suffix' => 'Append the component title to the class name (e.g. User => UserCommand).',
|
'--suffix' => 'Append the component title to the class name (e.g. User => UserCommand).',
|
||||||
'--force' => 'Force overwrite existing file.',
|
'--force' => 'Force overwrite existing file.',
|
||||||
@ -106,7 +106,7 @@ class CommandGenerator extends BaseCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! is_string($group)) {
|
if (! is_string($group)) {
|
||||||
$group = $type === 'generator' ? 'Generators' : 'CodeIgniter';
|
$group = $type === 'generator' ? 'Generators' : 'App';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->parseTemplate(
|
return $this->parseTemplate(
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class ConfigGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The config class name.',
|
'name' => 'The config class name.',
|
||||||
@ -61,7 +61,7 @@ class ConfigGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class ControllerGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The controller class name.',
|
'name' => 'The controller class name.',
|
||||||
@ -65,7 +65,7 @@ class ControllerGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--bare' => 'Extends from CodeIgniter\Controller instead of BaseController.',
|
'--bare' => 'Extends from CodeIgniter\Controller instead of BaseController.',
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class EntityGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The entity class name.',
|
'name' => 'The entity class name.',
|
||||||
@ -61,7 +61,7 @@ class EntityGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class FilterGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The filter class name.',
|
'name' => 'The filter class name.',
|
||||||
@ -61,7 +61,7 @@ class FilterGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
||||||
|
|||||||
@ -55,7 +55,7 @@ class MigrateCreate extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's arguments.
|
* The Command's arguments.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The migration file name.',
|
'name' => 'The migration file name.',
|
||||||
@ -64,7 +64,7 @@ class MigrateCreate extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's options.
|
* The Command's options.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--namespace' => 'Set root namespace. Defaults to APP_NAMESPACE',
|
'--namespace' => 'Set root namespace. Defaults to APP_NAMESPACE',
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class MigrationGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The migration class name.',
|
'name' => 'The migration class name.',
|
||||||
@ -65,7 +65,7 @@ class MigrationGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--session' => 'Generates the migration file for database sessions.',
|
'--session' => 'Generates the migration file for database sessions.',
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class ModelGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The model class name.',
|
'name' => 'The model class name.',
|
||||||
@ -62,7 +62,7 @@ class ModelGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--table' => 'Supply a table name. Default: "the lowercased plural of the class name".',
|
'--table' => 'Supply a table name. Default: "the lowercased plural of the class name".',
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class ScaffoldGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The class name',
|
'name' => 'The class name',
|
||||||
@ -62,7 +62,7 @@ class ScaffoldGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--bare' => 'Add the "--bare" option to controller component.',
|
'--bare' => 'Add the "--bare" option to controller component.',
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class SeederGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The seeder class name.',
|
'name' => 'The seeder class name.',
|
||||||
@ -61,7 +61,7 @@ class SeederGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
||||||
|
|||||||
@ -59,7 +59,7 @@ class SessionMigrationGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'-t' => 'Supply a table name.',
|
'-t' => 'Supply a table name.',
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class ValidationGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Arguments
|
* The Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'name' => 'The validation class name.',
|
'name' => 'The validation class name.',
|
||||||
@ -61,7 +61,7 @@ class ValidationGenerator extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's Options
|
* The Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace {namespace};
|
namespace {namespace};
|
||||||
|
|
||||||
use {useStatement};
|
use {useStatement};
|
||||||
|
use CodeIgniter\HTTP\ResponseInterface;
|
||||||
|
|
||||||
class {class} extends {extends}
|
class {class} extends {extends}
|
||||||
{
|
{
|
||||||
@ -10,7 +11,7 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Return an array of resource objects, themselves in array format
|
* Return an array of resource objects, themselves in array format
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
@ -20,7 +21,7 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Return the properties of a resource object
|
* Return the properties of a resource object
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function show($id = null)
|
public function show($id = null)
|
||||||
{
|
{
|
||||||
@ -30,7 +31,7 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Return a new resource object, with default properties
|
* Return a new resource object, with default properties
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function new()
|
public function new()
|
||||||
{
|
{
|
||||||
@ -40,7 +41,7 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Create a new resource object, from "posted" parameters
|
* Create a new resource object, from "posted" parameters
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
@ -50,7 +51,7 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Return the editable properties of a resource object
|
* Return the editable properties of a resource object
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function edit($id = null)
|
public function edit($id = null)
|
||||||
{
|
{
|
||||||
@ -60,7 +61,7 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Add or update a model resource, from "posted" properties
|
* Add or update a model resource, from "posted" properties
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function update($id = null)
|
public function update($id = null)
|
||||||
{
|
{
|
||||||
@ -70,7 +71,7 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Delete the designated resource object from the model
|
* Delete the designated resource object from the model
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function delete($id = null)
|
public function delete($id = null)
|
||||||
{
|
{
|
||||||
@ -80,7 +81,7 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Present a view of resource objects
|
* Present a view of resource objects
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
@ -90,9 +91,9 @@ class {class} extends {extends}
|
|||||||
/**
|
/**
|
||||||
* Present a view to present a specific resource object
|
* Present a view to present a specific resource object
|
||||||
*
|
*
|
||||||
* @param mixed $id
|
* @param string $id
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function show($id = null)
|
public function show($id = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class {class} implements FilterInterface
|
|||||||
* @param RequestInterface $request
|
* @param RequestInterface $request
|
||||||
* @param array|null $arguments
|
* @param array|null $arguments
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return RequestInterface|ResponseInterface|string|void
|
||||||
*/
|
*/
|
||||||
public function before(RequestInterface $request, $arguments = null)
|
public function before(RequestInterface $request, $arguments = null)
|
||||||
{
|
{
|
||||||
@ -38,7 +38,7 @@ class {class} implements FilterInterface
|
|||||||
* @param ResponseInterface $response
|
* @param ResponseInterface $response
|
||||||
* @param array|null $arguments
|
* @param array|null $arguments
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return ResponseInterface|void
|
||||||
*/
|
*/
|
||||||
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
|
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -17,6 +17,8 @@ class {class} extends Model
|
|||||||
protected $protectFields = true;
|
protected $protectFields = true;
|
||||||
protected $allowedFields = [];
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected bool $allowEmptyInserts = false;
|
||||||
|
|
||||||
// Dates
|
// Dates
|
||||||
protected $useTimestamps = false;
|
protected $useTimestamps = false;
|
||||||
protected $dateFormat = 'datetime';
|
protected $dateFormat = 'datetime';
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class Help extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Arguments
|
* the Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'command_name' => 'The command name [default: "help"]',
|
'command_name' => 'The command name [default: "help"]',
|
||||||
@ -62,7 +62,7 @@ class Help extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Options
|
* the Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [];
|
protected $options = [];
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ class ClearLogs extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's options
|
* The Command's options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--force' => 'Force delete of all logs files without prompting.',
|
'--force' => 'Force delete of all logs files without prompting.',
|
||||||
|
|||||||
@ -54,14 +54,14 @@ class ListCommands extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Arguments
|
* the Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [];
|
protected $arguments = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the Command's Options
|
* the Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--simple' => 'Prints a list of the commands with no other info',
|
'--simple' => 'Prints a list of the commands with no other info',
|
||||||
|
|||||||
@ -54,7 +54,7 @@ class Serve extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* Arguments
|
* Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [];
|
protected $arguments = [];
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ class Serve extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* Options
|
* Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'--php' => 'The PHP Binary [default: "PHP_BINARY"]',
|
'--php' => 'The PHP Binary [default: "PHP_BINARY"]',
|
||||||
|
|||||||
@ -62,7 +62,7 @@ final class Environment extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* The Command's options
|
* The Command's options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [];
|
protected $options = [];
|
||||||
|
|
||||||
|
|||||||
@ -57,13 +57,13 @@ class FilterCheck extends BaseCommand
|
|||||||
*/
|
*/
|
||||||
protected $arguments = [
|
protected $arguments = [
|
||||||
'method' => 'The HTTP method. get, post, put, etc.',
|
'method' => 'The HTTP method. get, post, put, etc.',
|
||||||
'route' => 'The route (URI path) to check filtes.',
|
'route' => 'The route (URI path) to check filters.',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the Command's Options
|
* the Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [];
|
protected $options = [];
|
||||||
|
|
||||||
|
|||||||
@ -57,14 +57,14 @@ class Namespaces extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Arguments
|
* the Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [];
|
protected $arguments = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the Command's Options
|
* the Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [
|
protected $options = [
|
||||||
'-c' => 'Show only CodeIgniter config namespaces.',
|
'-c' => 'Show only CodeIgniter config namespaces.',
|
||||||
|
|||||||
@ -63,7 +63,7 @@ class Publish extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Options
|
* the Command's Options
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $options = [];
|
protected $options = [];
|
||||||
|
|
||||||
|
|||||||
@ -61,7 +61,7 @@ class Routes extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* the Command's Arguments
|
* the Command's Arguments
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
protected $arguments = [];
|
protected $arguments = [];
|
||||||
|
|
||||||
|
|||||||
@ -37,8 +37,7 @@ final class AutoRouteCollector
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<int, array<int, string>>
|
* @return list<list<string>>
|
||||||
* @phpstan-return list<list<string>>
|
|
||||||
*/
|
*/
|
||||||
public function get(): array
|
public function get(): array
|
||||||
{
|
{
|
||||||
|
|||||||
@ -62,8 +62,7 @@ final class AutoRouteCollector
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<int, array<int, string>>
|
* @return list<list<string>>
|
||||||
* @phpstan-return list<list<string>>
|
|
||||||
*/
|
*/
|
||||||
public function get(): array
|
public function get(): array
|
||||||
{
|
{
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace CodeIgniter\Commands\Utilities\Routes\AutoRouterImproved;
|
namespace CodeIgniter\Commands\Utilities\Routes\AutoRouterImproved;
|
||||||
|
|
||||||
|
use Config\Routing;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use ReflectionMethod;
|
use ReflectionMethod;
|
||||||
|
|
||||||
@ -27,11 +28,12 @@ final class ControllerMethodReader
|
|||||||
private string $namespace;
|
private string $namespace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<int, string>
|
* @var list<string>
|
||||||
* @phpstan-var list<string>
|
|
||||||
*/
|
*/
|
||||||
private array $httpMethods;
|
private array $httpMethods;
|
||||||
|
|
||||||
|
private bool $translateURIDashes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $namespace the default namespace
|
* @param string $namespace the default namespace
|
||||||
*/
|
*/
|
||||||
@ -39,15 +41,17 @@ final class ControllerMethodReader
|
|||||||
{
|
{
|
||||||
$this->namespace = $namespace;
|
$this->namespace = $namespace;
|
||||||
$this->httpMethods = $httpMethods;
|
$this->httpMethods = $httpMethods;
|
||||||
|
|
||||||
|
$config = config(Routing::class);
|
||||||
|
$this->translateURIDashes = $config->translateURIDashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns found route info in the controller.
|
* Returns found route info in the controller.
|
||||||
*
|
*
|
||||||
* @phpstan-param class-string $class
|
* @param class-string $class
|
||||||
*
|
*
|
||||||
* @return array<int, array<string, array|string>>
|
* @return list<array<string, array|string>>
|
||||||
* @phpstan-return list<array<string, string|array>>
|
|
||||||
*/
|
*/
|
||||||
public function read(string $class, string $defaultController = 'Home', string $defaultMethod = 'index'): array
|
public function read(string $class, string $defaultController = 'Home', string $defaultMethod = 'index'): array
|
||||||
{
|
{
|
||||||
@ -69,7 +73,7 @@ final class ControllerMethodReader
|
|||||||
foreach ($this->httpMethods as $httpVerb) {
|
foreach ($this->httpMethods as $httpVerb) {
|
||||||
if (strpos($methodName, $httpVerb) === 0) {
|
if (strpos($methodName, $httpVerb) === 0) {
|
||||||
// Remove HTTP verb prefix.
|
// Remove HTTP verb prefix.
|
||||||
$methodInUri = lcfirst(substr($methodName, strlen($httpVerb)));
|
$methodInUri = $this->getUriByMethod($httpVerb, $methodName);
|
||||||
|
|
||||||
// Check if it is the default method.
|
// Check if it is the default method.
|
||||||
if ($methodInUri === $defaultMethod) {
|
if ($methodInUri === $defaultMethod) {
|
||||||
@ -154,7 +158,7 @@ final class ControllerMethodReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-param class-string $classname
|
* @param class-string $classname
|
||||||
*
|
*
|
||||||
* @return string URI path part from the folder(s) and controller
|
* @return string URI path part from the folder(s) and controller
|
||||||
*/
|
*/
|
||||||
@ -173,13 +177,33 @@ final class ControllerMethodReader
|
|||||||
$classPath .= lcfirst($part) . '/';
|
$classPath .= lcfirst($part) . '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtrim($classPath, '/');
|
$classUri = rtrim($classPath, '/');
|
||||||
|
|
||||||
|
if ($this->translateURIDashes) {
|
||||||
|
$classUri = str_replace('_', '-', $classUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $classUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string URI path part from the method
|
||||||
|
*/
|
||||||
|
private function getUriByMethod(string $httpVerb, string $methodName): string
|
||||||
|
{
|
||||||
|
$methodUri = lcfirst(substr($methodName, strlen($httpVerb)));
|
||||||
|
|
||||||
|
if ($this->translateURIDashes) {
|
||||||
|
$methodUri = str_replace('_', '-', $methodUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $methodUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a route for the default controller.
|
* Gets a route for the default controller.
|
||||||
*
|
*
|
||||||
* @phpstan-return list<array>
|
* @return list<array>
|
||||||
*/
|
*/
|
||||||
private function getRouteForDefaultController(
|
private function getRouteForDefaultController(
|
||||||
string $classShortname,
|
string $classShortname,
|
||||||
|
|||||||
@ -38,8 +38,7 @@ final class ControllerFinder
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return class-string[]
|
||||||
* @phpstan-return class-string[]
|
|
||||||
*/
|
*/
|
||||||
public function find(): array
|
public function find(): array
|
||||||
{
|
{
|
||||||
@ -66,7 +65,7 @@ final class ControllerFinder
|
|||||||
$classnameOrEmpty = $this->locator->getClassname($file);
|
$classnameOrEmpty = $this->locator->getClassname($file);
|
||||||
|
|
||||||
if ($classnameOrEmpty !== '') {
|
if ($classnameOrEmpty !== '') {
|
||||||
/** @phpstan-var class-string $classname */
|
/** @var class-string $classname */
|
||||||
$classname = $classnameOrEmpty;
|
$classname = $classnameOrEmpty;
|
||||||
|
|
||||||
$classes[] = $classname;
|
$classes[] = $classname;
|
||||||
|
|||||||
@ -35,10 +35,9 @@ final class ControllerMethodReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-param class-string $class
|
* @param class-string $class
|
||||||
*
|
*
|
||||||
* @return array<int, array{route: string, handler: string}>
|
* @return list<array{route: string, handler: string}>
|
||||||
* @phpstan-return list<array{route: string, handler: string}>
|
|
||||||
*/
|
*/
|
||||||
public function read(string $class, string $defaultController = 'Home', string $defaultMethod = 'index'): array
|
public function read(string $class, string $defaultController = 'Home', string $defaultMethod = 'index'): array
|
||||||
{
|
{
|
||||||
@ -128,7 +127,7 @@ final class ControllerMethodReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-param class-string $classname
|
* @param class-string $classname
|
||||||
*
|
*
|
||||||
* @return string URI path part from the folder(s) and controller
|
* @return string URI path part from the folder(s) and controller
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -13,6 +13,7 @@ namespace CodeIgniter\Commands\Utilities\Routes;
|
|||||||
|
|
||||||
use CodeIgniter\Config\Services;
|
use CodeIgniter\Config\Services;
|
||||||
use CodeIgniter\Router\RouteCollection;
|
use CodeIgniter\Router\RouteCollection;
|
||||||
|
use Config\App;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a sample URI path from route key regex.
|
* Generate a sample URI path from route key regex.
|
||||||
@ -51,6 +52,14 @@ final class SampleURIGenerator
|
|||||||
{
|
{
|
||||||
$sampleUri = $routeKey;
|
$sampleUri = $routeKey;
|
||||||
|
|
||||||
|
if (strpos($routeKey, '{locale}') !== false) {
|
||||||
|
$sampleUri = str_replace(
|
||||||
|
'{locale}',
|
||||||
|
config(App::class)->defaultLocale,
|
||||||
|
$routeKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($this->routes->getPlaceholders() as $placeholder => $regex) {
|
foreach ($this->routes->getPlaceholders() as $placeholder => $regex) {
|
||||||
$sample = $this->samples[$placeholder] ?? '::unknown::';
|
$sample = $this->samples[$placeholder] ?? '::unknown::';
|
||||||
|
|
||||||
|
|||||||
@ -25,9 +25,7 @@ use CodeIgniter\HTTP\Exceptions\RedirectException;
|
|||||||
use CodeIgniter\HTTP\IncomingRequest;
|
use CodeIgniter\HTTP\IncomingRequest;
|
||||||
use CodeIgniter\HTTP\RedirectResponse;
|
use CodeIgniter\HTTP\RedirectResponse;
|
||||||
use CodeIgniter\HTTP\RequestInterface;
|
use CodeIgniter\HTTP\RequestInterface;
|
||||||
use CodeIgniter\HTTP\Response;
|
|
||||||
use CodeIgniter\HTTP\ResponseInterface;
|
use CodeIgniter\HTTP\ResponseInterface;
|
||||||
use CodeIgniter\HTTP\URI;
|
|
||||||
use CodeIgniter\Model;
|
use CodeIgniter\Model;
|
||||||
use CodeIgniter\Session\Session;
|
use CodeIgniter\Session\Session;
|
||||||
use CodeIgniter\Test\TestLogger;
|
use CodeIgniter\Test\TestLogger;
|
||||||
@ -290,20 +288,24 @@ if (! function_exists('csrf_hash')) {
|
|||||||
if (! function_exists('csrf_field')) {
|
if (! function_exists('csrf_field')) {
|
||||||
/**
|
/**
|
||||||
* Generates a hidden input field for use within manually generated forms.
|
* Generates a hidden input field for use within manually generated forms.
|
||||||
|
*
|
||||||
|
* @param non-empty-string|null $id
|
||||||
*/
|
*/
|
||||||
function csrf_field(?string $id = null): string
|
function csrf_field(?string $id = null): string
|
||||||
{
|
{
|
||||||
return '<input type="hidden"' . (! empty($id) ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . csrf_token() . '" value="' . csrf_hash() . '"' . _solidus() . '>';
|
return '<input type="hidden"' . ($id !== null ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . csrf_token() . '" value="' . csrf_hash() . '"' . _solidus() . '>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! function_exists('csrf_meta')) {
|
if (! function_exists('csrf_meta')) {
|
||||||
/**
|
/**
|
||||||
* Generates a meta tag for use within javascript calls.
|
* Generates a meta tag for use within javascript calls.
|
||||||
|
*
|
||||||
|
* @param non-empty-string|null $id
|
||||||
*/
|
*/
|
||||||
function csrf_meta(?string $id = null): string
|
function csrf_meta(?string $id = null): string
|
||||||
{
|
{
|
||||||
return '<meta' . (! empty($id) ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . csrf_header() . '" content="' . csrf_hash() . '"' . _solidus() . '>';
|
return '<meta' . ($id !== null ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . csrf_header() . '" content="' . csrf_hash() . '"' . _solidus() . '>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,27 +504,11 @@ if (! function_exists('force_https')) {
|
|||||||
Services::session()->regenerate(); // @codeCoverageIgnore
|
Services::session()->regenerate(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$baseURL = config(App::class)->baseURL;
|
$uri = $request->getUri()->withScheme('https');
|
||||||
|
|
||||||
if (strpos($baseURL, 'https://') === 0) {
|
|
||||||
$authority = substr($baseURL, strlen('https://'));
|
|
||||||
} elseif (strpos($baseURL, 'http://') === 0) {
|
|
||||||
$authority = substr($baseURL, strlen('http://'));
|
|
||||||
} else {
|
|
||||||
$authority = $baseURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
$uri = URI::createURIString(
|
|
||||||
'https',
|
|
||||||
$authority,
|
|
||||||
$request->getUri()->getPath(), // Absolute URIs should use a "/" for an empty path
|
|
||||||
$request->getUri()->getQuery(),
|
|
||||||
$request->getUri()->getFragment()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set an HSTS header
|
// Set an HSTS header
|
||||||
$response->setHeader('Strict-Transport-Security', 'max-age=' . $duration)
|
$response->setHeader('Strict-Transport-Security', 'max-age=' . $duration)
|
||||||
->redirect($uri)
|
->redirect((string) $uri)
|
||||||
->setStatusCode(307)
|
->setStatusCode(307)
|
||||||
->setBody('')
|
->setBody('')
|
||||||
->getCookieStore()
|
->getCookieStore()
|
||||||
@ -755,7 +741,7 @@ if (! function_exists('lang')) {
|
|||||||
* A convenience method to translate a string or array of them and format
|
* A convenience method to translate a string or array of them and format
|
||||||
* the result with the intl extension's MessageFormatter.
|
* the result with the intl extension's MessageFormatter.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return list<string>|string
|
||||||
*/
|
*/
|
||||||
function lang(string $line, array $args = [], ?string $locale = null)
|
function lang(string $line, array $args = [], ?string $locale = null)
|
||||||
{
|
{
|
||||||
@ -868,13 +854,13 @@ if (! function_exists('redirect')) {
|
|||||||
*
|
*
|
||||||
* If more control is needed, you must use $response->redirect explicitly.
|
* If more control is needed, you must use $response->redirect explicitly.
|
||||||
*
|
*
|
||||||
* @param string|null $route Route name or Controller::method
|
* @param non-empty-string|null $route Route name or Controller::method
|
||||||
*/
|
*/
|
||||||
function redirect(?string $route = null): RedirectResponse
|
function redirect(?string $route = null): RedirectResponse
|
||||||
{
|
{
|
||||||
$response = Services::redirectresponse(null, true);
|
$response = Services::redirectresponse(null, true);
|
||||||
|
|
||||||
if (! empty($route)) {
|
if ($route !== null) {
|
||||||
return $response->route($route);
|
return $response->route($route);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1139,15 +1125,17 @@ if (! function_exists('timer')) {
|
|||||||
* returns its return value if any.
|
* returns its return value if any.
|
||||||
* Otherwise will start or stop the timer intelligently.
|
* Otherwise will start or stop the timer intelligently.
|
||||||
*
|
*
|
||||||
* @phpstan-param (callable(): mixed)|null $callable
|
* @param non-empty-string|null $name
|
||||||
|
* @param (callable(): mixed)|null $callable
|
||||||
*
|
*
|
||||||
* @return Timer
|
* @return mixed|Timer
|
||||||
|
* @phpstan-return ($name is null ? Timer : ($callable is (callable(): mixed) ? mixed : Timer))
|
||||||
*/
|
*/
|
||||||
function timer(?string $name = null, ?callable $callable = null)
|
function timer(?string $name = null, ?callable $callable = null)
|
||||||
{
|
{
|
||||||
$timer = Services::timer();
|
$timer = Services::timer();
|
||||||
|
|
||||||
if (empty($name)) {
|
if ($name === null) {
|
||||||
return $timer;
|
return $timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,8 +45,7 @@ class AutoloadConfig
|
|||||||
* but this should be done prior to creating any namespaced classes,
|
* but this should be done prior to creating any namespaced classes,
|
||||||
* else you will need to modify all of those classes for this to work.
|
* else you will need to modify all of those classes for this to work.
|
||||||
*
|
*
|
||||||
* @var array<string, array<int, string>|string>
|
* @var array<string, list<string>|string>
|
||||||
* @phpstan-var array<string, string|list<string>>
|
|
||||||
*/
|
*/
|
||||||
public $psr4 = [];
|
public $psr4 = [];
|
||||||
|
|
||||||
@ -72,8 +71,7 @@ class AutoloadConfig
|
|||||||
* that will be autoloaded. This can be useful for bootstrap operations
|
* that will be autoloaded. This can be useful for bootstrap operations
|
||||||
* or for loading functions.
|
* or for loading functions.
|
||||||
*
|
*
|
||||||
* @var array<int, string>
|
* @var list<string>
|
||||||
* @phpstan-var list<string>
|
|
||||||
*/
|
*/
|
||||||
public $files = [];
|
public $files = [];
|
||||||
|
|
||||||
|
|||||||
@ -343,7 +343,7 @@ class BaseService
|
|||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$classname = $locator->getClassname($file);
|
$classname = $locator->getClassname($file);
|
||||||
|
|
||||||
if (! in_array($classname, [Services::class], true)) {
|
if ($classname !== Services::class) {
|
||||||
static::$services[] = new $classname();
|
static::$services[] = new $classname();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,8 +62,7 @@ class Factories
|
|||||||
*
|
*
|
||||||
* [component => [alias => FQCN]]
|
* [component => [alias => FQCN]]
|
||||||
*
|
*
|
||||||
* @var array<string, array<string, string>>
|
* @var array<string, array<string, class-string>>
|
||||||
* @phpstan-var array<string, array<string, class-string>>
|
|
||||||
*/
|
*/
|
||||||
protected static $aliases = [];
|
protected static $aliases = [];
|
||||||
|
|
||||||
@ -76,8 +75,7 @@ class Factories
|
|||||||
*
|
*
|
||||||
* [component => [FQCN => instance]]
|
* [component => [FQCN => instance]]
|
||||||
*
|
*
|
||||||
* @var array<string, array<string, object>>
|
* @var array<string, array<class-string, object>>
|
||||||
* @phpstan-var array<string, array<class-string, object>>
|
|
||||||
*/
|
*/
|
||||||
protected static $instances = [];
|
protected static $instances = [];
|
||||||
|
|
||||||
@ -93,10 +91,9 @@ class Factories
|
|||||||
/**
|
/**
|
||||||
* Define the class to load. You can *override* the concrete class.
|
* Define the class to load. You can *override* the concrete class.
|
||||||
*
|
*
|
||||||
* @param string $component Lowercase, plural component name
|
* @param string $component Lowercase, plural component name
|
||||||
* @param string $alias Class alias. See the $aliases property.
|
* @param string $alias Class alias. See the $aliases property.
|
||||||
* @param string $classname FQCN to be loaded
|
* @param class-string $classname FQCN to be loaded
|
||||||
* @phpstan-param class-string $classname FQCN to be loaded
|
|
||||||
*/
|
*/
|
||||||
public static function define(string $component, string $alias, string $classname): void
|
public static function define(string $component, string $alias, string $classname): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class Publisher extends BaseConfig
|
|||||||
* result in a PublisherException. Files that do no fit the
|
* result in a PublisherException. Files that do no fit the
|
||||||
* pattern will cause copy/merge to fail.
|
* pattern will cause copy/merge to fail.
|
||||||
*
|
*
|
||||||
* @var array<string,string>
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
public $restrictions = [
|
public $restrictions = [
|
||||||
ROOTPATH => '*',
|
ROOTPATH => '*',
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class Routing extends BaseConfig
|
|||||||
* Default: APPPATH . 'Config/Routes.php'
|
* Default: APPPATH . 'Config/Routes.php'
|
||||||
*/
|
*/
|
||||||
public array $routeFiles = [
|
public array $routeFiles = [
|
||||||
APPPATH . 'Routes.php',
|
APPPATH . 'Config/Routes.php',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,4 +95,17 @@ class Routing extends BaseConfig
|
|||||||
* Default: false
|
* Default: false
|
||||||
*/
|
*/
|
||||||
public bool $prioritize = false;
|
public bool $prioritize = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of URI segments and namespaces. For Auto Routing (Improved).
|
||||||
|
*
|
||||||
|
* The key is the first URI segment. The value is the controller namespace.
|
||||||
|
* E.g.,
|
||||||
|
* [
|
||||||
|
* 'blog' => 'Acme\Blog\Controllers',
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* @var array [ uri_segment => namespace ]
|
||||||
|
*/
|
||||||
|
public array $moduleRoutes = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,8 @@ use CodeIgniter\View\ViewDecoratorInterface;
|
|||||||
/**
|
/**
|
||||||
* View configuration
|
* View configuration
|
||||||
*
|
*
|
||||||
* @phpstan-type ParserCallable (callable(mixed): mixed)
|
* @phpstan-type parser_callable (callable(mixed): mixed)
|
||||||
* @phpstan-type ParserCallableString (callable(mixed): mixed)&string
|
* @phpstan-type parser_callable_string (callable(mixed): mixed)&string
|
||||||
*/
|
*/
|
||||||
class View extends BaseConfig
|
class View extends BaseConfig
|
||||||
{
|
{
|
||||||
@ -40,7 +40,7 @@ class View extends BaseConfig
|
|||||||
* @psalm-suppress UndefinedDocblockClass
|
* @psalm-suppress UndefinedDocblockClass
|
||||||
*
|
*
|
||||||
* @var array<string, string>
|
* @var array<string, string>
|
||||||
* @phpstan-var array<string, ParserCallableString>
|
* @phpstan-var array<string, parser_callable_string>
|
||||||
*/
|
*/
|
||||||
public $filters = [];
|
public $filters = [];
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ class View extends BaseConfig
|
|||||||
* @psalm-suppress UndefinedDocblockClass
|
* @psalm-suppress UndefinedDocblockClass
|
||||||
*
|
*
|
||||||
* @var array<string, array<string>|callable|string>
|
* @var array<string, array<string>|callable|string>
|
||||||
* @phpstan-var array<string, array<ParserCallableString>|ParserCallableString|ParserCallable>
|
* @phpstan-var array<string, array<parser_callable_string>|parser_callable_string|parser_callable>
|
||||||
*/
|
*/
|
||||||
public $plugins = [];
|
public $plugins = [];
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ class View extends BaseConfig
|
|||||||
* Built-in View filters.
|
* Built-in View filters.
|
||||||
*
|
*
|
||||||
* @var array<string, string>
|
* @var array<string, string>
|
||||||
* @phpstan-var array<string, ParserCallableString>
|
* @phpstan-var array<string, parser_callable_string>
|
||||||
*/
|
*/
|
||||||
protected $coreFilters = [
|
protected $coreFilters = [
|
||||||
'abs' => '\abs',
|
'abs' => '\abs',
|
||||||
@ -90,7 +90,7 @@ class View extends BaseConfig
|
|||||||
* Built-in View plugins.
|
* Built-in View plugins.
|
||||||
*
|
*
|
||||||
* @var array<string, array<string>|callable|string>
|
* @var array<string, array<string>|callable|string>
|
||||||
* @phpstan-var array<string, array<ParserCallableString>|ParserCallableString|ParserCallable>
|
* @phpstan-var array<string, array<parser_callable_string>|parser_callable_string|parser_callable>
|
||||||
*/
|
*/
|
||||||
protected $corePlugins = [
|
protected $corePlugins = [
|
||||||
'csp_script_nonce' => '\CodeIgniter\View\Plugins::cspScriptNonce',
|
'csp_script_nonce' => '\CodeIgniter\View\Plugins::cspScriptNonce',
|
||||||
|
|||||||
@ -65,7 +65,7 @@ class Controller
|
|||||||
/**
|
/**
|
||||||
* Once validation has been run, will hold the Validation instance.
|
* Once validation has been run, will hold the Validation instance.
|
||||||
*
|
*
|
||||||
* @var ValidationInterface
|
* @var ValidationInterface|null
|
||||||
*/
|
*/
|
||||||
protected $validator;
|
protected $validator;
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ class Controller
|
|||||||
*/
|
*/
|
||||||
protected function loadHelpers()
|
protected function loadHelpers()
|
||||||
{
|
{
|
||||||
if (empty($this->helpers)) {
|
if ($this->helpers === []) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -88,8 +88,7 @@ class BaseBuilder
|
|||||||
* QB keys
|
* QB keys
|
||||||
* list of column names.
|
* list of column names.
|
||||||
*
|
*
|
||||||
* @var string[]
|
* @var list<string>
|
||||||
* @phpstan-var list<string>
|
|
||||||
*/
|
*/
|
||||||
protected $QBKeys = [];
|
protected $QBKeys = [];
|
||||||
|
|
||||||
@ -131,8 +130,7 @@ class BaseBuilder
|
|||||||
/**
|
/**
|
||||||
* QB data sets
|
* QB data sets
|
||||||
*
|
*
|
||||||
* @var array[]|string[]
|
* @var array<string, string>|list<list<int|string>>
|
||||||
* @phpstan-var array<string, string>|list<list<string|int>>
|
|
||||||
*/
|
*/
|
||||||
protected $QBSet = [];
|
protected $QBSet = [];
|
||||||
|
|
||||||
@ -164,16 +162,18 @@ class BaseBuilder
|
|||||||
* Holds additional options and data used to render SQL
|
* Holds additional options and data used to render SQL
|
||||||
* and is reset by resetWrite()
|
* and is reset by resetWrite()
|
||||||
*
|
*
|
||||||
* @phpstan-var array{
|
* @var array{
|
||||||
* updateFieldsAdditional?: array,
|
* updateFieldsAdditional?: array,
|
||||||
* tableIdentity?: string,
|
* tableIdentity?: string,
|
||||||
* updateFields?: array,
|
* updateFields?: array,
|
||||||
* constraints?: array,
|
* constraints?: array,
|
||||||
* setQueryAsData?: string,
|
* setQueryAsData?: string,
|
||||||
* sql?: string,
|
* sql?: string,
|
||||||
* alias?: string
|
* alias?: string,
|
||||||
|
* fieldTypes?: array<string, array<string, string>>
|
||||||
* }
|
* }
|
||||||
* @var array
|
*
|
||||||
|
* fieldTypes: [ProtectedTableName => [FieldName => Type]]
|
||||||
*/
|
*/
|
||||||
protected $QBOptions;
|
protected $QBOptions;
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ class BaseBuilder
|
|||||||
|
|
||||||
$this->from($tableName);
|
$this->from($tableName);
|
||||||
|
|
||||||
if (! empty($options)) {
|
if ($options !== null && $options !== []) {
|
||||||
foreach ($options as $key => $value) {
|
foreach ($options as $key => $value) {
|
||||||
if (property_exists($this, $key)) {
|
if (property_exists($this, $key)) {
|
||||||
$this->{$key} = $value;
|
$this->{$key} = $value;
|
||||||
@ -923,6 +923,7 @@ class BaseBuilder
|
|||||||
* @used-by whereNotIn()
|
* @used-by whereNotIn()
|
||||||
* @used-by orWhereNotIn()
|
* @used-by orWhereNotIn()
|
||||||
*
|
*
|
||||||
|
* @param non-empty-string|null $key
|
||||||
* @param array|BaseBuilder|Closure|null $values The values searched on, or anonymous function with subquery
|
* @param array|BaseBuilder|Closure|null $values The values searched on, or anonymous function with subquery
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
@ -931,7 +932,7 @@ class BaseBuilder
|
|||||||
*/
|
*/
|
||||||
protected function _whereIn(?string $key = null, $values = null, bool $not = false, string $type = 'AND ', ?bool $escape = null, string $clause = 'QBWhere')
|
protected function _whereIn(?string $key = null, $values = null, bool $not = false, string $type = 'AND ', ?bool $escape = null, string $clause = 'QBWhere')
|
||||||
{
|
{
|
||||||
if (empty($key) || ! is_string($key)) {
|
if ($key === null || $key === '') {
|
||||||
throw new InvalidArgumentException(sprintf('%s() expects $key to be a non-empty string', debug_backtrace(0, 2)[1]['function']));
|
throw new InvalidArgumentException(sprintf('%s() expects $key to be a non-empty string', debug_backtrace(0, 2)[1]['function']));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1437,7 +1438,7 @@ class BaseBuilder
|
|||||||
public function orderBy(string $orderBy, string $direction = '', ?bool $escape = null)
|
public function orderBy(string $orderBy, string $direction = '', ?bool $escape = null)
|
||||||
{
|
{
|
||||||
$qbOrderBy = [];
|
$qbOrderBy = [];
|
||||||
if (empty($orderBy)) {
|
if ($orderBy === '') {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1493,7 +1494,7 @@ class BaseBuilder
|
|||||||
$this->QBLimit = $value;
|
$this->QBLimit = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($offset)) {
|
if ($offset !== null && $offset !== 0) {
|
||||||
$this->QBOffset = $offset;
|
$this->QBOffset = $offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1507,8 +1508,8 @@ class BaseBuilder
|
|||||||
*/
|
*/
|
||||||
public function offset(int $offset)
|
public function offset(int $offset)
|
||||||
{
|
{
|
||||||
if (! empty($offset)) {
|
if ($offset !== 0) {
|
||||||
$this->QBOffset = (int) $offset;
|
$this->QBOffset = $offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -1739,7 +1740,7 @@ class BaseBuilder
|
|||||||
$this->where($where);
|
$this->where($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($limit)) {
|
if ($limit !== null && $limit !== 0) {
|
||||||
$this->limit($limit, $offset);
|
$this->limit($limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1760,6 +1761,8 @@ class BaseBuilder
|
|||||||
/**
|
/**
|
||||||
* Compiles batch insert/update/upsert strings and runs the queries
|
* Compiles batch insert/update/upsert strings and runs the queries
|
||||||
*
|
*
|
||||||
|
* @param '_deleteBatch'|'_insertBatch'|'_updateBatch'|'_upsertBatch' $renderMethod
|
||||||
|
*
|
||||||
* @return false|int|string[] Number of rows inserted or FALSE on failure, SQL array when testMode
|
* @return false|int|string[] Number of rows inserted or FALSE on failure, SQL array when testMode
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
@ -1967,11 +1970,9 @@ class BaseBuilder
|
|||||||
*
|
*
|
||||||
* @used-by batchExecute
|
* @used-by batchExecute
|
||||||
*
|
*
|
||||||
* @param string $table Protected table name
|
* @param string $table Protected table name
|
||||||
* @param string[] $keys QBKeys
|
* @param list<string> $keys QBKeys
|
||||||
* @phpstan-param list<string> $keys QBKeys
|
* @param list<list<int|string>> $values QBSet
|
||||||
* @param array<array<int|string>> $values QBSet
|
|
||||||
* @phpstan-param list<list<string|int>> $values QBSet
|
|
||||||
*/
|
*/
|
||||||
protected function _upsertBatch(string $table, array $keys, array $values): string
|
protected function _upsertBatch(string $table, array $keys, array $values): string
|
||||||
{
|
{
|
||||||
@ -2196,11 +2197,9 @@ class BaseBuilder
|
|||||||
*
|
*
|
||||||
* @used-by batchExecute
|
* @used-by batchExecute
|
||||||
*
|
*
|
||||||
* @param string $table Protected table name
|
* @param string $table Protected table name
|
||||||
* @param string[] $keys QBKeys
|
* @param list<string> $keys QBKeys
|
||||||
* @phpstan-param list<string> $keys QBKeys
|
* @param list<list<int|string>> $values QBSet
|
||||||
* @param array<array<int|string>> $values QBSet
|
|
||||||
* @phpstan-param list<list<string|int>> $values QBSet
|
|
||||||
*/
|
*/
|
||||||
protected function _insertBatch(string $table, array $keys, array $values): string
|
protected function _insertBatch(string $table, array $keys, array $values): string
|
||||||
{
|
{
|
||||||
@ -2277,7 +2276,7 @@ class BaseBuilder
|
|||||||
*
|
*
|
||||||
* @param array|object|null $set
|
* @param array|object|null $set
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return BaseResult|bool|Query
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
@ -2459,7 +2458,7 @@ class BaseBuilder
|
|||||||
$this->where($where);
|
$this->where($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($limit)) {
|
if ($limit !== null && $limit !== 0) {
|
||||||
if (! $this->canLimitWhereUpdates) {
|
if (! $this->canLimitWhereUpdates) {
|
||||||
throw new DatabaseException('This driver does not allow LIMITs on UPDATE queries using WHERE.');
|
throw new DatabaseException('This driver does not allow LIMITs on UPDATE queries using WHERE.');
|
||||||
}
|
}
|
||||||
@ -2566,11 +2565,9 @@ class BaseBuilder
|
|||||||
*
|
*
|
||||||
* @used-by batchExecute
|
* @used-by batchExecute
|
||||||
*
|
*
|
||||||
* @param string $table Protected table name
|
* @param string $table Protected table name
|
||||||
* @param string[] $keys QBKeys
|
* @param list<string> $keys QBKeys
|
||||||
* @phpstan-param list<string> $keys QBKeys
|
* @param list<list<int|string>> $values QBSet
|
||||||
* @param array[] $values QBSet
|
|
||||||
* @phpstan-param list<list<string|int>> $values QBSet
|
|
||||||
*/
|
*/
|
||||||
protected function _updateBatch(string $table, array $keys, array $values): string
|
protected function _updateBatch(string $table, array $keys, array $values): string
|
||||||
{
|
{
|
||||||
@ -2747,9 +2744,9 @@ class BaseBuilder
|
|||||||
/**
|
/**
|
||||||
* Compiles a delete string and runs the query
|
* Compiles a delete string and runs the query
|
||||||
*
|
*
|
||||||
* @param mixed $where
|
* @param array|RawSql|string $where
|
||||||
*
|
*
|
||||||
* @return bool|string Returns a string if in test mode.
|
* @return bool|string Returns a SQL string if in test mode.
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
@ -2771,7 +2768,7 @@ class BaseBuilder
|
|||||||
|
|
||||||
$sql = $this->_delete($this->removeAlias($table));
|
$sql = $this->_delete($this->removeAlias($table));
|
||||||
|
|
||||||
if (! empty($limit)) {
|
if ($limit !== null && $limit !== 0) {
|
||||||
$this->QBLimit = $limit;
|
$this->QBLimit = $limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2830,11 +2827,9 @@ class BaseBuilder
|
|||||||
*
|
*
|
||||||
* @used-by batchExecute
|
* @used-by batchExecute
|
||||||
*
|
*
|
||||||
* @param string $table Protected table name
|
* @param string $table Protected table name
|
||||||
* @param string[] $keys QBKeys
|
* @param list<string> $keys QBKeys
|
||||||
* @phpstan-param list<string> $keys QBKeys
|
* @paramst<string|int>> $values QBSet
|
||||||
* @param array<array<int|string>> $values QBSet
|
|
||||||
* @phpstan-param list<list<string|int>> $values QBSet
|
|
||||||
*/
|
*/
|
||||||
protected function _deleteBatch(string $table, array $keys, array $values): string
|
protected function _deleteBatch(string $table, array $keys, array $values): string
|
||||||
{
|
{
|
||||||
@ -3183,7 +3178,7 @@ class BaseBuilder
|
|||||||
*/
|
*/
|
||||||
protected function compileOrderBy(): string
|
protected function compileOrderBy(): string
|
||||||
{
|
{
|
||||||
if (is_array($this->QBOrderBy) && ! empty($this->QBOrderBy)) {
|
if (is_array($this->QBOrderBy) && $this->QBOrderBy !== []) {
|
||||||
foreach ($this->QBOrderBy as &$orderBy) {
|
foreach ($this->QBOrderBy as &$orderBy) {
|
||||||
if ($orderBy['escape'] !== false && ! $this->isLiteral($orderBy['field'])) {
|
if ($orderBy['escape'] !== false && ! $this->isLiteral($orderBy['field'])) {
|
||||||
$orderBy['field'] = $this->db->protectIdentifiers($orderBy['field']);
|
$orderBy['field'] = $this->db->protectIdentifiers($orderBy['field']);
|
||||||
@ -3276,7 +3271,7 @@ class BaseBuilder
|
|||||||
{
|
{
|
||||||
$str = trim($str);
|
$str = trim($str);
|
||||||
|
|
||||||
if (empty($str)
|
if ($str === ''
|
||||||
|| ctype_digit($str)
|
|| ctype_digit($str)
|
||||||
|| (string) (float) $str === $str
|
|| (string) (float) $str === $str
|
||||||
|| in_array(strtoupper($str), ['TRUE', 'FALSE'], true)
|
|| in_array(strtoupper($str), ['TRUE', 'FALSE'], true)
|
||||||
@ -3412,8 +3407,7 @@ class BaseBuilder
|
|||||||
/**
|
/**
|
||||||
* Returns the SQL string operator from where key
|
* Returns the SQL string operator from where key
|
||||||
*
|
*
|
||||||
* @return array<int, string>|false
|
* @return false|list<string>
|
||||||
* @phpstan-return list<string>|false
|
|
||||||
*/
|
*/
|
||||||
private function getOperatorFromWhereKey(string $whereKey)
|
private function getOperatorFromWhereKey(string $whereKey)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -174,7 +174,7 @@ abstract class BaseResult implements ResultInterface
|
|||||||
*/
|
*/
|
||||||
public function getResultArray(): array
|
public function getResultArray(): array
|
||||||
{
|
{
|
||||||
if (! empty($this->resultArray)) {
|
if ($this->resultArray !== []) {
|
||||||
return $this->resultArray;
|
return $this->resultArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ abstract class BaseResult implements ResultInterface
|
|||||||
*/
|
*/
|
||||||
public function getResultObject(): array
|
public function getResultObject(): array
|
||||||
{
|
{
|
||||||
if (! empty($this->resultObject)) {
|
if ($this->resultObject !== []) {
|
||||||
return $this->resultObject;
|
return $this->resultObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,14 +254,16 @@ abstract class BaseResult implements ResultInterface
|
|||||||
*
|
*
|
||||||
* If row doesn't exist, returns null.
|
* If row doesn't exist, returns null.
|
||||||
*
|
*
|
||||||
* @param int $n The index of the results to return
|
* @param int|string $n The index of the results to return, or column name.
|
||||||
* @param string $type The type of result object. 'array', 'object' or class name.
|
* @param string $type The type of result object. 'array', 'object' or class name.
|
||||||
|
* @phpstan-param class-string|'array'|'object' $type
|
||||||
*
|
*
|
||||||
* @return array|object|stdClass|null
|
* @return array|object|stdClass|null
|
||||||
* @phpstan-return ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : object|null))
|
* @phpstan-return ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : object|null))
|
||||||
*/
|
*/
|
||||||
public function getRow($n = 0, string $type = 'object')
|
public function getRow($n = 0, string $type = 'object')
|
||||||
{
|
{
|
||||||
|
// $n is a column name.
|
||||||
if (! is_numeric($n)) {
|
if (! is_numeric($n)) {
|
||||||
// We cache the row data for subsequent uses
|
// We cache the row data for subsequent uses
|
||||||
if (! is_array($this->rowData)) {
|
if (! is_array($this->rowData)) {
|
||||||
@ -321,7 +323,7 @@ abstract class BaseResult implements ResultInterface
|
|||||||
public function getRowArray(int $n = 0)
|
public function getRowArray(int $n = 0)
|
||||||
{
|
{
|
||||||
$result = $this->getResultArray();
|
$result = $this->getResultArray();
|
||||||
if (empty($result)) {
|
if ($result === []) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,7 +344,7 @@ abstract class BaseResult implements ResultInterface
|
|||||||
public function getRowObject(int $n = 0)
|
public function getRowObject(int $n = 0)
|
||||||
{
|
{
|
||||||
$result = $this->getResultObject();
|
$result = $this->getResultObject();
|
||||||
if (empty($result)) {
|
if ($result === []) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +392,7 @@ abstract class BaseResult implements ResultInterface
|
|||||||
{
|
{
|
||||||
$result = $this->getResult($type);
|
$result = $this->getResult($type);
|
||||||
|
|
||||||
return (empty($result)) ? null : $result[0];
|
return ($result === []) ? null : $result[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -402,7 +404,7 @@ abstract class BaseResult implements ResultInterface
|
|||||||
{
|
{
|
||||||
$result = $this->getResult($type);
|
$result = $this->getResult($type);
|
||||||
|
|
||||||
return (empty($result)) ? null : $result[count($result) - 1];
|
return ($result === []) ? null : $result[count($result) - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -413,7 +415,7 @@ abstract class BaseResult implements ResultInterface
|
|||||||
public function getNextRow(string $type = 'object')
|
public function getNextRow(string $type = 'object')
|
||||||
{
|
{
|
||||||
$result = $this->getResult($type);
|
$result = $this->getResult($type);
|
||||||
if (empty($result)) {
|
if ($result === []) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,7 +430,7 @@ abstract class BaseResult implements ResultInterface
|
|||||||
public function getPreviousRow(string $type = 'object')
|
public function getPreviousRow(string $type = 'object')
|
||||||
{
|
{
|
||||||
$result = $this->getResult($type);
|
$result = $this->getResult($type);
|
||||||
if (empty($result)) {
|
if ($result === []) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,10 +41,9 @@ class Config extends BaseConfig
|
|||||||
/**
|
/**
|
||||||
* Returns the database connection
|
* Returns the database connection
|
||||||
*
|
*
|
||||||
* @param array|BaseConnection|string|null $group The name of the connection group to use,
|
* @param array|BaseConnection|non-empty-string|null $group The name of the connection group to use,
|
||||||
* or an array of configuration settings.
|
* or an array of configuration settings.
|
||||||
* @phpstan-param array|BaseConnection|non-empty-string|null $group
|
* @param bool $getShared Whether to return a shared instance of the connection.
|
||||||
* @param bool $getShared Whether to return a shared instance of the connection.
|
|
||||||
*
|
*
|
||||||
* @return BaseConnection
|
* @return BaseConnection
|
||||||
*/
|
*/
|
||||||
@ -127,7 +126,7 @@ class Config extends BaseConfig
|
|||||||
/**
|
/**
|
||||||
* Returns a new instance of the Database Seeder.
|
* Returns a new instance of the Database Seeder.
|
||||||
*
|
*
|
||||||
* @phpstan-param null|non-empty-string $group
|
* @param non-empty-string|null $group
|
||||||
*
|
*
|
||||||
* @return Seeder
|
* @return Seeder
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -104,7 +104,7 @@ class Database
|
|||||||
'database' => isset($dsn['path']) ? rawurldecode(substr($dsn['path'], 1)) : '',
|
'database' => isset($dsn['path']) ? rawurldecode(substr($dsn['path'], 1)) : '',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (! empty($dsn['query'])) {
|
if (isset($dsn['query']) && ($dsn['query'] !== '')) {
|
||||||
parse_str($dsn['query'], $extra);
|
parse_str($dsn['query'], $extra);
|
||||||
|
|
||||||
foreach ($extra as $key => $val) {
|
foreach ($extra as $key => $val) {
|
||||||
|
|||||||
@ -32,14 +32,14 @@ class Forge
|
|||||||
/**
|
/**
|
||||||
* List of fields.
|
* List of fields.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, array|string> [name => attributes]
|
||||||
*/
|
*/
|
||||||
protected $fields = [];
|
protected $fields = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of keys.
|
* List of keys.
|
||||||
*
|
*
|
||||||
* @phpstan-var array{}|list<array{fields: string[], keyName: string}>
|
* @var list<array{fields?: string[], keyName?: string}>
|
||||||
*/
|
*/
|
||||||
protected $keys = [];
|
protected $keys = [];
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ class Forge
|
|||||||
/**
|
/**
|
||||||
* Primary keys.
|
* Primary keys.
|
||||||
*
|
*
|
||||||
* @phpstan-var array{}|array{fields: string[], keyName: string}
|
* @var array{fields?: string[], keyName?: string}
|
||||||
*/
|
*/
|
||||||
protected $primaryKeys = [];
|
protected $primaryKeys = [];
|
||||||
|
|
||||||
@ -351,14 +351,14 @@ class Forge
|
|||||||
/**
|
/**
|
||||||
* Add Field
|
* Add Field
|
||||||
*
|
*
|
||||||
* @param array|string $field
|
* @param array<string, array|string>|string $fields Field array or Field string
|
||||||
*
|
*
|
||||||
* @return Forge
|
* @return Forge
|
||||||
*/
|
*/
|
||||||
public function addField($field)
|
public function addField($fields)
|
||||||
{
|
{
|
||||||
if (is_string($field)) {
|
if (is_string($fields)) {
|
||||||
if ($field === 'id') {
|
if ($fields === 'id') {
|
||||||
$this->addField([
|
$this->addField([
|
||||||
'id' => [
|
'id' => [
|
||||||
'type' => 'INT',
|
'type' => 'INT',
|
||||||
@ -368,27 +368,27 @@ class Forge
|
|||||||
]);
|
]);
|
||||||
$this->addKey('id', true);
|
$this->addKey('id', true);
|
||||||
} else {
|
} else {
|
||||||
if (strpos($field, ' ') === false) {
|
if (strpos($fields, ' ') === false) {
|
||||||
throw new InvalidArgumentException('Field information is required for that operation.');
|
throw new InvalidArgumentException('Field information is required for that operation.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$fieldName = explode(' ', $field, 2)[0];
|
$fieldName = explode(' ', $fields, 2)[0];
|
||||||
$fieldName = trim($fieldName, '`\'"');
|
$fieldName = trim($fieldName, '`\'"');
|
||||||
|
|
||||||
$this->fields[$fieldName] = $field;
|
$this->fields[$fieldName] = $fields;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($field)) {
|
if (is_array($fields)) {
|
||||||
foreach ($field as $idx => $f) {
|
foreach ($fields as $name => $attributes) {
|
||||||
if (is_string($f)) {
|
if (is_string($attributes)) {
|
||||||
$this->addField($f);
|
$this->addField($attributes);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($f)) {
|
if (is_array($attributes)) {
|
||||||
$this->fields = array_merge($this->fields, [$idx => $f]);
|
$this->fields = array_merge($this->fields, [$name => $attributes]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,8 +404,14 @@ class Forge
|
|||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
public function addForeignKey($fieldName = '', string $tableName = '', $tableField = '', string $onUpdate = '', string $onDelete = '', string $fkName = ''): Forge
|
public function addForeignKey(
|
||||||
{
|
$fieldName = '',
|
||||||
|
string $tableName = '',
|
||||||
|
$tableField = '',
|
||||||
|
string $onUpdate = '',
|
||||||
|
string $onDelete = '',
|
||||||
|
string $fkName = ''
|
||||||
|
): Forge {
|
||||||
$fieldName = (array) $fieldName;
|
$fieldName = (array) $fieldName;
|
||||||
$tableField = (array) $tableField;
|
$tableField = (array) $tableField;
|
||||||
|
|
||||||
@ -428,8 +434,9 @@ class Forge
|
|||||||
*/
|
*/
|
||||||
public function dropKey(string $table, string $keyName, bool $prefixKeyName = true): bool
|
public function dropKey(string $table, string $keyName, bool $prefixKeyName = true): bool
|
||||||
{
|
{
|
||||||
$keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->DBPrefix : '') . $keyName);
|
$keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->DBPrefix : '') . $keyName);
|
||||||
$table = $this->db->escapeIdentifiers($this->db->DBPrefix . $table);
|
$table = $this->db->escapeIdentifiers($this->db->DBPrefix . $table);
|
||||||
|
|
||||||
$dropKeyAsConstraint = $this->dropKeyAsConstraint($table, $keyName);
|
$dropKeyAsConstraint = $this->dropKeyAsConstraint($table, $keyName);
|
||||||
|
|
||||||
if ($dropKeyAsConstraint === true) {
|
if ($dropKeyAsConstraint === true) {
|
||||||
@ -458,7 +465,7 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if if key needs to be dropped as a constraint.
|
* Checks if key needs to be dropped as a constraint.
|
||||||
*/
|
*/
|
||||||
protected function dropKeyAsConstraint(string $table, string $constraintName): bool
|
protected function dropKeyAsConstraint(string $table, string $constraintName): bool
|
||||||
{
|
{
|
||||||
@ -494,7 +501,7 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BaseResult|bool|false|mixed|Query
|
* @return bool
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
@ -518,7 +525,9 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @param array $attributes Table attributes
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
@ -562,28 +571,30 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param array $attributes Table attributes
|
||||||
|
*
|
||||||
* @return string SQL string
|
* @return string SQL string
|
||||||
*
|
*
|
||||||
* @deprecated $ifNotExists is no longer used, and will be removed.
|
* @deprecated $ifNotExists is no longer used, and will be removed.
|
||||||
*/
|
*/
|
||||||
protected function _createTable(string $table, bool $ifNotExists, array $attributes)
|
protected function _createTable(string $table, bool $ifNotExists, array $attributes)
|
||||||
{
|
{
|
||||||
$columns = $this->_processFields(true);
|
$processedFields = $this->_processFields(true);
|
||||||
|
|
||||||
for ($i = 0, $c = count($columns); $i < $c; $i++) {
|
for ($i = 0, $c = count($processedFields); $i < $c; $i++) {
|
||||||
$columns[$i] = ($columns[$i]['_literal'] !== false) ? "\n\t" . $columns[$i]['_literal']
|
$processedFields[$i] = ($processedFields[$i]['_literal'] !== false) ? "\n\t" . $processedFields[$i]['_literal']
|
||||||
: "\n\t" . $this->_processColumn($columns[$i]);
|
: "\n\t" . $this->_processColumn($processedFields[$i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$columns = implode(',', $columns);
|
$processedFields = implode(',', $processedFields);
|
||||||
|
|
||||||
$columns .= $this->_processPrimaryKeys($table);
|
$processedFields .= $this->_processPrimaryKeys($table);
|
||||||
$columns .= current($this->_processForeignKeys($table));
|
$processedFields .= current($this->_processForeignKeys($table));
|
||||||
|
|
||||||
if ($this->createTableKeys === true) {
|
if ($this->createTableKeys === true) {
|
||||||
$indexes = current($this->_processIndexes($table));
|
$indexes = current($this->_processIndexes($table));
|
||||||
if (is_string($indexes)) {
|
if (is_string($indexes)) {
|
||||||
$columns .= $indexes;
|
$processedFields .= $indexes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,7 +602,7 @@ class Forge
|
|||||||
$this->createTableStr . '%s',
|
$this->createTableStr . '%s',
|
||||||
'CREATE TABLE',
|
'CREATE TABLE',
|
||||||
$this->db->escapeIdentifiers($table),
|
$this->db->escapeIdentifiers($table),
|
||||||
$columns,
|
$processedFields,
|
||||||
$this->_createTableAttributes($attributes)
|
$this->_createTableAttributes($attributes)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -610,7 +621,7 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return bool
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
@ -676,7 +687,7 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return bool
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
@ -716,23 +727,24 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|string $field
|
* @param array<string, array|string>|string $fields Field array or Field string
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
public function addColumn(string $table, $field): bool
|
public function addColumn(string $table, $fields): bool
|
||||||
{
|
{
|
||||||
// Work-around for literal column definitions
|
// Work-around for literal column definitions
|
||||||
if (! is_array($field)) {
|
if (is_string($fields)) {
|
||||||
$field = [$field];
|
$fields = [$fields];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array_keys($field) as $k) {
|
foreach (array_keys($fields) as $name) {
|
||||||
$this->addField([$k => $field[$k]]);
|
$this->addField([$name => $fields[$name]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sqls = $this->_alterTable('ADD', $this->db->DBPrefix . $table, $this->_processFields());
|
$sqls = $this->_alterTable('ADD', $this->db->DBPrefix . $table, $this->_processFields());
|
||||||
$this->reset();
|
$this->reset();
|
||||||
|
|
||||||
if ($sqls === false) {
|
if ($sqls === false) {
|
||||||
if ($this->db->DBDebug) {
|
if ($this->db->DBDebug) {
|
||||||
throw new DatabaseException('This feature is not available for the database you are using.');
|
throw new DatabaseException('This feature is not available for the database you are using.');
|
||||||
@ -751,15 +763,16 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|string $columnName
|
* @param array|string $columnNames column names to DROP
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return bool
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
public function dropColumn(string $table, $columnName)
|
public function dropColumn(string $table, $columnNames)
|
||||||
{
|
{
|
||||||
$sql = $this->_alterTable('DROP', $this->db->DBPrefix . $table, $columnName);
|
$sql = $this->_alterTable('DROP', $this->db->DBPrefix . $table, $columnNames);
|
||||||
|
|
||||||
if ($sql === false) {
|
if ($sql === false) {
|
||||||
if ($this->db->DBDebug) {
|
if ($this->db->DBDebug) {
|
||||||
throw new DatabaseException('This feature is not available for the database you are using.');
|
throw new DatabaseException('This feature is not available for the database you are using.');
|
||||||
@ -772,19 +785,19 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|string $field
|
* @param array<string, array|string>|string $fields Field array or Field string
|
||||||
*
|
*
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
public function modifyColumn(string $table, $field): bool
|
public function modifyColumn(string $table, $fields): bool
|
||||||
{
|
{
|
||||||
// Work-around for literal column definitions
|
// Work-around for literal column definitions
|
||||||
if (! is_array($field)) {
|
if (is_string($fields)) {
|
||||||
$field = [$field];
|
$fields = [$fields];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array_keys($field) as $k) {
|
foreach (array_keys($fields) as $name) {
|
||||||
$this->addField([$k => $field[$k]]);
|
$this->addField([$name => $fields[$name]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->fields === []) {
|
if ($this->fields === []) {
|
||||||
@ -793,6 +806,7 @@ class Forge
|
|||||||
|
|
||||||
$sqls = $this->_alterTable('CHANGE', $this->db->DBPrefix . $table, $this->_processFields());
|
$sqls = $this->_alterTable('CHANGE', $this->db->DBPrefix . $table, $this->_processFields());
|
||||||
$this->reset();
|
$this->reset();
|
||||||
|
|
||||||
if ($sqls === false) {
|
if ($sqls === false) {
|
||||||
if ($this->db->DBDebug) {
|
if ($this->db->DBDebug) {
|
||||||
throw new DatabaseException('This feature is not available for the database you are using.');
|
throw new DatabaseException('This feature is not available for the database you are using.');
|
||||||
@ -813,48 +827,53 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|string $fields
|
* @param 'ADD'|'CHANGE'|'DROP' $alterType
|
||||||
|
* @param array|string $processedFields Processed column definitions
|
||||||
|
* or column names to DROP
|
||||||
*
|
*
|
||||||
* @return false|string|string[]
|
* @return false|list<string>|string|null SQL string
|
||||||
|
* @phpstan-return ($alterType is 'DROP' ? string : list<string>|false|null)
|
||||||
*/
|
*/
|
||||||
protected function _alterTable(string $alterType, string $table, $fields)
|
protected function _alterTable(string $alterType, string $table, $processedFields)
|
||||||
{
|
{
|
||||||
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table) . ' ';
|
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table) . ' ';
|
||||||
|
|
||||||
// DROP has everything it needs now.
|
// DROP has everything it needs now.
|
||||||
if ($alterType === 'DROP') {
|
if ($alterType === 'DROP') {
|
||||||
if (is_string($fields)) {
|
$columnNamesToDrop = $processedFields;
|
||||||
$fields = explode(',', $fields);
|
|
||||||
|
if (is_string($columnNamesToDrop)) {
|
||||||
|
$columnNamesToDrop = explode(',', $columnNamesToDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields = array_map(fn ($field) => 'DROP COLUMN ' . $this->db->escapeIdentifiers(trim($field)), $fields);
|
$columnNamesToDrop = array_map(fn ($field) => 'DROP COLUMN ' . $this->db->escapeIdentifiers(trim($field)), $columnNamesToDrop);
|
||||||
|
|
||||||
return $sql . implode(', ', $fields);
|
return $sql . implode(', ', $columnNamesToDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql .= ($alterType === 'ADD') ? 'ADD ' : $alterType . ' COLUMN ';
|
$sql .= ($alterType === 'ADD') ? 'ADD ' : $alterType . ' COLUMN ';
|
||||||
|
|
||||||
$sqls = [];
|
$sqls = [];
|
||||||
|
|
||||||
foreach ($fields as $data) {
|
foreach ($processedFields as $field) {
|
||||||
$sqls[] = $sql . ($data['_literal'] !== false
|
$sqls[] = $sql . ($field['_literal'] !== false
|
||||||
? $data['_literal']
|
? $field['_literal']
|
||||||
: $this->_processColumn($data));
|
: $this->_processColumn($field));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sqls;
|
return $sqls;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process fields
|
* Returns $processedFields array from $this->fields data.
|
||||||
*/
|
*/
|
||||||
protected function _processFields(bool $createTable = false): array
|
protected function _processFields(bool $createTable = false): array
|
||||||
{
|
{
|
||||||
$fields = [];
|
$processedFields = [];
|
||||||
|
|
||||||
foreach ($this->fields as $key => $attributes) {
|
foreach ($this->fields as $name => $attributes) {
|
||||||
if (! is_array($attributes)) {
|
if (! is_array($attributes)) {
|
||||||
$fields[] = ['_literal' => $attributes];
|
$processedFields[] = ['_literal' => $attributes];
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -870,7 +889,7 @@ class Forge
|
|||||||
}
|
}
|
||||||
|
|
||||||
$field = [
|
$field = [
|
||||||
'name' => $key,
|
'name' => $name,
|
||||||
'new_name' => $attributes['NAME'] ?? null,
|
'new_name' => $attributes['NAME'] ?? null,
|
||||||
'type' => $attributes['TYPE'] ?? null,
|
'type' => $attributes['TYPE'] ?? null,
|
||||||
'length' => '',
|
'length' => '',
|
||||||
@ -928,24 +947,24 @@ class Forge
|
|||||||
$field['length'] = '(' . $attributes['CONSTRAINT'] . ')';
|
$field['length'] = '(' . $attributes['CONSTRAINT'] . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields[] = $field;
|
$processedFields[] = $field;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $fields;
|
return $processedFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process column
|
* Converts $processedField array to field definition string.
|
||||||
*/
|
*/
|
||||||
protected function _processColumn(array $field): string
|
protected function _processColumn(array $processedField): string
|
||||||
{
|
{
|
||||||
return $this->db->escapeIdentifiers($field['name'])
|
return $this->db->escapeIdentifiers($processedField['name'])
|
||||||
. ' ' . $field['type'] . $field['length']
|
. ' ' . $processedField['type'] . $processedField['length']
|
||||||
. $field['unsigned']
|
. $processedField['unsigned']
|
||||||
. $field['default']
|
. $processedField['default']
|
||||||
. $field['null']
|
. $processedField['null']
|
||||||
. $field['auto_increment']
|
. $processedField['auto_increment']
|
||||||
. $field['unique'];
|
. $processedField['unique'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1163,10 +1182,10 @@ class Forge
|
|||||||
{
|
{
|
||||||
$errorNames = [];
|
$errorNames = [];
|
||||||
|
|
||||||
foreach ($this->foreignKeys as $name) {
|
foreach ($this->foreignKeys as $fkeyInfo) {
|
||||||
foreach ($name['field'] as $f) {
|
foreach ($fkeyInfo['field'] as $fieldName) {
|
||||||
if (! isset($this->fields[$f])) {
|
if (! isset($this->fields[$fieldName])) {
|
||||||
$errorNames[] = $f;
|
$errorNames[] = $fieldName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ abstract class Migration
|
|||||||
/**
|
/**
|
||||||
* The name of the database group to use.
|
* The name of the database group to use.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string|null
|
||||||
*/
|
*/
|
||||||
protected $DBGroup;
|
protected $DBGroup;
|
||||||
|
|
||||||
@ -39,12 +39,15 @@ abstract class Migration
|
|||||||
*/
|
*/
|
||||||
protected $forge;
|
protected $forge;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*/
|
|
||||||
public function __construct(?Forge $forge = null)
|
public function __construct(?Forge $forge = null)
|
||||||
{
|
{
|
||||||
$this->forge = $forge ?? Database::forge($this->DBGroup ?? config(Database::class)->defaultGroup);
|
if (isset($this->DBGroup)) {
|
||||||
|
$this->forge = Database::forge($this->DBGroup);
|
||||||
|
} elseif ($forge !== null) {
|
||||||
|
$this->forge = $forge;
|
||||||
|
} else {
|
||||||
|
$this->forge = Database::forge(config(Database::class)->defaultGroup);
|
||||||
|
}
|
||||||
|
|
||||||
$this->db = $this->forge->getConnection();
|
$this->db = $this->forge->getConnection();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,14 +122,11 @@ class MigrationRunner
|
|||||||
protected $groupSkip = false;
|
protected $groupSkip = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* The migration can manage multiple databases. So it should always use the
|
||||||
|
* default DB group so that it creates the `migrations` table in the default
|
||||||
|
* DB group. Therefore, passing $db is for testing purposes only.
|
||||||
*
|
*
|
||||||
* When passing in $db, you may pass any of the following to connect:
|
* @param array|ConnectionInterface|string|null $db DB group. For testing purposes only.
|
||||||
* - group name
|
|
||||||
* - existing connection instance
|
|
||||||
* - array of database configuration values
|
|
||||||
*
|
|
||||||
* @param array|ConnectionInterface|string|null $db
|
|
||||||
*
|
*
|
||||||
* @throws ConfigException
|
* @throws ConfigException
|
||||||
*/
|
*/
|
||||||
@ -138,16 +135,12 @@ class MigrationRunner
|
|||||||
$this->enabled = $config->enabled ?? false;
|
$this->enabled = $config->enabled ?? false;
|
||||||
$this->table = $config->table ?? 'migrations';
|
$this->table = $config->table ?? 'migrations';
|
||||||
|
|
||||||
// Default name space is the app namespace
|
|
||||||
$this->namespace = APP_NAMESPACE;
|
$this->namespace = APP_NAMESPACE;
|
||||||
|
|
||||||
// get default database group
|
// Even if a DB connection is passed, since it is a test,
|
||||||
$config = config(Database::class);
|
// it is assumed to use the default group name
|
||||||
$this->group = $config->defaultGroup;
|
$this->group = is_string($db) ? $db : config(Database::class)->defaultGroup;
|
||||||
unset($config);
|
|
||||||
|
|
||||||
// If no db connection passed in, use
|
|
||||||
// default database group.
|
|
||||||
$this->db = db_connect($db);
|
$this->db = db_connect($db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +167,7 @@ class MigrationRunner
|
|||||||
|
|
||||||
$migrations = $this->findMigrations();
|
$migrations = $this->findMigrations();
|
||||||
|
|
||||||
if (empty($migrations)) {
|
if ($migrations === []) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +235,7 @@ class MigrationRunner
|
|||||||
$targetBatch = $batches[count($batches) - 1 + $targetBatch] ?? 0;
|
$targetBatch = $batches[count($batches) - 1 + $targetBatch] ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($batches) && $targetBatch === 0) {
|
if ($batches === [] && $targetBatch === 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,7 +639,7 @@ class MigrationRunner
|
|||||||
$builder = $this->db->table($this->table);
|
$builder = $this->db->table($this->table);
|
||||||
|
|
||||||
// If group was specified then use it
|
// If group was specified then use it
|
||||||
if (! empty($group)) {
|
if ($group !== '') {
|
||||||
$builder->where('group', $group);
|
$builder->where('group', $group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,8 +832,9 @@ class MigrationRunner
|
|||||||
throw new RuntimeException($message);
|
throw new RuntimeException($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
$instance = new $class();
|
/** @var Migration $instance */
|
||||||
$group = $instance->getDBGroup() ?? config(Database::class)->defaultGroup;
|
$instance = new $class(Database::forge($this->db));
|
||||||
|
$group = $instance->getDBGroup() ?? $this->group;
|
||||||
|
|
||||||
if (ENVIRONMENT !== 'testing' && $group === 'tests' && $this->groupFilter !== 'tests') {
|
if (ENVIRONMENT !== 'testing' && $group === 'tests' && $this->groupFilter !== 'tests') {
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
@ -856,8 +850,6 @@ class MigrationRunner
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setGroup($group);
|
|
||||||
|
|
||||||
if (! is_callable([$instance, $direction])) {
|
if (! is_callable([$instance, $direction])) {
|
||||||
$message = sprintf(lang('Migrations.missingMethod'), $direction);
|
$message = sprintf(lang('Migrations.missingMethod'), $direction);
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class Builder extends BaseBuilder
|
|||||||
*/
|
*/
|
||||||
protected function _fromTables(): string
|
protected function _fromTables(): string
|
||||||
{
|
{
|
||||||
if (! empty($this->QBJoin) && count($this->QBFrom) > 1) {
|
if ($this->QBJoin !== [] && count($this->QBFrom) > 1) {
|
||||||
return '(' . implode(', ', $this->QBFrom) . ')';
|
return '(' . implode(', ', $this->QBFrom) . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -150,7 +150,7 @@ class Connection extends BaseConnection
|
|||||||
$ssl['cipher'] = $this->encrypt['ssl_cipher'];
|
$ssl['cipher'] = $this->encrypt['ssl_cipher'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($ssl)) {
|
if ($ssl !== []) {
|
||||||
if (isset($this->encrypt['ssl_verify'])) {
|
if (isset($this->encrypt['ssl_verify'])) {
|
||||||
if ($this->encrypt['ssl_verify']) {
|
if ($this->encrypt['ssl_verify']) {
|
||||||
if (defined('MYSQLI_OPT_SSL_VERIFY_SERVER_CERT')) {
|
if (defined('MYSQLI_OPT_SSL_VERIFY_SERVER_CERT')) {
|
||||||
|
|||||||
@ -128,57 +128,59 @@ class Forge extends BaseForge
|
|||||||
/**
|
/**
|
||||||
* ALTER TABLE
|
* ALTER TABLE
|
||||||
*
|
*
|
||||||
* @param string $alterType ALTER type
|
* @param string $alterType ALTER type
|
||||||
* @param string $table Table name
|
* @param string $table Table name
|
||||||
* @param array|string $field Column definition
|
* @param array|string $processedFields Processed column definitions
|
||||||
|
* or column names to DROP
|
||||||
*
|
*
|
||||||
* @return string|string[]
|
* @return list<string>|string SQL string
|
||||||
|
* @phpstan-return ($alterType is 'DROP' ? string : list<string>)
|
||||||
*/
|
*/
|
||||||
protected function _alterTable(string $alterType, string $table, $field)
|
protected function _alterTable(string $alterType, string $table, $processedFields)
|
||||||
{
|
{
|
||||||
if ($alterType === 'DROP') {
|
if ($alterType === 'DROP') {
|
||||||
return parent::_alterTable($alterType, $table, $field);
|
return parent::_alterTable($alterType, $table, $processedFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table);
|
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table);
|
||||||
|
|
||||||
foreach ($field as $i => $data) {
|
foreach ($processedFields as $i => $field) {
|
||||||
if ($data['_literal'] !== false) {
|
if ($field['_literal'] !== false) {
|
||||||
$field[$i] = ($alterType === 'ADD') ? "\n\tADD " . $data['_literal'] : "\n\tMODIFY " . $data['_literal'];
|
$processedFields[$i] = ($alterType === 'ADD') ? "\n\tADD " . $field['_literal'] : "\n\tMODIFY " . $field['_literal'];
|
||||||
} else {
|
} else {
|
||||||
if ($alterType === 'ADD') {
|
if ($alterType === 'ADD') {
|
||||||
$field[$i]['_literal'] = "\n\tADD ";
|
$processedFields[$i]['_literal'] = "\n\tADD ";
|
||||||
} else {
|
} else {
|
||||||
$field[$i]['_literal'] = empty($data['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE ";
|
$processedFields[$i]['_literal'] = empty($field['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE ";
|
||||||
}
|
}
|
||||||
|
|
||||||
$field[$i] = $field[$i]['_literal'] . $this->_processColumn($field[$i]);
|
$processedFields[$i] = $processedFields[$i]['_literal'] . $this->_processColumn($processedFields[$i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [$sql . implode(',', $field)];
|
return [$sql . implode(',', $processedFields)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process column
|
* Process column
|
||||||
*/
|
*/
|
||||||
protected function _processColumn(array $field): string
|
protected function _processColumn(array $processedField): string
|
||||||
{
|
{
|
||||||
$extraClause = isset($field['after']) ? ' AFTER ' . $this->db->escapeIdentifiers($field['after']) : '';
|
$extraClause = isset($processedField['after']) ? ' AFTER ' . $this->db->escapeIdentifiers($processedField['after']) : '';
|
||||||
|
|
||||||
if (empty($extraClause) && isset($field['first']) && $field['first'] === true) {
|
if (empty($extraClause) && isset($processedField['first']) && $processedField['first'] === true) {
|
||||||
$extraClause = ' FIRST';
|
$extraClause = ' FIRST';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->db->escapeIdentifiers($field['name'])
|
return $this->db->escapeIdentifiers($processedField['name'])
|
||||||
. (empty($field['new_name']) ? '' : ' ' . $this->db->escapeIdentifiers($field['new_name']))
|
. (empty($processedField['new_name']) ? '' : ' ' . $this->db->escapeIdentifiers($processedField['new_name']))
|
||||||
. ' ' . $field['type'] . $field['length']
|
. ' ' . $processedField['type'] . $processedField['length']
|
||||||
. $field['unsigned']
|
. $processedField['unsigned']
|
||||||
. $field['null']
|
. $processedField['null']
|
||||||
. $field['default']
|
. $processedField['default']
|
||||||
. $field['auto_increment']
|
. $processedField['auto_increment']
|
||||||
. $field['unique']
|
. $processedField['unique']
|
||||||
. (empty($field['comment']) ? '' : ' COMMENT ' . $field['comment'])
|
. (empty($processedField['comment']) ? '' : ' COMMENT ' . $processedField['comment'])
|
||||||
. $extraClause;
|
. $extraClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -166,7 +166,7 @@ class Builder extends BaseBuilder
|
|||||||
*/
|
*/
|
||||||
public function delete($where = '', ?int $limit = null, bool $resetData = true)
|
public function delete($where = '', ?int $limit = null, bool $resetData = true)
|
||||||
{
|
{
|
||||||
if (! empty($limit)) {
|
if ($limit !== null && $limit !== 0) {
|
||||||
$this->QBLimit = $limit;
|
$this->QBLimit = $limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -93,21 +93,29 @@ class Forge extends BaseForge
|
|||||||
/**
|
/**
|
||||||
* ALTER TABLE
|
* ALTER TABLE
|
||||||
*
|
*
|
||||||
* @param string $alterType ALTER type
|
* @param string $alterType ALTER type
|
||||||
* @param string $table Table name
|
* @param string $table Table name
|
||||||
* @param array|string $field Column definition
|
* @param array|string $processedFields Processed column definitions
|
||||||
|
* or column names to DROP
|
||||||
*
|
*
|
||||||
* @return string|string[]
|
* @return list<string>|string SQL string
|
||||||
|
* @phpstan-return ($alterType is 'DROP' ? string : list<string>)
|
||||||
*/
|
*/
|
||||||
protected function _alterTable(string $alterType, string $table, $field)
|
protected function _alterTable(string $alterType, string $table, $processedFields)
|
||||||
{
|
{
|
||||||
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table);
|
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table);
|
||||||
|
|
||||||
if ($alterType === 'DROP') {
|
if ($alterType === 'DROP') {
|
||||||
$fields = array_map(fn ($field) => $this->db->escapeIdentifiers(trim($field)), is_string($field) ? explode(',', $field) : $field);
|
$columnNamesToDrop = $processedFields;
|
||||||
|
|
||||||
|
$fields = array_map(
|
||||||
|
fn ($field) => $this->db->escapeIdentifiers(trim($field)),
|
||||||
|
is_string($columnNamesToDrop) ? explode(',', $columnNamesToDrop) : $columnNamesToDrop
|
||||||
|
);
|
||||||
|
|
||||||
return $sql . ' DROP (' . implode(',', $fields) . ') CASCADE CONSTRAINT INVALIDATE';
|
return $sql . ' DROP (' . implode(',', $fields) . ') CASCADE CONSTRAINT INVALIDATE';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($alterType === 'CHANGE') {
|
if ($alterType === 'CHANGE') {
|
||||||
$alterType = 'MODIFY';
|
$alterType = 'MODIFY';
|
||||||
}
|
}
|
||||||
@ -115,50 +123,50 @@ class Forge extends BaseForge
|
|||||||
$nullableMap = array_column($this->db->getFieldData($table), 'nullable', 'name');
|
$nullableMap = array_column($this->db->getFieldData($table), 'nullable', 'name');
|
||||||
$sqls = [];
|
$sqls = [];
|
||||||
|
|
||||||
for ($i = 0, $c = count($field); $i < $c; $i++) {
|
for ($i = 0, $c = count($processedFields); $i < $c; $i++) {
|
||||||
if ($alterType === 'MODIFY') {
|
if ($alterType === 'MODIFY') {
|
||||||
// If a null constraint is added to a column with a null constraint,
|
// If a null constraint is added to a column with a null constraint,
|
||||||
// ORA-01451 will occur,
|
// ORA-01451 will occur,
|
||||||
// so add null constraint is used only when it is different from the current null constraint.
|
// so add null constraint is used only when it is different from the current null constraint.
|
||||||
// If a not null constraint is added to a column with a not null constraint,
|
// If a not null constraint is added to a column with a not null constraint,
|
||||||
// ORA-01442 will occur.
|
// ORA-01442 will occur.
|
||||||
$wantToAddNull = strpos($field[$i]['null'], ' NOT') === false;
|
$wantToAddNull = strpos($processedFields[$i]['null'], ' NOT') === false;
|
||||||
$currentNullable = $nullableMap[$field[$i]['name']];
|
$currentNullable = $nullableMap[$processedFields[$i]['name']];
|
||||||
|
|
||||||
if ($wantToAddNull === true && $currentNullable === true) {
|
if ($wantToAddNull === true && $currentNullable === true) {
|
||||||
$field[$i]['null'] = '';
|
$processedFields[$i]['null'] = '';
|
||||||
} elseif ($field[$i]['null'] === '' && $currentNullable === false) {
|
} elseif ($processedFields[$i]['null'] === '' && $currentNullable === false) {
|
||||||
// Nullable by default
|
// Nullable by default
|
||||||
$field[$i]['null'] = ' NULL';
|
$processedFields[$i]['null'] = ' NULL';
|
||||||
} elseif ($wantToAddNull === false && $currentNullable === false) {
|
} elseif ($wantToAddNull === false && $currentNullable === false) {
|
||||||
$field[$i]['null'] = '';
|
$processedFields[$i]['null'] = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($field[$i]['_literal'] !== false) {
|
if ($processedFields[$i]['_literal'] !== false) {
|
||||||
$field[$i] = "\n\t" . $field[$i]['_literal'];
|
$processedFields[$i] = "\n\t" . $processedFields[$i]['_literal'];
|
||||||
} else {
|
} else {
|
||||||
$field[$i]['_literal'] = "\n\t" . $this->_processColumn($field[$i]);
|
$processedFields[$i]['_literal'] = "\n\t" . $this->_processColumn($processedFields[$i]);
|
||||||
|
|
||||||
if (! empty($field[$i]['comment'])) {
|
if (! empty($processedFields[$i]['comment'])) {
|
||||||
$sqls[] = 'COMMENT ON COLUMN '
|
$sqls[] = 'COMMENT ON COLUMN '
|
||||||
. $this->db->escapeIdentifiers($table) . '.' . $this->db->escapeIdentifiers($field[$i]['name'])
|
. $this->db->escapeIdentifiers($table) . '.' . $this->db->escapeIdentifiers($processedFields[$i]['name'])
|
||||||
. ' IS ' . $field[$i]['comment'];
|
. ' IS ' . $processedFields[$i]['comment'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($alterType === 'MODIFY' && ! empty($field[$i]['new_name'])) {
|
if ($alterType === 'MODIFY' && ! empty($processedFields[$i]['new_name'])) {
|
||||||
$sqls[] = $sql . ' RENAME COLUMN ' . $this->db->escapeIdentifiers($field[$i]['name'])
|
$sqls[] = $sql . ' RENAME COLUMN ' . $this->db->escapeIdentifiers($processedFields[$i]['name'])
|
||||||
. ' TO ' . $this->db->escapeIdentifiers($field[$i]['new_name']);
|
. ' TO ' . $this->db->escapeIdentifiers($processedFields[$i]['new_name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$field[$i] = "\n\t" . $field[$i]['_literal'];
|
$processedFields[$i] = "\n\t" . $processedFields[$i]['_literal'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql .= ' ' . $alterType . ' ';
|
$sql .= ' ' . $alterType . ' ';
|
||||||
$sql .= count($field) === 1
|
$sql .= count($processedFields) === 1
|
||||||
? $field[0]
|
? $processedFields[0]
|
||||||
: '(' . implode(',', $field) . ')';
|
: '(' . implode(',', $processedFields) . ')';
|
||||||
|
|
||||||
// RENAME COLUMN must be executed after MODIFY
|
// RENAME COLUMN must be executed after MODIFY
|
||||||
array_unshift($sqls, $sql);
|
array_unshift($sqls, $sql);
|
||||||
@ -184,26 +192,26 @@ class Forge extends BaseForge
|
|||||||
/**
|
/**
|
||||||
* Process column
|
* Process column
|
||||||
*/
|
*/
|
||||||
protected function _processColumn(array $field): string
|
protected function _processColumn(array $processedField): string
|
||||||
{
|
{
|
||||||
$constraint = '';
|
$constraint = '';
|
||||||
// @todo: can't cover multi pattern when set type.
|
// @todo: can't cover multi pattern when set type.
|
||||||
if ($field['type'] === 'VARCHAR2' && strpos($field['length'], "('") === 0) {
|
if ($processedField['type'] === 'VARCHAR2' && strpos($processedField['length'], "('") === 0) {
|
||||||
$constraint = ' CHECK(' . $this->db->escapeIdentifiers($field['name'])
|
$constraint = ' CHECK(' . $this->db->escapeIdentifiers($processedField['name'])
|
||||||
. ' IN ' . $field['length'] . ')';
|
. ' IN ' . $processedField['length'] . ')';
|
||||||
|
|
||||||
$field['length'] = '(' . max(array_map('mb_strlen', explode("','", mb_substr($field['length'], 2, -2)))) . ')' . $constraint;
|
$processedField['length'] = '(' . max(array_map('mb_strlen', explode("','", mb_substr($processedField['length'], 2, -2)))) . ')' . $constraint;
|
||||||
} elseif (isset($this->primaryKeys['fields']) && count($this->primaryKeys['fields']) === 1 && $field['name'] === $this->primaryKeys['fields'][0]) {
|
} elseif (isset($this->primaryKeys['fields']) && count($this->primaryKeys['fields']) === 1 && $processedField['name'] === $this->primaryKeys['fields'][0]) {
|
||||||
$field['unique'] = '';
|
$processedField['unique'] = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->db->escapeIdentifiers($field['name'])
|
return $this->db->escapeIdentifiers($processedField['name'])
|
||||||
. ' ' . $field['type'] . $field['length']
|
. ' ' . $processedField['type'] . $processedField['length']
|
||||||
. $field['unsigned']
|
. $processedField['unsigned']
|
||||||
. $field['default']
|
. $processedField['default']
|
||||||
. $field['auto_increment']
|
. $processedField['auto_increment']
|
||||||
. $field['null']
|
. $processedField['null']
|
||||||
. $field['unique'];
|
. $processedField['unique'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -246,7 +254,6 @@ class Forge extends BaseForge
|
|||||||
$attributes['TYPE'] = 'NUMBER';
|
$attributes['TYPE'] = 'NUMBER';
|
||||||
$attributes['CONSTRAINT'] = 1;
|
$attributes['CONSTRAINT'] = 1;
|
||||||
$attributes['UNSIGNED'] = true;
|
$attributes['UNSIGNED'] = true;
|
||||||
$attributes['NULL'] = false;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@ -146,7 +146,7 @@ class Builder extends BaseBuilder
|
|||||||
$this->set($set);
|
$this->set($set);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->QBSet) {
|
if ($this->QBSet === []) {
|
||||||
if ($this->db->DBDebug) {
|
if ($this->db->DBDebug) {
|
||||||
throw new DatabaseException('You must use the "set" method to update an entry.');
|
throw new DatabaseException('You must use the "set" method to update an entry.');
|
||||||
}
|
}
|
||||||
@ -229,7 +229,7 @@ class Builder extends BaseBuilder
|
|||||||
*/
|
*/
|
||||||
public function delete($where = '', ?int $limit = null, bool $resetData = true)
|
public function delete($where = '', ?int $limit = null, bool $resetData = true)
|
||||||
{
|
{
|
||||||
if (! empty($limit) || ! empty($this->QBLimit)) {
|
if ($limit !== null && $limit !== 0 || ! empty($this->QBLimit)) {
|
||||||
throw new DatabaseException('PostgreSQL does not allow LIMITs on DELETE queries.');
|
throw new DatabaseException('PostgreSQL does not allow LIMITs on DELETE queries.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,6 +312,132 @@ class Builder extends BaseBuilder
|
|||||||
return parent::join($table, $cond, $type, $escape);
|
return parent::join($table, $cond, $type, $escape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a platform-specific batch update string from the supplied data
|
||||||
|
*
|
||||||
|
* @used-by batchExecute
|
||||||
|
*
|
||||||
|
* @param string $table Protected table name
|
||||||
|
* @param list<string> $keys QBKeys
|
||||||
|
* @param list<list<int|string>> $values QBSet
|
||||||
|
*/
|
||||||
|
protected function _updateBatch(string $table, array $keys, array $values): string
|
||||||
|
{
|
||||||
|
$sql = $this->QBOptions['sql'] ?? '';
|
||||||
|
|
||||||
|
// if this is the first iteration of batch then we need to build skeleton sql
|
||||||
|
if ($sql === '') {
|
||||||
|
$constraints = $this->QBOptions['constraints'] ?? [];
|
||||||
|
|
||||||
|
if ($constraints === []) {
|
||||||
|
if ($this->db->DBDebug) {
|
||||||
|
throw new DatabaseException('You must specify a constraint to match on for batch updates.'); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''; // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
$updateFields = $this->QBOptions['updateFields'] ??
|
||||||
|
$this->updateFields($keys, false, $constraints)->QBOptions['updateFields'] ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
$alias = $this->QBOptions['alias'] ?? '_u';
|
||||||
|
|
||||||
|
$sql = 'UPDATE ' . $this->compileIgnore('update') . $table . "\n";
|
||||||
|
|
||||||
|
$sql .= "SET\n";
|
||||||
|
|
||||||
|
$that = $this;
|
||||||
|
$sql .= implode(
|
||||||
|
",\n",
|
||||||
|
array_map(
|
||||||
|
static fn ($key, $value) => $key . ($value instanceof RawSql ?
|
||||||
|
' = ' . $value :
|
||||||
|
' = ' . $that->cast($alias . '.' . $value, $that->getFieldType($table, $key))),
|
||||||
|
array_keys($updateFields),
|
||||||
|
$updateFields
|
||||||
|
)
|
||||||
|
) . "\n";
|
||||||
|
|
||||||
|
$sql .= "FROM (\n{:_table_:}";
|
||||||
|
|
||||||
|
$sql .= ') ' . $alias . "\n";
|
||||||
|
|
||||||
|
$sql .= 'WHERE ' . implode(
|
||||||
|
' AND ',
|
||||||
|
array_map(
|
||||||
|
static function ($key, $value) use ($table, $alias, $that) {
|
||||||
|
if ($value instanceof RawSql && is_string($key)) {
|
||||||
|
return $table . '.' . $key . ' = ' . $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value instanceof RawSql) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $table . '.' . $value . ' = '
|
||||||
|
. $that->cast($alias . '.' . $value, $that->getFieldType($table, $value));
|
||||||
|
},
|
||||||
|
array_keys($constraints),
|
||||||
|
$constraints
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->QBOptions['sql'] = $sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->QBOptions['setQueryAsData'])) {
|
||||||
|
$data = $this->QBOptions['setQueryAsData'];
|
||||||
|
} else {
|
||||||
|
$data = implode(
|
||||||
|
" UNION ALL\n",
|
||||||
|
array_map(
|
||||||
|
static fn ($value) => 'SELECT ' . implode(', ', array_map(
|
||||||
|
static fn ($key, $index) => $index . ' ' . $key,
|
||||||
|
$keys,
|
||||||
|
$value
|
||||||
|
)),
|
||||||
|
$values
|
||||||
|
)
|
||||||
|
) . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace('{:_table_:}', $data, $sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns cast expression.
|
||||||
|
*
|
||||||
|
* @TODO move this to BaseBuilder in 4.5.0
|
||||||
|
*
|
||||||
|
* @param float|int|string $expression
|
||||||
|
*/
|
||||||
|
private function cast($expression, ?string $type): string
|
||||||
|
{
|
||||||
|
return ($type === null) ? $expression : 'CAST(' . $expression . ' AS ' . strtoupper($type) . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the filed type from database meta data.
|
||||||
|
*
|
||||||
|
* @param string $table Protected table name.
|
||||||
|
* @param string $fieldName Field name. May be protected.
|
||||||
|
*/
|
||||||
|
private function getFieldType(string $table, string $fieldName): ?string
|
||||||
|
{
|
||||||
|
$fieldName = trim($fieldName, $this->db->escapeChar);
|
||||||
|
|
||||||
|
if (! isset($this->QBOptions['fieldTypes'][$table])) {
|
||||||
|
$this->QBOptions['fieldTypes'][$table] = [];
|
||||||
|
|
||||||
|
foreach ($this->db->getFieldData($table) as $field) {
|
||||||
|
$this->QBOptions['fieldTypes'][$table][$field->name] = $field->type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->QBOptions['fieldTypes'][$table][$fieldName] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a platform-specific upsertBatch string from the supplied data
|
* Generates a platform-specific upsertBatch string from the supplied data
|
||||||
*
|
*
|
||||||
@ -436,18 +562,25 @@ class Builder extends BaseBuilder
|
|||||||
|
|
||||||
$sql .= ') ' . $alias . "\n";
|
$sql .= ') ' . $alias . "\n";
|
||||||
|
|
||||||
|
$that = $this;
|
||||||
$sql .= 'WHERE ' . implode(
|
$sql .= 'WHERE ' . implode(
|
||||||
' AND ',
|
' AND ',
|
||||||
array_map(
|
array_map(
|
||||||
static fn ($key, $value) => (
|
static function ($key, $value) use ($table, $alias, $that) {
|
||||||
$value instanceof RawSql ?
|
if ($value instanceof RawSql) {
|
||||||
$value :
|
return $value;
|
||||||
(
|
}
|
||||||
is_string($key) ?
|
|
||||||
$table . '.' . $key . ' = ' . $alias . '.' . $value :
|
if (is_string($key)) {
|
||||||
$table . '.' . $value . ' = ' . $alias . '.' . $value
|
return $table . '.' . $key . ' = '
|
||||||
)
|
. $that->cast(
|
||||||
),
|
$alias . '.' . $value,
|
||||||
|
$that->getFieldType($table, $key)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $table . '.' . $value . ' = ' . $alias . '.' . $value;
|
||||||
|
},
|
||||||
array_keys($constraints),
|
array_keys($constraints),
|
||||||
$constraints
|
$constraints
|
||||||
)
|
)
|
||||||
|
|||||||
@ -81,50 +81,52 @@ class Forge extends BaseForge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|string $field
|
* @param array|string $processedFields Processed column definitions
|
||||||
|
* or column names to DROP
|
||||||
*
|
*
|
||||||
* @return array|bool|string
|
* @return false|list<string>|string SQL string or false
|
||||||
|
* @phpstan-return ($alterType is 'DROP' ? string : list<string>|false)
|
||||||
*/
|
*/
|
||||||
protected function _alterTable(string $alterType, string $table, $field)
|
protected function _alterTable(string $alterType, string $table, $processedFields)
|
||||||
{
|
{
|
||||||
if (in_array($alterType, ['DROP', 'ADD'], true)) {
|
if (in_array($alterType, ['DROP', 'ADD'], true)) {
|
||||||
return parent::_alterTable($alterType, $table, $field);
|
return parent::_alterTable($alterType, $table, $processedFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table);
|
$sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table);
|
||||||
$sqls = [];
|
$sqls = [];
|
||||||
|
|
||||||
foreach ($field as $data) {
|
foreach ($processedFields as $field) {
|
||||||
if ($data['_literal'] !== false) {
|
if ($field['_literal'] !== false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_compare($this->db->getVersion(), '8', '>=') && isset($data['type'])) {
|
if (version_compare($this->db->getVersion(), '8', '>=') && isset($field['type'])) {
|
||||||
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($data['name'])
|
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($field['name'])
|
||||||
. " TYPE {$data['type']}{$data['length']}";
|
. " TYPE {$field['type']}{$field['length']}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($data['default'])) {
|
if (! empty($field['default'])) {
|
||||||
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($data['name'])
|
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($field['name'])
|
||||||
. " SET DEFAULT {$data['default']}";
|
. " SET DEFAULT {$field['default']}";
|
||||||
}
|
}
|
||||||
|
|
||||||
$nullable = true; // Nullable by default.
|
$nullable = true; // Nullable by default.
|
||||||
if (isset($data['null']) && ($data['null'] === false || $data['null'] === ' NOT ' . $this->null)) {
|
if (isset($field['null']) && ($field['null'] === false || $field['null'] === ' NOT ' . $this->null)) {
|
||||||
$nullable = false;
|
$nullable = false;
|
||||||
}
|
}
|
||||||
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($data['name'])
|
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($field['name'])
|
||||||
. ($nullable === true ? ' DROP' : ' SET') . ' NOT NULL';
|
. ($nullable === true ? ' DROP' : ' SET') . ' NOT NULL';
|
||||||
|
|
||||||
if (! empty($data['new_name'])) {
|
if (! empty($field['new_name'])) {
|
||||||
$sqls[] = $sql . ' RENAME COLUMN ' . $this->db->escapeIdentifiers($data['name'])
|
$sqls[] = $sql . ' RENAME COLUMN ' . $this->db->escapeIdentifiers($field['name'])
|
||||||
. ' TO ' . $this->db->escapeIdentifiers($data['new_name']);
|
. ' TO ' . $this->db->escapeIdentifiers($field['new_name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($data['comment'])) {
|
if (! empty($field['comment'])) {
|
||||||
$sqls[] = 'COMMENT ON COLUMN' . $this->db->escapeIdentifiers($table)
|
$sqls[] = 'COMMENT ON COLUMN' . $this->db->escapeIdentifiers($table)
|
||||||
. '.' . $this->db->escapeIdentifiers($data['name'])
|
. '.' . $this->db->escapeIdentifiers($field['name'])
|
||||||
. " IS {$data['comment']}";
|
. " IS {$field['comment']}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,14 +136,14 @@ class Forge extends BaseForge
|
|||||||
/**
|
/**
|
||||||
* Process column
|
* Process column
|
||||||
*/
|
*/
|
||||||
protected function _processColumn(array $field): string
|
protected function _processColumn(array $processedField): string
|
||||||
{
|
{
|
||||||
return $this->db->escapeIdentifiers($field['name'])
|
return $this->db->escapeIdentifiers($processedField['name'])
|
||||||
. ' ' . $field['type'] . ($field['type'] === 'text' ? '' : $field['length'])
|
. ' ' . $processedField['type'] . ($processedField['type'] === 'text' ? '' : $processedField['length'])
|
||||||
. $field['default']
|
. $processedField['default']
|
||||||
. $field['null']
|
. $processedField['null']
|
||||||
. $field['auto_increment']
|
. $processedField['auto_increment']
|
||||||
. $field['unique'];
|
. $processedField['unique'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -57,8 +57,9 @@ interface ResultInterface
|
|||||||
*
|
*
|
||||||
* If row doesn't exist, returns null.
|
* If row doesn't exist, returns null.
|
||||||
*
|
*
|
||||||
* @param int $n The index of the results to return
|
* @param int|string $n The index of the results to return, or column name.
|
||||||
* @param string $type The type of result object. 'array', 'object' or class name.
|
* @param string $type The type of result object. 'array', 'object' or class name.
|
||||||
|
* @phpstan-param class-string|'array'|'object' $type
|
||||||
*
|
*
|
||||||
* @return array|object|stdClass|null
|
* @return array|object|stdClass|null
|
||||||
* @phpstan-return ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : object|null))
|
* @phpstan-return ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : object|null))
|
||||||
|
|||||||
12
system/Database/SQLSRV/Builder.php
Normal file → Executable file
12
system/Database/SQLSRV/Builder.php
Normal file → Executable file
@ -332,7 +332,7 @@ class Builder extends BaseBuilder
|
|||||||
$this->set($set);
|
$this->set($set);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->QBSet)) {
|
if ($this->QBSet === []) {
|
||||||
if ($this->db->DBDebug) {
|
if ($this->db->DBDebug) {
|
||||||
throw new DatabaseException('You must use the "set" method to update an entry.');
|
throw new DatabaseException('You must use the "set" method to update an entry.');
|
||||||
}
|
}
|
||||||
@ -514,7 +514,7 @@ class Builder extends BaseBuilder
|
|||||||
$this->where($where);
|
$this->where($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->QBWhere)) {
|
if ($this->QBWhere === []) {
|
||||||
if ($this->db->DBDebug) {
|
if ($this->db->DBDebug) {
|
||||||
throw new DatabaseException('Deletes are not allowed unless they contain a "where" or "like" clause.');
|
throw new DatabaseException('Deletes are not allowed unless they contain a "where" or "like" clause.');
|
||||||
}
|
}
|
||||||
@ -522,7 +522,7 @@ class Builder extends BaseBuilder
|
|||||||
return false; // @codeCoverageIgnore
|
return false; // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($limit)) {
|
if ($limit !== null && $limit !== 0) {
|
||||||
$this->QBLimit = $limit;
|
$this->QBLimit = $limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,7 +551,7 @@ class Builder extends BaseBuilder
|
|||||||
$sql = (! $this->QBDistinct) ? 'SELECT ' : 'SELECT DISTINCT ';
|
$sql = (! $this->QBDistinct) ? 'SELECT ' : 'SELECT DISTINCT ';
|
||||||
|
|
||||||
// SQL Server can't work with select * if group by is specified
|
// SQL Server can't work with select * if group by is specified
|
||||||
if (empty($this->QBSelect) && ! empty($this->QBGroupBy) && is_array($this->QBGroupBy)) {
|
if (empty($this->QBSelect) && $this->QBGroupBy !== [] && is_array($this->QBGroupBy)) {
|
||||||
foreach ($this->QBGroupBy as $field) {
|
foreach ($this->QBGroupBy as $field) {
|
||||||
$this->QBSelect[] = is_array($field) ? $field['field'] : $field;
|
$this->QBSelect[] = is_array($field) ? $field['field'] : $field;
|
||||||
}
|
}
|
||||||
@ -573,7 +573,7 @@ class Builder extends BaseBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the "FROM" portion of the query
|
// Write the "FROM" portion of the query
|
||||||
if (! empty($this->QBFrom)) {
|
if ($this->QBFrom !== []) {
|
||||||
$sql .= "\nFROM " . $this->_fromTables();
|
$sql .= "\nFROM " . $this->_fromTables();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,7 +660,7 @@ class Builder extends BaseBuilder
|
|||||||
});
|
});
|
||||||
|
|
||||||
// if no primary found then look for unique - since indexes have no order
|
// if no primary found then look for unique - since indexes have no order
|
||||||
if (empty($uniqueIndexes)) {
|
if ($uniqueIndexes === []) {
|
||||||
$uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames) {
|
$uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames) {
|
||||||
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
|
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
|
||||||
|
|
||||||
|
|||||||
4
system/Database/SQLSRV/Connection.php
Normal file → Executable file
4
system/Database/SQLSRV/Connection.php
Normal file → Executable file
@ -444,7 +444,7 @@ class Connection extends BaseConnection
|
|||||||
*/
|
*/
|
||||||
public function setDatabase(?string $databaseName = null)
|
public function setDatabase(?string $databaseName = null)
|
||||||
{
|
{
|
||||||
if (empty($databaseName)) {
|
if ($databaseName === null || $databaseName === '') {
|
||||||
$databaseName = $this->database;
|
$databaseName = $this->database;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,7 +538,7 @@ class Connection extends BaseConnection
|
|||||||
return $this->dataCache['version'];
|
return $this->dataCache['version'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->connID || empty($info = sqlsrv_server_info($this->connID))) {
|
if (! $this->connID || ($info = sqlsrv_server_info($this->connID)) === []) {
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
74
system/Database/SQLSRV/Forge.php
Normal file → Executable file
74
system/Database/SQLSRV/Forge.php
Normal file → Executable file
@ -126,26 +126,30 @@ class Forge extends BaseForge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|string $field
|
* @param array|string $processedFields Processed column definitions
|
||||||
|
* or column names to DROP
|
||||||
*
|
*
|
||||||
* @return false|string|string[]
|
* @return false|list<string>|string SQL string or false
|
||||||
|
* @phpstan-return ($alterType is 'DROP' ? string : list<string>|false)
|
||||||
*/
|
*/
|
||||||
protected function _alterTable(string $alterType, string $table, $field)
|
protected function _alterTable(string $alterType, string $table, $processedFields)
|
||||||
{
|
{
|
||||||
// Handle DROP here
|
// Handle DROP here
|
||||||
if ($alterType === 'DROP') {
|
if ($alterType === 'DROP') {
|
||||||
|
$columnNamesToDrop = $processedFields;
|
||||||
|
|
||||||
// check if fields are part of any indexes
|
// check if fields are part of any indexes
|
||||||
$indexData = $this->db->getIndexData($table);
|
$indexData = $this->db->getIndexData($table);
|
||||||
|
|
||||||
foreach ($indexData as $index) {
|
foreach ($indexData as $index) {
|
||||||
if (is_string($field)) {
|
if (is_string($columnNamesToDrop)) {
|
||||||
$field = explode(',', $field);
|
$columnNamesToDrop = explode(',', $columnNamesToDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fld = array_intersect($field, $index->fields);
|
$fld = array_intersect($columnNamesToDrop, $index->fields);
|
||||||
|
|
||||||
// Drop index if field is part of an index
|
// Drop index if field is part of an index
|
||||||
if (! empty($fld)) {
|
if ($fld !== []) {
|
||||||
$this->_dropIndex($table, $index);
|
$this->_dropIndex($table, $index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,7 +157,7 @@ class Forge extends BaseForge
|
|||||||
$fullTable = $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($table);
|
$fullTable = $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($table);
|
||||||
|
|
||||||
// Drop default constraints
|
// Drop default constraints
|
||||||
$fields = implode(',', $this->db->escape((array) $field));
|
$fields = implode(',', $this->db->escape((array) $columnNamesToDrop));
|
||||||
|
|
||||||
$sql = <<<SQL
|
$sql = <<<SQL
|
||||||
SELECT name
|
SELECT name
|
||||||
@ -170,7 +174,7 @@ class Forge extends BaseForge
|
|||||||
|
|
||||||
$sql = 'ALTER TABLE ' . $fullTable . ' DROP ';
|
$sql = 'ALTER TABLE ' . $fullTable . ' DROP ';
|
||||||
|
|
||||||
$fields = array_map(static fn ($item) => 'COLUMN [' . trim($item) . ']', (array) $field);
|
$fields = array_map(static fn ($item) => 'COLUMN [' . trim($item) . ']', (array) $columnNamesToDrop);
|
||||||
|
|
||||||
return $sql . implode(',', $fields);
|
return $sql . implode(',', $fields);
|
||||||
}
|
}
|
||||||
@ -181,45 +185,45 @@ class Forge extends BaseForge
|
|||||||
$sqls = [];
|
$sqls = [];
|
||||||
|
|
||||||
if ($alterType === 'ADD') {
|
if ($alterType === 'ADD') {
|
||||||
foreach ($field as $data) {
|
foreach ($processedFields as $field) {
|
||||||
$sqls[] = $sql . ($data['_literal'] !== false ? $data['_literal'] : $this->_processColumn($data));
|
$sqls[] = $sql . ($field['_literal'] !== false ? $field['_literal'] : $this->_processColumn($field));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sqls;
|
return $sqls;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($field as $data) {
|
foreach ($processedFields as $field) {
|
||||||
if ($data['_literal'] !== false) {
|
if ($field['_literal'] !== false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($data['type'])) {
|
if (isset($field['type'])) {
|
||||||
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($data['name'])
|
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($field['name'])
|
||||||
. " {$data['type']}{$data['length']}";
|
. " {$field['type']}{$field['length']}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($data['default'])) {
|
if (! empty($field['default'])) {
|
||||||
$sqls[] = $sql . ' ALTER COLUMN ADD CONSTRAINT ' . $this->db->escapeIdentifiers($data['name']) . '_def'
|
$sqls[] = $sql . ' ALTER COLUMN ADD CONSTRAINT ' . $this->db->escapeIdentifiers($field['name']) . '_def'
|
||||||
. " DEFAULT {$data['default']} FOR " . $this->db->escapeIdentifiers($data['name']);
|
. " DEFAULT {$field['default']} FOR " . $this->db->escapeIdentifiers($field['name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$nullable = true; // Nullable by default.
|
$nullable = true; // Nullable by default.
|
||||||
if (isset($data['null']) && ($data['null'] === false || $data['null'] === ' NOT ' . $this->null)) {
|
if (isset($field['null']) && ($field['null'] === false || $field['null'] === ' NOT ' . $this->null)) {
|
||||||
$nullable = false;
|
$nullable = false;
|
||||||
}
|
}
|
||||||
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($data['name'])
|
$sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($field['name'])
|
||||||
. " {$data['type']}{$data['length']} " . ($nullable === true ? '' : 'NOT') . ' NULL';
|
. " {$field['type']}{$field['length']} " . ($nullable === true ? '' : 'NOT') . ' NULL';
|
||||||
|
|
||||||
if (! empty($data['comment'])) {
|
if (! empty($field['comment'])) {
|
||||||
$sqls[] = 'EXEC sys.sp_addextendedproperty '
|
$sqls[] = 'EXEC sys.sp_addextendedproperty '
|
||||||
. "@name=N'Caption', @value=N'" . $data['comment'] . "' , "
|
. "@name=N'Caption', @value=N'" . $field['comment'] . "' , "
|
||||||
. "@level0type=N'SCHEMA',@level0name=N'" . $this->db->schema . "', "
|
. "@level0type=N'SCHEMA',@level0name=N'" . $this->db->schema . "', "
|
||||||
. "@level1type=N'TABLE',@level1name=N'" . $this->db->escapeIdentifiers($table) . "', "
|
. "@level1type=N'TABLE',@level1name=N'" . $this->db->escapeIdentifiers($table) . "', "
|
||||||
. "@level2type=N'COLUMN',@level2name=N'" . $this->db->escapeIdentifiers($data['name']) . "'";
|
. "@level2type=N'COLUMN',@level2name=N'" . $this->db->escapeIdentifiers($field['name']) . "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($data['new_name'])) {
|
if (! empty($field['new_name'])) {
|
||||||
$sqls[] = "EXEC sp_rename '[" . $this->db->schema . '].[' . $table . '].[' . $data['name'] . "]' , '" . $data['new_name'] . "', 'COLUMN';";
|
$sqls[] = "EXEC sp_rename '[" . $this->db->schema . '].[' . $table . '].[' . $field['name'] . "]' , '" . $field['new_name'] . "', 'COLUMN';";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,16 +291,16 @@ class Forge extends BaseForge
|
|||||||
/**
|
/**
|
||||||
* Process column
|
* Process column
|
||||||
*/
|
*/
|
||||||
protected function _processColumn(array $field): string
|
protected function _processColumn(array $processedField): string
|
||||||
{
|
{
|
||||||
return $this->db->escapeIdentifiers($field['name'])
|
return $this->db->escapeIdentifiers($processedField['name'])
|
||||||
. (empty($field['new_name']) ? '' : ' ' . $this->db->escapeIdentifiers($field['new_name']))
|
. (empty($processedField['new_name']) ? '' : ' ' . $this->db->escapeIdentifiers($processedField['new_name']))
|
||||||
. ' ' . $field['type'] . ($field['type'] === 'text' ? '' : $field['length'])
|
. ' ' . $processedField['type'] . ($processedField['type'] === 'text' ? '' : $processedField['length'])
|
||||||
. $field['default']
|
. $processedField['default']
|
||||||
. $field['null']
|
. $processedField['null']
|
||||||
. $field['auto_increment']
|
. $processedField['auto_increment']
|
||||||
. ''
|
. ''
|
||||||
. $field['unique'];
|
. $processedField['unique'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
0
system/Database/SQLSRV/PreparedQuery.php
Normal file → Executable file
0
system/Database/SQLSRV/PreparedQuery.php
Normal file → Executable file
0
system/Database/SQLSRV/Result.php
Normal file → Executable file
0
system/Database/SQLSRV/Result.php
Normal file → Executable file
0
system/Database/SQLSRV/Utils.php
Normal file → Executable file
0
system/Database/SQLSRV/Utils.php
Normal file → Executable file
@ -109,51 +109,56 @@ class Forge extends BaseForge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array|string $field
|
* @param array|string $processedFields Processed column definitions
|
||||||
|
* or column names to DROP
|
||||||
*
|
*
|
||||||
* @return array|string|null
|
* @return array|string|null
|
||||||
|
* @return list<string>|string|null SQL string or null
|
||||||
|
* @phpstan-return ($alterType is 'DROP' ? string : list<string>|null)
|
||||||
*/
|
*/
|
||||||
protected function _alterTable(string $alterType, string $table, $field)
|
protected function _alterTable(string $alterType, string $table, $processedFields)
|
||||||
{
|
{
|
||||||
switch ($alterType) {
|
switch ($alterType) {
|
||||||
case 'DROP':
|
case 'DROP':
|
||||||
|
$columnNamesToDrop = $processedFields;
|
||||||
|
|
||||||
$sqlTable = new Table($this->db, $this);
|
$sqlTable = new Table($this->db, $this);
|
||||||
|
|
||||||
$sqlTable->fromTable($table)
|
$sqlTable->fromTable($table)
|
||||||
->dropColumn($field)
|
->dropColumn($columnNamesToDrop)
|
||||||
->run();
|
->run();
|
||||||
|
|
||||||
return '';
|
return ''; // Why empty string?
|
||||||
|
|
||||||
case 'CHANGE':
|
case 'CHANGE':
|
||||||
(new Table($this->db, $this))
|
(new Table($this->db, $this))
|
||||||
->fromTable($table)
|
->fromTable($table)
|
||||||
->modifyColumn($field)
|
->modifyColumn($processedFields) // @TODO Bug: should be NOT processed fields
|
||||||
->run();
|
->run();
|
||||||
|
|
||||||
return null;
|
return null; // Why null?
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return parent::_alterTable($alterType, $table, $field);
|
return parent::_alterTable($alterType, $table, $processedFields);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process column
|
* Process column
|
||||||
*/
|
*/
|
||||||
protected function _processColumn(array $field): string
|
protected function _processColumn(array $processedField): string
|
||||||
{
|
{
|
||||||
if ($field['type'] === 'TEXT' && strpos($field['length'], "('") === 0) {
|
if ($processedField['type'] === 'TEXT' && strpos($processedField['length'], "('") === 0) {
|
||||||
$field['type'] .= ' CHECK(' . $this->db->escapeIdentifiers($field['name'])
|
$processedField['type'] .= ' CHECK(' . $this->db->escapeIdentifiers($processedField['name'])
|
||||||
. ' IN ' . $field['length'] . ')';
|
. ' IN ' . $processedField['length'] . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->db->escapeIdentifiers($field['name'])
|
return $this->db->escapeIdentifiers($processedField['name'])
|
||||||
. ' ' . $field['type']
|
. ' ' . $processedField['type']
|
||||||
. $field['auto_increment']
|
. $processedField['auto_increment']
|
||||||
. $field['null']
|
. $processedField['null']
|
||||||
. $field['unique']
|
. $processedField['unique']
|
||||||
. $field['default'];
|
. $processedField['default'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,8 +188,11 @@ class Forge extends BaseForge
|
|||||||
*/
|
*/
|
||||||
protected function _attributeAutoIncrement(array &$attributes, array &$field)
|
protected function _attributeAutoIncrement(array &$attributes, array &$field)
|
||||||
{
|
{
|
||||||
if (! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === true
|
if (
|
||||||
&& stripos($field['type'], 'int') !== false) {
|
! empty($attributes['AUTO_INCREMENT'])
|
||||||
|
&& $attributes['AUTO_INCREMENT'] === true
|
||||||
|
&& stripos($field['type'], 'int') !== false
|
||||||
|
) {
|
||||||
$field['type'] = 'INTEGER PRIMARY KEY';
|
$field['type'] = 'INTEGER PRIMARY KEY';
|
||||||
$field['default'] = '';
|
$field['default'] = '';
|
||||||
$field['null'] = '';
|
$field['null'] = '';
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
namespace CodeIgniter\Database\SQLite3;
|
namespace CodeIgniter\Database\SQLite3;
|
||||||
|
|
||||||
use CodeIgniter\Database\Exceptions\DataException;
|
use CodeIgniter\Database\Exceptions\DataException;
|
||||||
use stdclass;
|
use stdClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Table
|
* Class Table
|
||||||
@ -28,8 +28,7 @@ class Table
|
|||||||
/**
|
/**
|
||||||
* All of the fields this table represents.
|
* All of the fields this table represents.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, array<string, bool|int|string|null>> [name => attributes]
|
||||||
* @phpstan-var array<string, array<string, bool|int|string|null>>
|
|
||||||
*/
|
*/
|
||||||
protected $fields = [];
|
protected $fields = [];
|
||||||
|
|
||||||
@ -114,7 +113,7 @@ class Table
|
|||||||
// if primary key index exists twice then remove psuedo index name 'primary'.
|
// if primary key index exists twice then remove psuedo index name 'primary'.
|
||||||
$primaryIndexes = array_filter($this->keys, static fn ($index) => $index['type'] === 'primary');
|
$primaryIndexes = array_filter($this->keys, static fn ($index) => $index['type'] === 'primary');
|
||||||
|
|
||||||
if (! empty($primaryIndexes) && count($primaryIndexes) > 1 && array_key_exists('primary', $this->keys)) {
|
if ($primaryIndexes !== [] && count($primaryIndexes) > 1 && array_key_exists('primary', $this->keys)) {
|
||||||
unset($this->keys['primary']);
|
unset($this->keys['primary']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +156,7 @@ class Table
|
|||||||
/**
|
/**
|
||||||
* Drops columns from the table.
|
* Drops columns from the table.
|
||||||
*
|
*
|
||||||
* @param array|string $columns
|
* @param list<string>|string $columns Column names to drop.
|
||||||
*
|
*
|
||||||
* @return Table
|
* @return Table
|
||||||
*/
|
*/
|
||||||
@ -178,14 +177,15 @@ class Table
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies a field, including changing data type,
|
* Modifies a field, including changing data type, renaming, etc.
|
||||||
* renaming, etc.
|
*
|
||||||
|
* @param list<array<string, bool|int|string|null>> $fieldsToModify
|
||||||
*
|
*
|
||||||
* @return Table
|
* @return Table
|
||||||
*/
|
*/
|
||||||
public function modifyColumn(array $fields)
|
public function modifyColumn(array $fieldsToModify)
|
||||||
{
|
{
|
||||||
foreach ($fields as $field) {
|
foreach ($fieldsToModify as $field) {
|
||||||
$oldName = $field['name'];
|
$oldName = $field['name'];
|
||||||
unset($field['name']);
|
unset($field['name']);
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user