feat: initial ACRIB WordPress deployment
- WordPress 6.9.4 (es_ES) with Kadence theme - Homepage: Hero, La Asociación, Pilares, Beneficios, Eventos, Miembros, Hazte Miembro, Contacto - Brand identity: #13294b navy, #a12932 burgundy, #c69c48 gold - Fonts: Raleway (headings) + Source Sans 3 (body) + Lato (UI) - Plugins: Kadence Blocks, Polylang, Contact Form 7 - Custom CSS with full brand styling and responsive layout - HTTPS enforced via wp-config.php proxy detection
This commit is contained in:
62
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/CHANGELOG.md
vendored
Normal file
62
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. This project adhere to the [Semantic Versioning](http://semver.org/) standard.
|
||||
|
||||
## [1.3.0] - 2026-02-25
|
||||
|
||||
### Added
|
||||
- Transaction nesting support via savepoints. Nested `beginTransaction()` calls now create savepoints instead of issuing `START TRANSACTION`, which would implicitly commit any existing transaction.
|
||||
- `DB::transactionLevel()` method to retrieve the current transaction nesting depth.
|
||||
|
||||
### Changed
|
||||
- `DB::commit()` releases the current savepoint when nested, and issues a real `COMMIT` only at the outermost level.
|
||||
- `DB::rollback()` rolls back to the current savepoint when nested, and issues a real `ROLLBACK` only at the outermost level.
|
||||
- `tests-php.yml` ensure slic runs in PHP 7.4.
|
||||
|
||||
## [1.0.8] TBD
|
||||
|
||||
* Feat - Add the `DB::generate_results` and `DB::generate_col` methods to the `DB` class to fetch all results matching an unbounded query with a set of bounded queries.
|
||||
|
||||
## [1.0.7] 2023-10-23
|
||||
|
||||
* Tweak - Updates around `trim()` for php 8.1 compatibility.
|
||||
* Tweak - Force `From()` and `Select()` to convert passed non-strings to an empty string.
|
||||
|
||||
## [1.0.6] 2023-09-05
|
||||
|
||||
* Tweak - Fix array shape for errors in `DatabaseQueryException`
|
||||
|
||||
## [1.0.5] 2023-09-05
|
||||
|
||||
* Tweak - Updating docblock for `whereExists()` and `whereNotExists()` in response to a PHPStan flag.
|
||||
|
||||
## [1.0.4] 2023-06-06
|
||||
|
||||
* Tweak - Added more documentation for methods provided by DB.
|
||||
* Tweak - Adjusted docblocks to better declare types.
|
||||
|
||||
## [1.0.3] 2022-11-22
|
||||
|
||||
* Tweak - Set composer.json `config.platform.php` to `7.0`.
|
||||
|
||||
## [1.0.2] 2022-11-22
|
||||
|
||||
* Fix - Adjust `DB::insert()`, `DB::delete()`, `DB::update()`, and `DB::replace()` signature to match `wpdb`'s supported method signatures.
|
||||
* Fix - Adjust `DB::get_var()`, `DB::get_col()`, and `DB::get_results()` signature of first arg to match `wpdb`'s signature.
|
||||
|
||||
## [1.0.1] 2022-09-29
|
||||
|
||||
* Tweak - Added a `Config` class to handle overrides of the `DatabaseQueryException` and addition of a hook prefix.
|
||||
* Tweak - Added tests for `Config`
|
||||
* Docs - More documentation
|
||||
|
||||
## [1.0.0] 2022-08-17
|
||||
|
||||
* Feature - Initial version
|
||||
* Docs - Documentation
|
||||
* Tweak - Automated tests
|
||||
|
||||
[1.0.0]: https://github.com/stellarwp/schema/releases/tag/1.0.0
|
||||
[1.0.1]: https://github.com/stellarwp/schema/releases/tag/1.0.1
|
||||
[1.0.2]: https://github.com/stellarwp/schema/releases/tag/1.0.2
|
||||
[1.0.3]: https://github.com/stellarwp/schema/releases/tag/1.0.3
|
||||
202
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/CLAUDE.md
vendored
Normal file
202
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/CLAUDE.md
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
# StellarWP DB - Claude Instructions
|
||||
|
||||
## Project Overview
|
||||
|
||||
StellarWP DB is a WordPress database wrapper and query builder library that provides a fluent interface for constructing and executing database queries. It's built on top of WordPress's `$wpdb` global and adds a modern, chainable API with proper error handling.
|
||||
|
||||
**Key Features:**
|
||||
- Fluent query builder interface
|
||||
- SQL injection protection via WordPress's prepared statements
|
||||
- Support for complex queries (joins, unions, subqueries, etc.)
|
||||
- Meta table abstractions for WordPress-style data
|
||||
- Error handling with exceptions
|
||||
- Full compatibility with `$wpdb` methods
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Classes
|
||||
|
||||
1. **DB** (`src/DB/DB.php`)
|
||||
- Static facade/decorator for `$wpdb`
|
||||
- Entry point for creating query builders via `DB::table()`
|
||||
- Provides static methods that wrap `$wpdb` methods with error checking
|
||||
- Throws `DatabaseQueryException` on SQL errors
|
||||
|
||||
2. **QueryBuilder** (`src/DB/QueryBuilder/QueryBuilder.php`)
|
||||
- Main query building class
|
||||
- Uses traits to organize functionality:
|
||||
- `Aggregate` - COUNT, SUM, AVG, MIN, MAX operations
|
||||
- `CRUD` - INSERT, UPDATE, DELETE, UPSERT operations
|
||||
- `FromClause` - FROM table handling
|
||||
- `WhereClause` - WHERE conditions
|
||||
- `JoinClause` - JOIN operations
|
||||
- `SelectStatement` - SELECT column handling
|
||||
- `MetaQuery` - WordPress meta table helpers
|
||||
- And more...
|
||||
|
||||
3. **Config** (`src/DB/Config.php`)
|
||||
- Configuration management
|
||||
- Allows setting custom exception classes
|
||||
- Hook prefix configuration for WordPress integration
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
/home/matt/git/db/
|
||||
├── src/DB/ # Main source code
|
||||
│ ├── Config.php # Configuration class
|
||||
│ ├── DB.php # Main DB facade
|
||||
│ ├── Database/ # Database-specific classes
|
||||
│ │ ├── Actions/ # Database actions (e.g., EnableBigSqlSelects)
|
||||
│ │ ├── Exceptions/ # Custom exceptions
|
||||
│ │ └── Provider.php # Service provider
|
||||
│ └── QueryBuilder/ # Query builder components
|
||||
│ ├── Clauses/ # SQL clause representations
|
||||
│ ├── Concerns/ # Traits for QueryBuilder
|
||||
│ ├── Types/ # Type definitions (JoinType, Operator, etc.)
|
||||
│ ├── QueryBuilder.php # Main query builder
|
||||
│ ├── JoinQueryBuilder.php
|
||||
│ └── WhereQueryBuilder.php
|
||||
├── tests/ # Test suite
|
||||
│ ├── wpunit/ # WordPress unit tests
|
||||
│ └── _support/ # Test support classes
|
||||
├── .github/workflows/ # GitHub Actions CI/CD
|
||||
├── composer.json # PHP dependencies
|
||||
├── phpstan.neon.dist # PHPStan configuration
|
||||
└── README.md # Documentation
|
||||
```
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Composer Scripts
|
||||
|
||||
```bash
|
||||
# Run static analysis with PHPStan
|
||||
composer test:analysis
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
The project uses Codeception with WordPress testing framework (wp-browser) and a tool called "slic" for managing the test environment:
|
||||
|
||||
```bash
|
||||
# Run tests using slic (see .github/workflows/tests-php.yml)
|
||||
${SLIC_BIN} run wpunit --ext DotReporter
|
||||
```
|
||||
|
||||
### Static Analysis
|
||||
|
||||
PHPStan is configured at level 5 with WordPress-specific rules:
|
||||
- Configuration: `phpstan.neon.dist`
|
||||
- Includes WordPress stubs via `szepeviktor/phpstan-wordpress`
|
||||
- Analyzes only the `src/` directory
|
||||
|
||||
## Code Conventions
|
||||
|
||||
### Namespacing
|
||||
- Root namespace: `StellarWP\DB`
|
||||
- Follow PSR-4 autoloading standard
|
||||
- Tests use `StellarWP\DB\Tests` namespace
|
||||
|
||||
### WordPress Integration
|
||||
- All table names are automatically prefixed with `$wpdb->prefix`
|
||||
- Use `DB::raw()` to bypass automatic prefixing
|
||||
- Methods match `$wpdb` signatures where applicable
|
||||
|
||||
### Error Handling
|
||||
- SQL errors throw `DatabaseQueryException` by default
|
||||
- Custom exception classes can be configured via `Config::setDatabaseQueryException()`
|
||||
- All database operations should be wrapped in try-catch blocks in production code
|
||||
|
||||
### Query Building Patterns
|
||||
|
||||
```php
|
||||
// Basic query
|
||||
DB::table('posts')
|
||||
->select('ID', 'post_title')
|
||||
->where('post_status', 'publish')
|
||||
->orderBy('post_date', 'DESC')
|
||||
->limit(10)
|
||||
->getAll();
|
||||
|
||||
// Complex query with joins and meta
|
||||
DB::table('posts', 'p')
|
||||
->select(['p.ID', 'id'], ['p.post_title', 'title'])
|
||||
->attachMeta('postmeta', 'p.ID', 'post_id',
|
||||
['_thumbnail_id', 'thumbnailId'],
|
||||
['_custom_field', 'customValue']
|
||||
)
|
||||
->leftJoin('term_relationships', 'p.ID', 'tr.object_id', 'tr')
|
||||
->where('p.post_type', 'post')
|
||||
->where('p.post_status', 'publish')
|
||||
->getAll();
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
### For Strauss Integration
|
||||
The library is designed to be included via Strauss for namespace isolation in WordPress plugins. The README examples assume a namespace prefix like `Boom\Shakalaka\`.
|
||||
|
||||
### WordPress Compatibility
|
||||
- Requires WordPress with `$wpdb` global
|
||||
- Compatible with WordPress coding standards
|
||||
- Follows WordPress database structure conventions (posts, postmeta, etc.)
|
||||
|
||||
### Performance Considerations
|
||||
- Queries are not executed until terminal methods are called (`get()`, `getAll()`, `count()`, etc.)
|
||||
- Use `attachMeta()` for efficient meta queries instead of multiple joins
|
||||
- The library generates SQL using WordPress's `prepare()` method for security
|
||||
|
||||
### Recent Updates (v1.0.8)
|
||||
- Added `DB::generate_results()` and `DB::generate_col()` for handling large result sets with bounded queries
|
||||
- PHP 8.1 compatibility improvements
|
||||
- Better type safety in docblocks
|
||||
|
||||
## CI/CD
|
||||
|
||||
### GitHub Actions Workflows
|
||||
|
||||
1. **Tests** (`.github/workflows/tests-php.yml`)
|
||||
- Runs on every push
|
||||
- Uses `stellarwp/slic` for test environment setup
|
||||
- Executes wpunit test suite
|
||||
|
||||
2. **Static Analysis** (`.github/workflows/static-analysis.yml`)
|
||||
- Runs on every push
|
||||
- PHP 8.0 environment
|
||||
- Executes PHPStan via `composer test:analysis`
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding New Query Features
|
||||
1. Create a new trait in `src/DB/QueryBuilder/Concerns/`
|
||||
2. Add the trait to the `QueryBuilder` class
|
||||
3. Implement the SQL generation method (e.g., `getYourFeatureSQL()`)
|
||||
4. Add it to the `getSQL()` method if needed
|
||||
5. Write tests in `tests/wpunit/QueryBuilder/`
|
||||
|
||||
### Debugging Queries
|
||||
```php
|
||||
// Get the generated SQL without executing
|
||||
$sql = DB::table('posts')
|
||||
->where('post_status', 'publish')
|
||||
->getSQL();
|
||||
|
||||
// Use wpdb's last_query after execution
|
||||
$results = DB::table('posts')->getAll();
|
||||
$lastQuery = $wpdb->last_query;
|
||||
```
|
||||
|
||||
### Meta Table Patterns
|
||||
The library provides special handling for WordPress meta tables:
|
||||
- `attachMeta()` - Efficiently join and select meta values
|
||||
- `configureMetaTable()` - Customize meta table column names
|
||||
- Automatic LEFT JOIN generation for each meta key
|
||||
- Support for multiple meta values with the same key
|
||||
|
||||
## Resources
|
||||
|
||||
- [WordPress $wpdb Documentation](https://developer.wordpress.org/reference/classes/wpdb/)
|
||||
- [Codeception Documentation](https://codeception.com/)
|
||||
- [PHPStan Documentation](https://phpstan.org/)
|
||||
- [WordPress Coding Standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/)
|
||||
339
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/LICENSE
vendored
Normal file
339
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/LICENSE
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
1075
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/README.md
vendored
Normal file
1075
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/README.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
69
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/src/DB/Config.php
vendored
Normal file
69
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/src/DB/Config.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException;
|
||||
|
||||
class Config {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $databaseQueryException = DatabaseQueryException::class;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $hookPrefix = '';
|
||||
|
||||
/**
|
||||
* Gets the DatabaseQueryException class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getDatabaseQueryException(): string {
|
||||
return static::$databaseQueryException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hook prefix.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHookPrefix(): string {
|
||||
return static::$hookPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this class back to the defaults.
|
||||
*/
|
||||
public static function reset() {
|
||||
static::$hookPrefix = '';
|
||||
static::$databaseQueryException = DatabaseQueryException::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DatabaseQueryException class.
|
||||
*
|
||||
* @param string $class Class name of the DatabaseQueryException to use.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setDatabaseQueryException( string $class ) {
|
||||
if ( ! is_a( $class, DatabaseQueryException::class, true ) ) {
|
||||
throw new \InvalidArgumentException( 'The provided DatabaseQueryException class must be or must extend ' . DatabaseQueryException::class . '.' );
|
||||
}
|
||||
|
||||
static::$databaseQueryException = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hook prefix.
|
||||
*
|
||||
* @param string $prefix The prefix to add to hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setHookPrefix( string $prefix ) {
|
||||
static::$hookPrefix = $prefix;
|
||||
}
|
||||
}
|
||||
485
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/src/DB/DB.php
vendored
Normal file
485
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/db/src/DB/DB.php
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Generator;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\QueryBuilder;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class DB
|
||||
*
|
||||
* A static decorator for the $wpdb class and decorator function which does SQL error checking when performing queries.
|
||||
* If a SQL error occurs a DatabaseQueryException is thrown.
|
||||
*
|
||||
* @method static int|bool query( string $query )
|
||||
* @method static int|false insert( string $table, array $data, array|string|null $format = null )
|
||||
* @method static int|false delete( string $table, array $where, array|string|null $where_format = null )
|
||||
* @method static int|false update( string $table, array $data, array $where, array|string|null $format = null, array|string|null $where_format = null )
|
||||
* @method static int|false replace( string $table, array $data, array|string|null $format = null )
|
||||
* @method static null|string get_var( string|null $query = null, int $x = 0, int $y = 0 )
|
||||
* @method static array|object|null|void get_row( string|null $query = null, string $output = OBJECT, int $y = 0 )
|
||||
* @method static array get_col( string|null $query = null, int $x = 0 )
|
||||
* @method static array|object|null get_results( string|null $query = null, string $output = OBJECT )
|
||||
* @method static string get_charset_collate()
|
||||
* @method static string esc_like( string $text )
|
||||
* @method static string remove_placeholder_escape( string $text )
|
||||
* @method static Config config()
|
||||
*/
|
||||
class DB {
|
||||
/**
|
||||
* Is this library initialized?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $initialized = false;
|
||||
|
||||
/**
|
||||
* The Database\Provider instance.
|
||||
*
|
||||
* @var Database\Provider
|
||||
*/
|
||||
private static $provider;
|
||||
|
||||
/**
|
||||
* Current transaction nesting depth.
|
||||
*
|
||||
* @since 1.3.0
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $transactionDepth = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the service provider.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static function init(): void {
|
||||
if ( ! self::$initialized ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$provider = new Database\Provider();
|
||||
self::$provider->register();
|
||||
self::$initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current transaction nesting depth.
|
||||
*
|
||||
* @since 1.3.0
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function transactionLevel() {
|
||||
return self::$transactionDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the dbDelta function and returns a WP_Error with any errors that occurred during the process
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param $delta
|
||||
*
|
||||
* @return array
|
||||
* @throws DatabaseQueryException
|
||||
* @see dbDelta() for parameter and return details
|
||||
*
|
||||
*/
|
||||
public static function delta( $delta ) {
|
||||
return self::runQueryWithErrorChecking(
|
||||
function () use ( $delta ) {
|
||||
return dbDelta( $delta );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for the $wpdb->prepare method
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $query
|
||||
* @param mixed ...$args
|
||||
*
|
||||
* @return false|mixed
|
||||
* @see WPDB::prepare() for usage details
|
||||
*
|
||||
*/
|
||||
public static function prepare( $query, ...$args ) {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prepare( $query, ...$args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method which calls the static method on the $wpdb while performing error checking
|
||||
*
|
||||
* @since 1.0.0 add givewp_db_pre_query action
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
*
|
||||
* @return mixed
|
||||
* @throws DatabaseQueryException
|
||||
*/
|
||||
public static function __callStatic( $name, $arguments ) {
|
||||
return self::runQueryWithErrorChecking(
|
||||
static function () use ( $name, $arguments ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( in_array( $name, [ 'get_row', 'get_col', 'get_results', 'query' ], true ) ) {
|
||||
$hook_prefix = Config::getHookPrefix();
|
||||
|
||||
/**
|
||||
* Allow for hooking just before query execution.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $argument First argument passed to the $wpdb method.
|
||||
* @param string $hook_prefix Prefix for the hook.
|
||||
*/
|
||||
do_action( 'stellarwp_db_pre_query', current( $arguments ), $hook_prefix );
|
||||
|
||||
if ( $hook_prefix ) {
|
||||
/**
|
||||
* Allow for hooking just before query execution.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $argument First argument passed to the $wpdb method.
|
||||
* @param string $hook_prefix Prefix for the hook.
|
||||
*/
|
||||
do_action( "{$hook_prefix}_stellarwp_db_pre_query", current( $arguments ), $hook_prefix );
|
||||
}
|
||||
}
|
||||
|
||||
return call_user_func_array( [ $wpdb, $name ], $arguments );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last insert ID
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return int
|
||||
*/
|
||||
public static function last_insert_id() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->insert_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefix given table name with $wpdb->prefix
|
||||
*
|
||||
* @param string $tableName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function prefix( $tableName ) {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . $tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create QueryBuilder instance
|
||||
*
|
||||
* @param string|RawSQL $table
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public static function table( $table, $alias = '' ) {
|
||||
$builder = new QueryBuilder();
|
||||
$builder->from( $table, $alias );
|
||||
|
||||
return $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a transaction. If the callable works then the transaction is committed. If the callable throws an exception
|
||||
* then the transaction is rolled back.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function transaction( callable $callback ) {
|
||||
self::beginTransaction();
|
||||
|
||||
try {
|
||||
$callback();
|
||||
} catch ( Exception $e ) {
|
||||
self::rollback();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
self::commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually starts a transaction.
|
||||
*
|
||||
* Nested calls create savepoints instead of starting a new transaction,
|
||||
* preventing MySQL's implicit commit behavior.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 1.3.0 Added savepoint support for nested transactions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function beginTransaction() {
|
||||
global $wpdb;
|
||||
|
||||
if ( self::$transactionDepth === 0 ) {
|
||||
$wpdb->query( 'START TRANSACTION' );
|
||||
} else {
|
||||
$wpdb->query( 'SAVEPOINT sp_' . self::$transactionDepth );
|
||||
}
|
||||
|
||||
self::$transactionDepth++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually rolls back a transaction.
|
||||
*
|
||||
* When nested, rolls back to the current savepoint. When at the outermost
|
||||
* level, issues a real ROLLBACK.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 1.3.0 Added savepoint support for nested transactions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function rollback() {
|
||||
global $wpdb;
|
||||
|
||||
self::$transactionDepth = max( 0, self::$transactionDepth - 1 );
|
||||
|
||||
if ( self::$transactionDepth === 0 ) {
|
||||
$wpdb->query( 'ROLLBACK' );
|
||||
} else {
|
||||
$wpdb->query( 'ROLLBACK TO SAVEPOINT sp_' . self::$transactionDepth );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually commits a transaction.
|
||||
*
|
||||
* When nested, releases the current savepoint. When at the outermost
|
||||
* level, issues a real COMMIT.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 1.3.0 Added savepoint support for nested transactions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function commit() {
|
||||
global $wpdb;
|
||||
|
||||
self::$transactionDepth = max( 0, self::$transactionDepth - 1 );
|
||||
|
||||
if ( self::$transactionDepth === 0 ) {
|
||||
$wpdb->query( 'COMMIT' );
|
||||
} else {
|
||||
$wpdb->query( 'RELEASE SAVEPOINT sp_' . self::$transactionDepth );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as a flag to tell QueryBuilder not to process the provided SQL
|
||||
* If $args are provided, we will assume that dev wants to use DB::prepare method with raw SQL
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array ...$args
|
||||
*
|
||||
* @return RawSQL
|
||||
*/
|
||||
public static function raw( $sql, ...$args ) {
|
||||
return new RawSQL( $sql, ...$args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a query callable and checks to see if any unique SQL errors occurred when it was run
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param Callable $queryCaller
|
||||
*
|
||||
* @return mixed
|
||||
* @throws DatabaseQueryException
|
||||
*/
|
||||
private static function runQueryWithErrorChecking( $queryCaller ) {
|
||||
global $wpdb, $EZSQL_ERROR;
|
||||
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
||||
|
||||
$errorCount = is_array( $EZSQL_ERROR ) ? count( $EZSQL_ERROR ) : 0;
|
||||
$hasShowErrors = $wpdb->hide_errors();
|
||||
|
||||
$output = $queryCaller();
|
||||
|
||||
if ( $hasShowErrors ) {
|
||||
$wpdb->show_errors();
|
||||
}
|
||||
|
||||
$wpError = self::getQueryErrors( $errorCount );
|
||||
|
||||
if ( ! empty( $wpError->errors ) ) {
|
||||
/** @var DatabaseQueryException */
|
||||
$exception_class = Config::getDatabaseQueryException();
|
||||
|
||||
throw new $exception_class( $wpdb->last_query, $wpError->errors );
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the SQL errors stored by WordPress
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param int $initialCount
|
||||
*
|
||||
* @return WP_Error
|
||||
*/
|
||||
private static function getQueryErrors( $initialCount = 0 ) {
|
||||
global $EZSQL_ERROR;
|
||||
|
||||
$wpError = new WP_Error();
|
||||
|
||||
if ( is_array( $EZSQL_ERROR ) ) {
|
||||
for ( $index = $initialCount, $indexMax = count( $EZSQL_ERROR ); $index < $indexMax; $index ++ ) {
|
||||
$error = $EZSQL_ERROR[ $index ];
|
||||
|
||||
if ( empty( $error['error_str'] ) || empty( $error['query'] ) || 0 === strpos(
|
||||
$error['query'],
|
||||
'DESCRIBE '
|
||||
) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$wpError->add( 'db_delta_error', $error['error_str'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $wpError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the results from a query in batches.
|
||||
*
|
||||
* @since TBD
|
||||
*
|
||||
* @param string $query The SQL query.
|
||||
* @param int $batch_size The number of results to return in each batch.
|
||||
* @param Closure $fetch The function to fetch the results.
|
||||
*
|
||||
* @return Generator<mixed> A generator to get all the results of the query.
|
||||
*/
|
||||
private static function run_batched_query( string $query, int $batch_size, Closure $fetch ): Generator {
|
||||
// Capture the end part of the main query, the one not bound with parentheses.
|
||||
preg_match( '/([^)(]*?)$/', $query, $matches );
|
||||
|
||||
// Does the end part of the query contain a LIMIT? Look for `LIMIT <offset>, <limit>` or `LIMIT <limit>`.
|
||||
$has_limit = (bool) preg_match( '/LIMIT\\s+\\d+\\s*(,\\s*\\d+)*$/i', $matches[1] );
|
||||
|
||||
if ( $has_limit ) {
|
||||
yield from $fetch( $query );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a LIMIT template to the query.
|
||||
$query_template = trim( $query . ' LIMIT %d, %d' );
|
||||
|
||||
$offset = 0;
|
||||
$found_rows = 0;
|
||||
$fetched = 0;
|
||||
$key = 0;
|
||||
|
||||
// Set up the first query, make sure ot include SQL_CALC_FOUND_ROWS.
|
||||
$first_query = self::prepare(
|
||||
$query_template,
|
||||
$offset,
|
||||
$batch_size
|
||||
);
|
||||
|
||||
// Build the first query to include SQL_CALC_FOUND_ROWS if not already present.
|
||||
$first_query = preg_replace( '/^SELECT\\s*(?!SQL_CALC_FOUND_ROWS)/i', 'SELECT SQL_CALC_FOUND_ROWS ', $first_query );
|
||||
|
||||
$run_query = $first_query;
|
||||
|
||||
do {
|
||||
foreach ( $fetch( $run_query ) as $result ) {
|
||||
$fetched ++;
|
||||
yield $key => $result;
|
||||
$key ++;
|
||||
}
|
||||
|
||||
if ( $offset === 0 ) {
|
||||
// First run.
|
||||
$found_rows = (int) self::get_var( 'SELECT FOUND_ROWS()' );
|
||||
}
|
||||
|
||||
$offset += $batch_size;
|
||||
|
||||
// Compile the query for the next run.
|
||||
$run_query = self::prepare(
|
||||
$query_template,
|
||||
$offset,
|
||||
$batch_size
|
||||
);
|
||||
} while ( $fetched < $found_rows );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the results from a query in batches.
|
||||
*
|
||||
* This method should be used to run an unbounded query in batches.
|
||||
*
|
||||
* @since TBD
|
||||
*
|
||||
* @param string|null $query The SQL query.
|
||||
* @param string $output The required return type. One of OBJECT, ARRAY_A, ARRAY_N.
|
||||
* @param int $batch_size The number of results to return in each batch.
|
||||
*
|
||||
* @return Generator<array|object|null> A generator to get all the results of the query.
|
||||
*/
|
||||
public static function generate_results( string $query = null, string $output = OBJECT, int $batch_size = 20 ): Generator {
|
||||
yield from self::run_batched_query( $query, $batch_size, static function ( string $run_query ) use ( $output ) {
|
||||
return self::get_results( $run_query, $output );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the values in a column from a query in batches.
|
||||
*
|
||||
* @since TBD
|
||||
*
|
||||
* @param string|null $query The SQL query.
|
||||
* @param int $x The column number to return.
|
||||
* @param int $batch_size The number of results to return in each batch.
|
||||
*
|
||||
* @return Generator<mixed> The values of the column.
|
||||
*/
|
||||
public function generate_col( string $query = null, int $x = 0, int $batch_size = 50 ): Generator {
|
||||
yield from self::run_batched_query( $query, $batch_size, static function ( string $run_query ) use ( $x ) {
|
||||
return self::get_col( $run_query, $x );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\Database\Actions;
|
||||
|
||||
class EnableBigSqlSelects {
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*
|
||||
* Enables mysql big selects for the session using a session system variable.
|
||||
*
|
||||
* This is necessary for hosts that have an arbitrary MAX_JOIN_SIZE limit, which prevents more complex queries from
|
||||
* running properly. Setting SQL_BIG_SELECTS ignores this limit. This is also done by WooCommerce, supporting the
|
||||
* idea that this is a viable option. There also doesn't seem to be a way for hosts to prevent this.
|
||||
*
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_big_selects
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/system-variable-privileges.html
|
||||
*
|
||||
*/
|
||||
public function set_var() {
|
||||
static $bigSelects = false;
|
||||
|
||||
if ( ! $bigSelects ) {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1;' );
|
||||
|
||||
$bigSelects = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class DatabaseQueryException
|
||||
*
|
||||
* An exception for when errors occurred within the database while performing a query, which stores the SQL errors the
|
||||
* database returned
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class DatabaseQueryException extends \Exception {
|
||||
/**
|
||||
* @var array<string, string[]>
|
||||
*/
|
||||
private $queryErrors;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $query;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array<string, string[]> $queryErrors
|
||||
*/
|
||||
public function __construct(
|
||||
string $query,
|
||||
array $queryErrors,
|
||||
string $message = 'Database Query',
|
||||
$code = 0,
|
||||
Throwable $previous = null
|
||||
) {
|
||||
$this->query = $query;
|
||||
$this->queryErrors = $queryErrors;
|
||||
|
||||
parent::__construct( $message, $code, $previous );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query errors
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array<string, string[]>
|
||||
*/
|
||||
public function getQueryErrors(): array {
|
||||
return $this->queryErrors;
|
||||
}
|
||||
|
||||
public function getQuery(): string {
|
||||
return $this->query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\Database;
|
||||
|
||||
class Provider {
|
||||
/**
|
||||
* @var Actions\EnableBigSqlSelects
|
||||
*/
|
||||
public $action_enable_big_sql_selects;
|
||||
|
||||
/**
|
||||
* Binds and sets up implementations.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function register() {
|
||||
add_action( 'stellarwp_db_pre_query', [ $this, 'enable_big_sql_selects' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the EnableBigSqlSelects action.
|
||||
*/
|
||||
public function enable_big_sql_selects() {
|
||||
if ( $this->action_enable_big_sql_selects === null ) {
|
||||
$this->action_enable_big_sql_selects = new Actions\EnableBigSqlSelects();
|
||||
}
|
||||
|
||||
$this->action_enable_big_sql_selects->set_var();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\QueryBuilder;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class From {
|
||||
/**
|
||||
* @var string|RawSQL
|
||||
*/
|
||||
public $table;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $alias;
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string|null $alias
|
||||
*/
|
||||
public function __construct( $table, $alias = '' ) {
|
||||
$this->table = QueryBuilder::prefixTable( $table );
|
||||
$this->alias = is_scalar( $alias ) ? trim( (string) $alias ) : '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\Math;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\Operator;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Having {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $column;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $comparisonOperator;
|
||||
|
||||
/**
|
||||
* @var string|int
|
||||
*/
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $logicalOperator;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $mathFunction;
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
* @param string|null $logicalOperator
|
||||
* @param string $mathFunction
|
||||
*/
|
||||
public function __construct( $column, $comparisonOperator, $value, $logicalOperator, $mathFunction = null ) {
|
||||
$this->column = trim( $column );
|
||||
$this->comparisonOperator = $this->getComparisonOperator( $comparisonOperator );
|
||||
$this->value = $value;
|
||||
$this->logicalOperator = $logicalOperator ? $this->getLogicalOperator( $logicalOperator ) : '';
|
||||
$this->mathFunction = $this->getMathFunction( $mathFunction );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $logicalOperator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getLogicalOperator( $logicalOperator ) {
|
||||
$operators = [
|
||||
Operator::_AND,
|
||||
Operator::_OR
|
||||
];
|
||||
|
||||
$logicalOperator = strtoupper( $logicalOperator );
|
||||
|
||||
if ( ! in_array( $logicalOperator, $operators, true ) ) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unsupported logical operator %s. Please use one of the supported operators (%s)',
|
||||
$logicalOperator,
|
||||
implode( ',', $operators )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $logicalOperator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $comparisonOperator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getComparisonOperator( $comparisonOperator ) {
|
||||
$operators = [
|
||||
'<',
|
||||
'<=',
|
||||
'>',
|
||||
'>=',
|
||||
'<>',
|
||||
'!=',
|
||||
'='
|
||||
];
|
||||
|
||||
if ( ! in_array( $comparisonOperator, $operators, true ) ) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unsupported comparison operator %s. Please use one of the supported operators (%s)',
|
||||
$comparisonOperator,
|
||||
implode( ',', $operators )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $comparisonOperator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $mathFunction
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function getMathFunction( $mathFunction ) {
|
||||
if ( array_key_exists( $mathFunction, Math::getTypes() ) ) {
|
||||
return $mathFunction;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\QueryBuilder;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\JoinType;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Join {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $table;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $joinType;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $alias;
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param string $joinType \StellarWP\DB\QueryBuilder\Types\JoinType
|
||||
* @param string|null $alias
|
||||
*/
|
||||
public function __construct( $joinType, $table, $alias = '' ) {
|
||||
$this->table = QueryBuilder::prefixTable( $table );
|
||||
$this->joinType = $this->getJoinType( $joinType );
|
||||
$this->alias = is_scalar( $alias ) ? trim( (string) $alias ) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getJoinType( $type ) {
|
||||
$type = strtoupper( $type );
|
||||
|
||||
if ( array_key_exists( $type, JoinType::getTypes() ) ) {
|
||||
return $type;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Join type %s is not supported. Please provide one of the supported join types (%s)',
|
||||
$type,
|
||||
implode( ',', JoinType::getTypes() )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\Operator;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class JoinCondition {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $logicalOperator;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $column1;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $column2;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $quote;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $logicalOperator
|
||||
* @param string $column1
|
||||
* @param string $column2
|
||||
* @param bool $quote
|
||||
*/
|
||||
public function __construct( $logicalOperator, $column1, $column2, $quote = false ) {
|
||||
$this->logicalOperator = $this->getLogicalOperator( $logicalOperator );
|
||||
$this->column1 = trim( $column1 );
|
||||
$this->column2 = trim( $column2 );
|
||||
$this->quote = $quote;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $operator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getLogicalOperator( $operator ) {
|
||||
$operator = strtoupper( $operator );
|
||||
|
||||
$supportedOperators = [
|
||||
Operator::ON,
|
||||
Operator::_AND,
|
||||
Operator::_OR
|
||||
];
|
||||
|
||||
if ( ! in_array( $operator, $supportedOperators, true ) ) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unsupported logical operator %s. Please provide one of the supported operators (%s)',
|
||||
$operator,
|
||||
implode( ',', $supportedOperators )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $operator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\QueryBuilder;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class MetaTable {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $tableName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $keyColumnName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $valueColumnName;
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param string $metaKeyColumnName
|
||||
* @param string $metaValueColumnName
|
||||
*/
|
||||
public function __construct( $table, $metaKeyColumnName, $metaValueColumnName ) {
|
||||
$this->tableName = QueryBuilder::prefixTable( $table );
|
||||
$this->keyColumnName = trim( $metaKeyColumnName );
|
||||
$this->valueColumnName = trim( $metaValueColumnName );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class OrderBy {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $column;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $direction;
|
||||
|
||||
/**
|
||||
* @param $column
|
||||
* @param $direction
|
||||
*/
|
||||
public function __construct( $column, $direction ) {
|
||||
$this->column = trim( $column );
|
||||
$this->direction = $this->getSortDirection( $direction );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $direction
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getSortDirection( $direction ) {
|
||||
$direction = strtoupper( $direction );
|
||||
$directions = ['ASC', 'DESC'];
|
||||
|
||||
if ( ! in_array( $direction, $directions, true ) ) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unsupported sort direction %s. Please use one of the (%s)',
|
||||
$direction,
|
||||
implode( ',', $directions )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $direction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class RawSQL {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sql;
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
* @param array<int,mixed>|string|null $args
|
||||
*/
|
||||
public function __construct( $sql, $args = null ) {
|
||||
$this->sql = $args ? DB::prepare( $sql, $args ) : $sql;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Select {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $column;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $alias;
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string|null $alias
|
||||
*/
|
||||
public function __construct( $column, $alias = '' ) {
|
||||
$this->column = trim( $column );
|
||||
$this->alias = is_scalar( $alias ) ? trim( (string) $alias ) : '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\QueryBuilder;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Union {
|
||||
/**
|
||||
* @var QueryBuilder
|
||||
*/
|
||||
public $builder;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $all = false;
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $builder
|
||||
* @param bool $all
|
||||
*/
|
||||
public function __construct( $builder, $all = false ) {
|
||||
$this->builder = $builder;
|
||||
$this->all = $all;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\Operator;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Where {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $column;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $comparisonOperator;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $logicalOperator;
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param mixed $value
|
||||
* @param string $comparisonOperator
|
||||
* @param string|null $logicalOperator
|
||||
*/
|
||||
public function __construct( $column, $value, $comparisonOperator, $logicalOperator ) {
|
||||
$this->column = trim( $column );
|
||||
$this->value = $value;
|
||||
$this->comparisonOperator = $this->getComparisonOperator( $comparisonOperator );
|
||||
$this->logicalOperator = $logicalOperator ? $this->getLogicalOperator( $logicalOperator ) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $comparisonOperator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getComparisonOperator( $comparisonOperator ) {
|
||||
$operators = [
|
||||
'<',
|
||||
'<=',
|
||||
'>',
|
||||
'>=',
|
||||
'<>',
|
||||
'!=',
|
||||
'=',
|
||||
Operator::LIKE,
|
||||
Operator::NOTLIKE,
|
||||
Operator::IN,
|
||||
Operator::NOTIN,
|
||||
Operator::BETWEEN,
|
||||
Operator::NOTBETWEEN,
|
||||
Operator::ISNULL,
|
||||
Operator::NOTNULL
|
||||
];
|
||||
|
||||
if ( ! in_array( $comparisonOperator, $operators, true ) ) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unsupported comparison operator %s. Please use one of the supported operators (%s)',
|
||||
$comparisonOperator,
|
||||
implode( ',', $operators )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $comparisonOperator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $logicalOperator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getLogicalOperator( $logicalOperator ) {
|
||||
$operators = [
|
||||
Operator::_AND,
|
||||
Operator::_OR
|
||||
];
|
||||
|
||||
$logicalOperator = strtoupper( $logicalOperator );
|
||||
|
||||
if ( ! in_array( $logicalOperator, $operators, true ) ) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Unsupported logical operator %s. Please use one of the supported operators (%s)',
|
||||
$logicalOperator,
|
||||
implode( ',', $operators )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $logicalOperator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait Aggregate {
|
||||
/**
|
||||
* Returns the number of rows returned by a query
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param null|string $column
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count( $column = null ) {
|
||||
$column = ( ! $column || $column === '*' ) ? '1' : trim( $column );
|
||||
|
||||
$this->selects[] = new RawSQL( 'SELECT COUNT(%1s) AS count', $column );
|
||||
|
||||
$result = $this->get();
|
||||
|
||||
if ( is_array( $result ) ) {
|
||||
return +$result['count'];
|
||||
}
|
||||
|
||||
return +$result->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total sum in a set of values
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $column
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
public function sum( $column ) {
|
||||
$this->selects[] = new RawSQL( 'SELECT SUM(%1s) AS sum', $column );
|
||||
|
||||
$result = $this->get();
|
||||
|
||||
if ( is_array( $result ) ) {
|
||||
return +$result['sum'];
|
||||
}
|
||||
|
||||
return +$result->sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the average value in a set of values
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $column
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
public function avg( $column ) {
|
||||
$this->selects[] = new RawSQL( 'SELECT AVG(%1s) AS avg', $column );
|
||||
|
||||
$result = $this->get();
|
||||
|
||||
if ( is_array( $result ) ) {
|
||||
return +$result['avg'];
|
||||
}
|
||||
|
||||
return +$result->avg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum value in a set of values
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $column
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
public function min( $column ) {
|
||||
$this->selects[] = new RawSQL( 'SELECT MIN(%1s) AS min', $column );
|
||||
|
||||
$result = $this->get();
|
||||
|
||||
if ( is_array( $result ) ) {
|
||||
return +$result['min'];
|
||||
}
|
||||
|
||||
return +$result->min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value in a set of values
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $column
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
public function max( $column ) {
|
||||
$this->selects[] = new RawSQL( 'SELECT MAX(%1s) AS max', $column );
|
||||
|
||||
$result = $this->get();
|
||||
|
||||
if ( is_array( $result ) ) {
|
||||
return +$result['max'];
|
||||
}
|
||||
|
||||
return +$result->max;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait CRUD {
|
||||
/**
|
||||
* @see https://developer.wordpress.org/reference/classes/wpdb/insert/
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array|string $format
|
||||
*
|
||||
* @param array $data
|
||||
* @return false|int
|
||||
*
|
||||
*/
|
||||
public function insert( $data, $format = null ) {
|
||||
return DB::insert(
|
||||
$this->getTable(),
|
||||
$data,
|
||||
$format
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://developer.wordpress.org/reference/classes/wpdb/update/
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $data
|
||||
* @param array|string|null $format
|
||||
*
|
||||
* @return false|int
|
||||
*
|
||||
*/
|
||||
public function update( $data, $format = null ) {
|
||||
return DB::update(
|
||||
$this->getTable(),
|
||||
$data,
|
||||
$this->getWhere(),
|
||||
$format,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upsert allows for inserting or updating a row depending on whether it already exists.
|
||||
*
|
||||
* @since 1.0.8
|
||||
*
|
||||
* @param array<string, string|int|float|bool|null> $data The data to insert or update.
|
||||
* @param array $match The columns to match on.
|
||||
* @param string|array|null $format Array of formats to be mapped to each value in $data. If string, the format will be used for all values in $data.
|
||||
*
|
||||
* @return false|int Number of rows updated/inserted, false on error.
|
||||
*/
|
||||
public function upsert( $data, $match = [], $format = null ) {
|
||||
// Build the where clause(s).
|
||||
foreach ( $match as $column ) {
|
||||
$this->where( $column, $data[ $column ] );
|
||||
}
|
||||
|
||||
// If the row exists, update it.
|
||||
if ( $this->get() ) {
|
||||
return $this->update( $data, $format );
|
||||
}
|
||||
|
||||
// Otherwise, insert it.
|
||||
return $this->insert( $data, $format );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete rows from the database.
|
||||
*
|
||||
* Unlike WordPress's $wpdb->delete() method, this implementation generates and executes
|
||||
* a DELETE SQL statement directly, which allows for advanced features like ORDER BY and LIMIT.
|
||||
*
|
||||
* Supports:
|
||||
* - WHERE clauses (including whereLike, whereIn, whereBetween, etc.)
|
||||
* - ORDER BY for controlling which rows are deleted first
|
||||
* - LIMIT to restrict the number of rows deleted
|
||||
* - Complex WHERE conditions (AND, OR, nested queries)
|
||||
*
|
||||
* Usage examples:
|
||||
* ```php
|
||||
* // Simple delete with WHERE
|
||||
* DB::table('posts')->where('post_status', 'draft')->delete();
|
||||
*
|
||||
* // Delete with LIMIT (delete only 10 rows)
|
||||
* DB::table('posts')->where('post_type', 'temp')->limit(10)->delete();
|
||||
*
|
||||
* // Delete oldest posts first using ORDER BY and LIMIT
|
||||
* DB::table('posts')
|
||||
* ->where('post_status', 'trash')
|
||||
* ->orderBy('post_date', 'ASC')
|
||||
* ->limit(100)
|
||||
* ->delete();
|
||||
*
|
||||
* // Delete with LIKE pattern
|
||||
* DB::table('posts')->whereLike('post_title', 'Draft:%')->delete();
|
||||
*
|
||||
* // Delete with multiple conditions
|
||||
* DB::table('posts')
|
||||
* ->where('post_type', 'page')
|
||||
* ->where('post_status', 'auto-draft')
|
||||
* ->whereBetween('ID', 1, 1000)
|
||||
* ->delete();
|
||||
* ```
|
||||
*
|
||||
* Restrictions:
|
||||
* - Table aliases in the FROM clause may not be supported on older database versions
|
||||
* (MySQL < 8.0.24, MariaDB < 11.6). Avoid using table aliases with delete().
|
||||
* - JOINs are not supported in DELETE statements with this implementation
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return false|int Number of rows deleted, or false on error.
|
||||
*
|
||||
* @see QueryBuilder::deleteSQL() for the SQL generation logic
|
||||
*/
|
||||
public function delete() {
|
||||
return DB::query( $this->deleteSQL() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get results
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $output ARRAY_A|ARRAY_N|OBJECT|OBJECT_K
|
||||
*
|
||||
* @return array|object|null
|
||||
*/
|
||||
public function getAll( $output = OBJECT ) {
|
||||
return DB::get_results( $this->getSQL(), $output );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get row
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $output ARRAY_A|ARRAY_N|OBJECT|OBJECT_K
|
||||
*
|
||||
* @return array|object|null
|
||||
*/
|
||||
public function get( $output = OBJECT ) {
|
||||
return DB::get_row( $this->getSQL(), $output );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getTable() {
|
||||
return $this->froms[0]->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
private function getWhere() {
|
||||
$wheres = [];
|
||||
|
||||
foreach ( $this->wheres as $where ) {
|
||||
$wheres[ $where->column ] = $where->value;
|
||||
}
|
||||
|
||||
return $wheres;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\From;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait FromClause {
|
||||
/**
|
||||
* @var From[]
|
||||
*/
|
||||
protected $froms = [];
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function from( $table, $alias = '' ) {
|
||||
$this->froms[] = new From( $table, $alias );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string[]
|
||||
*/
|
||||
protected function getFromSQL() {
|
||||
if ( empty( $this->froms ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'FROM ' . implode(
|
||||
', ',
|
||||
array_map( function ( From $from ) {
|
||||
if ( $from->alias ) {
|
||||
return DB::prepare(
|
||||
'%1s AS %2s',
|
||||
$from->table,
|
||||
$from->alias
|
||||
);
|
||||
}
|
||||
|
||||
return DB::prepare( '%1s', $from->table );
|
||||
}, $this->froms )
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait GroupByStatement {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $groupByColumns = [];
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function groupBy( $tableColumn ) {
|
||||
if ( ! in_array( $tableColumn, $this->groupByColumns, true ) ) {
|
||||
$this->groupByColumns[] = DB::prepare( '%1s', $tableColumn );
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getGroupBySQL() {
|
||||
return ! empty( $this->groupByColumns )
|
||||
? [ 'GROUP BY ' . implode( ',', $this->groupByColumns ) ]
|
||||
: [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\Having;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\Math;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\Operator;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait HavingClause {
|
||||
/**
|
||||
* @var Having[]|RawSQL[]
|
||||
*/
|
||||
protected $havings = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $includeHavingKeyword = true;
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string $value
|
||||
* @param null|string $mathFunction \StellarWP\DB\QueryBuilder\Types\Math
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
*/
|
||||
public function having( $column, $comparisonOperator, $value, $mathFunction = null ) {
|
||||
$this->havings[] = new Having(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
empty( $this->havings ) ? null : Operator::_AND,
|
||||
$mathFunction
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string $value
|
||||
* @param null|string $mathFunction \StellarWP\DB\QueryBuilder\Types\Math
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orHaving( $column, $comparisonOperator, $value, $mathFunction = null ) {
|
||||
$this->havings[] = new Having(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
empty( $this->havings ) ? null : Operator::_OR,
|
||||
$mathFunction
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function havingCount( $column, $comparisonOperator, $value ) {
|
||||
return $this->having(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::COUNT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orHavingCount( $column, $comparisonOperator, $value ) {
|
||||
return $this->orHaving(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::COUNT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function havingMin( $column, $comparisonOperator, $value ) {
|
||||
return $this->having(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::MIN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orHavingMin( $column, $comparisonOperator, $value ) {
|
||||
return $this->orHaving(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::MIN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function havingMax( $column, $comparisonOperator, $value ) {
|
||||
return $this->having(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::MAX
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orHavingMax( $column, $comparisonOperator, $value ) {
|
||||
return $this->orHaving(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::MAX
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function havingAvg( $column, $comparisonOperator, $value ) {
|
||||
return $this->having(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::AVG
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orHavingAvg( $column, $comparisonOperator, $value ) {
|
||||
return $this->orHaving(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::AVG
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function havingSum( $column, $comparisonOperator, $value ) {
|
||||
return $this->having(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::SUM
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $comparisonOperator
|
||||
* @param string|int $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orHavingSum( $column, $comparisonOperator, $value ) {
|
||||
return $this->orHaving(
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$value,
|
||||
Math::SUM
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw SQL HAVING clause
|
||||
*
|
||||
* @param string $sql
|
||||
* @param ...$args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function havingRaw( $sql, ...$args ) {
|
||||
$this->havings[] = new RawSQL( $sql, $args );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getHavingSQL() {
|
||||
if ( empty( $this->havings ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$havings = [];
|
||||
|
||||
foreach ( $this->havings as $i => $having ) {
|
||||
if ( $having instanceof RawSQL ) {
|
||||
if ( $i === 0 ) {
|
||||
// If the first element is an instance of RawSQL
|
||||
// then we don't need the starting HAVING keyword because we assume that the dev will include that in RawSQL
|
||||
$this->includeHavingKeyword = false;
|
||||
}
|
||||
$havings[] = $having->sql;
|
||||
continue;
|
||||
}
|
||||
|
||||
$havings[] = $this->buildHavingSQL( $having );
|
||||
}
|
||||
|
||||
if ( $this->includeHavingKeyword ) {
|
||||
return array_merge( ['HAVING'], $havings );
|
||||
}
|
||||
|
||||
return $havings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Having $having
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function buildHavingSQL( Having $having ) {
|
||||
if ( $having->mathFunction ) {
|
||||
return DB::prepare(
|
||||
"%1s %2s(%3s) %4s %s",
|
||||
$having->logicalOperator,
|
||||
$having->mathFunction,
|
||||
$having->column,
|
||||
$having->comparisonOperator,
|
||||
$having->value
|
||||
);
|
||||
}
|
||||
|
||||
return DB::prepare(
|
||||
"%1s %s %3s %s",
|
||||
$having->logicalOperator,
|
||||
$having->column,
|
||||
$having->comparisonOperator,
|
||||
$having->value
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use Closure;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\JoinQueryBuilder;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\Join;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait JoinClause {
|
||||
|
||||
/**
|
||||
* @var Closure[]|RawSQL[]
|
||||
*/
|
||||
protected $joins = [];
|
||||
|
||||
/**
|
||||
* Method used to build advanced JOIN queries, Check README.md for more info.
|
||||
* If you need to perform only simple JOINs with only one JOIN condition, then you don't need this method.
|
||||
*
|
||||
* @param Closure $callback The closure will receive a StellarWP\DB\QueryBuilder\JoinQueryBuilder instance
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function join( $callback ) {
|
||||
$this->joins[] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string $column1
|
||||
* @param string $column2
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function leftJoin( $table, $column1, $column2, $alias = '' ) {
|
||||
$this->join(
|
||||
function ( JoinQueryBuilder $builder ) use ( $table, $column1, $column2, $alias ) {
|
||||
$builder
|
||||
->leftJoin( $table, $alias )
|
||||
->on( $column1, $column2 );
|
||||
}
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string $column1
|
||||
* @param string $column2
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function innerJoin( $table, $column1, $column2, $alias = '' ) {
|
||||
$this->join(
|
||||
function ( JoinQueryBuilder $builder ) use ( $table, $column1, $column2, $alias ) {
|
||||
$builder
|
||||
->innerJoin( $table, $alias )
|
||||
->on( $column1, $column2 );
|
||||
}
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string $column1
|
||||
* @param string $column2
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function rightJoin( $table, $column1, $column2, $alias = '' ) {
|
||||
$this->join(
|
||||
function ( JoinQueryBuilder $builder ) use ( $table, $column1, $column2, $alias ) {
|
||||
$builder
|
||||
->rightJoin( $table, $alias )
|
||||
->on( $column1, $column2 );
|
||||
}
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add raw SQL JOIN clause
|
||||
*
|
||||
* @param string $sql
|
||||
* @param ...$args
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function joinRaw( $sql, ...$args ) {
|
||||
$this->joins[] = new RawSQL( $sql, $args );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getJoinSQL() {
|
||||
return array_map(function ( $callback ) {
|
||||
if ( $callback instanceof RawSQL ) {
|
||||
return $callback->sql;
|
||||
}
|
||||
|
||||
$builder = new JoinQueryBuilder();
|
||||
|
||||
call_user_func( $callback, $builder );
|
||||
|
||||
$joins = array_map( function ( $join ) {
|
||||
if ( $join instanceof RawSQL ) {
|
||||
return $join->sql;
|
||||
}
|
||||
|
||||
if ( $join instanceof Join ) {
|
||||
if ( $join->alias ) {
|
||||
return DB::prepare(
|
||||
'%1s JOIN %2s %3s',
|
||||
$join->joinType,
|
||||
$join->table,
|
||||
$join->alias
|
||||
);
|
||||
}
|
||||
|
||||
return DB::prepare(
|
||||
'%1s JOIN %2s',
|
||||
$join->joinType,
|
||||
$join->table
|
||||
);
|
||||
}
|
||||
|
||||
// JoinCondition
|
||||
return DB::prepare(
|
||||
$join->quote
|
||||
? ' %1s %2s = %s'
|
||||
: ' %1s %2s = %3s',
|
||||
$join->logicalOperator,
|
||||
$join->column1,
|
||||
$join->column2
|
||||
);
|
||||
}, $builder->getDefinedJoins() );
|
||||
|
||||
return implode( ' ', $joins );
|
||||
}, $this->joins );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait LimitStatement {
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $limit;
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function limit( $limit ) {
|
||||
$this->limit = (int) $limit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getLimitSQL() {
|
||||
return $this->limit
|
||||
? [ "LIMIT {$this->limit}" ]
|
||||
: [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\MetaTable;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\JoinQueryBuilder;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\QueryBuilder;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait MetaQuery {
|
||||
|
||||
/**
|
||||
* @var MetaTable[]
|
||||
*/
|
||||
private $metaTablesConfigs = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $defaultMetaKeyColumn = 'meta_key';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $defaultMetaValueColumn = 'meta_value';
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string $metaKeyColumn
|
||||
* @param string $metaValueColumn
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function configureMetaTable( $table, $metaKeyColumn, $metaValueColumn ) {
|
||||
$this->metaTablesConfigs[] = new MetaTable(
|
||||
$table,
|
||||
$metaKeyColumn,
|
||||
$metaValueColumn
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
*
|
||||
* @return MetaTable
|
||||
*/
|
||||
protected function getMetaTable( $table ) {
|
||||
$tableName = QueryBuilder::prefixTable( $table );
|
||||
|
||||
foreach ( $this->metaTablesConfigs as $metaTable ) {
|
||||
if ( $metaTable->tableName === $tableName ) {
|
||||
return $metaTable;
|
||||
}
|
||||
}
|
||||
|
||||
return new MetaTable(
|
||||
$table,
|
||||
$this->defaultMetaKeyColumn,
|
||||
$this->defaultMetaValueColumn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select meta columns
|
||||
*
|
||||
* @since 1.0.0 optimize group concat functionality
|
||||
* @since 1.0.0 add group concat functionality
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string|RawSQL $table
|
||||
* @param string $foreignKey
|
||||
* @param string $primaryKey
|
||||
* @param array|string $columns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function attachMeta( $table, $foreignKey, $primaryKey, ...$columns ) {
|
||||
$metaTable = $this->getMetaTable( $table );
|
||||
|
||||
foreach ( $columns as $i => $definition ) {
|
||||
if ( is_array( $definition ) ) {
|
||||
list( $column, $columnAlias, $concat ) = array_pad( $definition, 3, false );
|
||||
} else {
|
||||
$column = $definition;
|
||||
$columnAlias = $concat = false;
|
||||
}
|
||||
|
||||
// Set dynamic alias
|
||||
$tableAlias = sprintf('%s_%s_%d', ( $table instanceof RawSQL ) ? $table->sql : $table, 'attach_meta', $i);
|
||||
|
||||
// Check if we have meta columns that dev wants to group concat
|
||||
if ( $concat ) {
|
||||
/**
|
||||
* Include foreign key to prevent errors if sql_mode is only_full_group_by
|
||||
*
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
|
||||
*/
|
||||
$this->groupBy( $foreignKey );
|
||||
|
||||
// Group concat same key values into faux array
|
||||
// @example key => ["value1", "value2"]
|
||||
$this->selectRaw(
|
||||
"CONCAT('[',GROUP_CONCAT(DISTINCT CONCAT('\"',%1s,'\"')),']') AS %2s",
|
||||
$tableAlias . '.' . $metaTable->valueColumnName,
|
||||
$columnAlias ?: $column
|
||||
);
|
||||
} else {
|
||||
$this->select( [ "{$tableAlias}.{$metaTable->valueColumnName}", $columnAlias ?: $column ] );
|
||||
}
|
||||
|
||||
$this->join(
|
||||
function ( JoinQueryBuilder $builder ) use (
|
||||
$table,
|
||||
$foreignKey,
|
||||
$primaryKey,
|
||||
$tableAlias,
|
||||
$column,
|
||||
$metaTable
|
||||
) {
|
||||
$builder
|
||||
->leftJoin( $table, $tableAlias )
|
||||
->on( $foreignKey, "{$tableAlias}.{$primaryKey}" )
|
||||
->andOn( "{$tableAlias}.{$metaTable->keyColumnName}", $column, true );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait OffsetStatement {
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $offset;
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function offset( $offset ) {
|
||||
$this->offset = (int) $offset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getOffsetSQL() {
|
||||
return $this->limit && $this->offset
|
||||
? [ "OFFSET {$this->offset}" ]
|
||||
: [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\OrderBy;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait OrderByStatement {
|
||||
/**
|
||||
* @var OrderBy[]
|
||||
*/
|
||||
protected $orderBys = [];
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $direction ASC|DESC
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orderBy( $column, $direction = 'ASC' ) {
|
||||
$this->orderBys[] = new OrderBy( $column, $direction );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string[]
|
||||
*/
|
||||
protected function getOrderBySQL() {
|
||||
if ( empty( $this->orderBys ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$orderBys = implode(
|
||||
', ',
|
||||
array_map( function ( OrderBy $order ) {
|
||||
return DB::prepare( '%1s %2s', $order->column, $order->direction );
|
||||
}, $this->orderBys )
|
||||
);
|
||||
|
||||
|
||||
return [ 'ORDER BY ' . $orderBys ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\Select;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait SelectStatement {
|
||||
/**
|
||||
* @var Select[]|RawSQL[]
|
||||
*/
|
||||
protected $selects = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $distinct = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $includeSelectKeyword = true;
|
||||
|
||||
/**
|
||||
* @param array|string $columns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function select( ...$columns ) {
|
||||
$selects = array_map(function ( $select ) {
|
||||
if ( is_array( $select ) ) {
|
||||
list( $column, $alias ) = $select;
|
||||
|
||||
return new Select( $column, $alias );
|
||||
}
|
||||
|
||||
return new Select( $select );
|
||||
}, $columns );
|
||||
|
||||
$this->selects = array_merge( $this->selects, $selects );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw SQL SELECT statement
|
||||
*
|
||||
* @param string $sql
|
||||
* @param ...$args
|
||||
*/
|
||||
public function selectRaw( $sql, ...$args ) {
|
||||
$this->selects[] = new RawSQL( $sql, $args );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Select distinct
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function distinct() {
|
||||
$this->distinct = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getSelectSQL() {
|
||||
// Select all by default
|
||||
if ( empty( $this->selects ) ) {
|
||||
$this->select( '*' );
|
||||
}
|
||||
|
||||
$selects = [];
|
||||
|
||||
foreach ( $this->selects as $i => $select ) {
|
||||
if ( $select instanceof RawSQL ) {
|
||||
if ( $i === 0 ) {
|
||||
// If the first element is an instance of RawSQL
|
||||
// then we don't need the starting SELECT keyword because we assume that the dev will include that in RawSQL
|
||||
$this->includeSelectKeyword = false;
|
||||
}
|
||||
$selects[] = $select->sql;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $select->alias ) {
|
||||
$selects[] = DB::prepare(
|
||||
'%1s AS %2s',
|
||||
$select->column,
|
||||
$select->alias
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$selects[] = DB::prepare( '%1s', $select->column );
|
||||
}
|
||||
|
||||
$selectStatements = implode( ', ', $selects );
|
||||
|
||||
if ( $this->includeSelectKeyword ) {
|
||||
$keyword = 'SELECT ';
|
||||
|
||||
if ( $this->distinct ) {
|
||||
$keyword .= 'DISTINCT ';
|
||||
}
|
||||
|
||||
return [ $keyword . $selectStatements ];
|
||||
}
|
||||
|
||||
return [ $selectStatements ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait TablePrefix {
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function prefixTable( $table ) {
|
||||
global $wpdb;
|
||||
|
||||
// Shared tables in multisite environment
|
||||
$sharedTables = [
|
||||
'users' => $wpdb->users,
|
||||
'usermeta' => $wpdb->usermeta,
|
||||
];
|
||||
|
||||
if ( $table instanceof RawSQL ) {
|
||||
return $table->sql;
|
||||
}
|
||||
|
||||
if ( array_key_exists( $table, $sharedTables ) ) {
|
||||
return $sharedTables[ $table ];
|
||||
}
|
||||
|
||||
return $wpdb->prefix . $table;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\Union;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\QueryBuilder;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait UnionOperator {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $unions = [];
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $union
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function union( ...$union ) {
|
||||
$this->unions = array_map( function ( QueryBuilder $builder ) {
|
||||
return new Union( $builder );
|
||||
}, $union );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $union
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function unionAll( ...$union ) {
|
||||
$this->unions = array_map( function ( QueryBuilder $builder ) {
|
||||
return new Union( $builder, true );
|
||||
}, $union );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string[]
|
||||
*/
|
||||
protected function getUnionSQL() {
|
||||
if ( empty( $this->unions ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_map( function ( Union $union ) {
|
||||
return ( $union->all ? 'UNION ALL ' : 'UNION ' ) . $union->builder->getSQL();
|
||||
}, $this->unions );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns;
|
||||
|
||||
use Closure;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\DB;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\Where;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\QueryBuilder;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\Operator;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\WhereQueryBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
trait WhereClause {
|
||||
|
||||
/**
|
||||
* @var Where[]|RawSQL[]|string[]
|
||||
*/
|
||||
protected $wheres = [];
|
||||
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $includeWhereKeyword = true;
|
||||
|
||||
/**
|
||||
* @param string|Closure|null $column The Closure will receive a StellarWP\DB\QueryBuilder\WhereQueryBuilder instance
|
||||
* @param string|Closure|array|null|mixed $value The Closure will receive a StellarWP\DB\QueryBuilder\QueryBuilder instance
|
||||
* @param string $comparisonOperator
|
||||
* @param string $logicalOperator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
private function setWhere( $column, $value, $comparisonOperator, $logicalOperator ) {
|
||||
// If the columns is a Closure instance, we will assume the developer
|
||||
// wants to begin a nested where statement which is wrapped in parentheses.
|
||||
if ( $column instanceof Closure && is_null( $value ) ) {
|
||||
$builder = new WhereQueryBuilder();
|
||||
call_user_func( $column, $builder );
|
||||
|
||||
// Since this is a nested where statement, we have to remove the starting WHERE keyword
|
||||
// which is the first returned array element from the getWhereSQL method
|
||||
$wheres = $builder->getSQL();
|
||||
array_shift( $wheres );
|
||||
|
||||
$this->wheres[] = sprintf(
|
||||
"%s (%s)",
|
||||
empty( $this->wheres ) ? null : $logicalOperator,
|
||||
implode( ' ', $wheres )
|
||||
);
|
||||
} // If the value is a Closure instance, we will assume the developer is performing an entire sub-select within the query
|
||||
elseif ( $value instanceof Closure ) {
|
||||
$builder = new QueryBuilder();
|
||||
call_user_func( $value, $builder );
|
||||
|
||||
$this->wheres[] = sprintf(
|
||||
"%s %s %s (%s)",
|
||||
empty( $this->wheres ) ? null : $logicalOperator,
|
||||
$column,
|
||||
$comparisonOperator,
|
||||
$builder->getSQL()
|
||||
);
|
||||
} // Standard WHERE clause
|
||||
else {
|
||||
$this->wheres[] = new Where(
|
||||
$column,
|
||||
$value,
|
||||
$comparisonOperator,
|
||||
empty( $this->wheres ) ? null : $logicalOperator
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|Closure|null $column The closure will receive a StellarWP\DB\QueryBuilder\WhereQueryBuilder instance
|
||||
* @param string|Closure|array|null|mixed $value The closure will receive a StellarWP\DB\QueryBuilder\QueryBuilder instance
|
||||
* @param string $comparisonOperator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function where( $column, $value = null, $comparisonOperator = '=' ) {
|
||||
return $this->setWhere(
|
||||
$column,
|
||||
$value,
|
||||
$comparisonOperator,
|
||||
Operator::_AND
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|Closure $column
|
||||
* @param string|Closure|array|null|mixed $value
|
||||
* @param string $comparisonOperator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhere( $column, $value = null, $comparisonOperator = '=' ) {
|
||||
return $this->setWhere(
|
||||
$column,
|
||||
$value,
|
||||
$comparisonOperator,
|
||||
Operator::_OR
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param array|Closure $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereIn( $column, $value ) {
|
||||
return $this->where(
|
||||
$column,
|
||||
$value,
|
||||
Operator::IN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param array|Closure $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhereIn( $column, $value ) {
|
||||
return $this->orWhere(
|
||||
$column,
|
||||
$value,
|
||||
Operator::IN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param array|Closure $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereNotIn( $column, $value ) {
|
||||
return $this->where(
|
||||
$column,
|
||||
$value,
|
||||
Operator::NOTIN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param array|Closure $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhereNotIn( $column, $value ) {
|
||||
return $this->orWhere(
|
||||
$column,
|
||||
$value,
|
||||
Operator::NOTIN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string|int $min
|
||||
* @param string|int $max
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereBetween( $column, $min, $max ) {
|
||||
return $this->where(
|
||||
$column,
|
||||
[ $min, $max ],
|
||||
Operator::BETWEEN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string|int $min
|
||||
* @param string|int $max
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereNotBetween( $column, $min, $max ) {
|
||||
return $this->where(
|
||||
$column,
|
||||
[ $min, $max ],
|
||||
Operator::NOTBETWEEN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string|int $min
|
||||
* @param string|int $max
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhereBetween( $column, $min, $max ) {
|
||||
return $this->orWhere(
|
||||
$column,
|
||||
[ $min, $max ],
|
||||
Operator::BETWEEN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string|int $min
|
||||
* @param string|int $max
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhereNotBetween( $column, $min, $max ) {
|
||||
return $this->orWhere(
|
||||
$column,
|
||||
[ $min, $max ],
|
||||
Operator::NOTBETWEEN
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereLike( $column, $value ) {
|
||||
return $this->where(
|
||||
$column,
|
||||
$value,
|
||||
Operator::LIKE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereNotLike( $column, $value ) {
|
||||
return $this->where(
|
||||
$column,
|
||||
$value,
|
||||
Operator::NOTLIKE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhereLike( $column, $value ) {
|
||||
return $this->orWhere(
|
||||
$column,
|
||||
$value,
|
||||
Operator::LIKE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhereNotLike( $column, $value ) {
|
||||
return $this->orWhere(
|
||||
$column,
|
||||
$value,
|
||||
Operator::NOTLIKE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereIsNull( $column ) {
|
||||
return $this->where(
|
||||
$column,
|
||||
null,
|
||||
Operator::ISNULL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhereIsNull( $column ) {
|
||||
return $this->orWhere(
|
||||
$column,
|
||||
null,
|
||||
Operator::ISNULL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereIsNotNull( $column ) {
|
||||
return $this->where(
|
||||
$column,
|
||||
null,
|
||||
Operator::NOTNULL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhereIsNotNull( $column ) {
|
||||
return $this->orWhere(
|
||||
$column,
|
||||
null,
|
||||
Operator::NOTNULL
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Closure $callback The closure will receive a StellarWP\DB\QueryBuilder\QueryBuilder instance
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereExists( $callback ) {
|
||||
return $this->where(
|
||||
null,
|
||||
$callback,
|
||||
Operator::EXISTS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure $callback The closure will receive a StellarWP\DB\QueryBuilder\QueryBuilder instance
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereNotExists( $callback ) {
|
||||
return $this->where(
|
||||
null,
|
||||
$callback,
|
||||
Operator::NOTEXISTS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw SQL WHERE clause
|
||||
*
|
||||
* @param $sql
|
||||
* @param ...$args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereRaw( $sql, ...$args ) {
|
||||
$this->wheres[] = new RawSQL( $sql, $args );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getWhereSQL() {
|
||||
// Bailout
|
||||
if ( empty( $this->wheres ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$wheres = [];
|
||||
|
||||
foreach ( $this->wheres as $i => $where ) {
|
||||
if ( $where instanceof RawSQL ) {
|
||||
if ( $i === 0 ) {
|
||||
// If the first element is an instance of RawSQL
|
||||
// then we don't need the starting WHERE keyword because we assume that the dev will include that in RawSQL
|
||||
$this->includeWhereKeyword = false;
|
||||
}
|
||||
$wheres[] = $where->sql;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $where instanceof Where ) {
|
||||
$wheres[] = $this->buildWhereSQL( $where );
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the variable $where is not an instance of the Where class
|
||||
// it means the SQL is already generated by the Query Builder, so we just return that
|
||||
$wheres[] = $where;
|
||||
}
|
||||
|
||||
|
||||
if ( $this->includeWhereKeyword ) {
|
||||
return array_merge( ['WHERE'], $wheres );
|
||||
}
|
||||
|
||||
return $wheres;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Where $where
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function buildWhereSQL( Where $where ) {
|
||||
switch ( $where->comparisonOperator ) {
|
||||
// Handle membership conditions
|
||||
case Operator::IN:
|
||||
case Operator::NOTIN:
|
||||
|
||||
return DB::prepare(
|
||||
"%1s %2s %3s",
|
||||
$where->logicalOperator,
|
||||
$where->column,
|
||||
$where->comparisonOperator
|
||||
) . ' (' . implode(
|
||||
',',
|
||||
array_map( function ( $where ) {
|
||||
return DB::prepare( '%s', $where );
|
||||
}, $where->value )
|
||||
) . ')';
|
||||
|
||||
// Handle BETWEEN conditions
|
||||
case Operator::BETWEEN:
|
||||
case Operator::NOTBETWEEN:
|
||||
list( $min, $max ) = $where->value;
|
||||
|
||||
return DB::prepare(
|
||||
"%1s %2s %3s %s AND %s",
|
||||
$where->logicalOperator,
|
||||
$where->column,
|
||||
$where->comparisonOperator,
|
||||
$min,
|
||||
$max
|
||||
);
|
||||
|
||||
// Handle LIKE conditions
|
||||
case Operator::LIKE:
|
||||
case Operator::NOTLIKE:
|
||||
return DB::prepare(
|
||||
"%1s %2s %3s %s",
|
||||
$where->logicalOperator,
|
||||
$where->column,
|
||||
$where->comparisonOperator,
|
||||
strpos( $where->value, '%' ) !== false
|
||||
? $where->value
|
||||
: sprintf( '%%%s%%', $where->value )
|
||||
);
|
||||
|
||||
// Handle NULL conditions
|
||||
case Operator::ISNULL:
|
||||
case Operator::NOTNULL:
|
||||
return DB::prepare(
|
||||
"%1s %2s %3s",
|
||||
$where->logicalOperator,
|
||||
$where->column,
|
||||
$where->comparisonOperator
|
||||
);
|
||||
|
||||
// Standard WHERE clause
|
||||
default:
|
||||
return DB::prepare(
|
||||
"%1s %2s %3s %s",
|
||||
$where->logicalOperator,
|
||||
$where->column,
|
||||
$where->comparisonOperator,
|
||||
$where->value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\Join;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\JoinCondition;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\JoinType;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types\Operator;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class JoinQueryBuilder {
|
||||
/**
|
||||
* @var Join[]|JoinCondition[]|RawSQL[]
|
||||
*/
|
||||
private $joins = [];
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function leftJoin( $table, $alias = '' ) {
|
||||
return $this->join(
|
||||
JoinType::LEFT,
|
||||
$table,
|
||||
$alias
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function rightJoin( $table, $alias = '' ) {
|
||||
return $this->join(
|
||||
JoinType::RIGHT,
|
||||
$table,
|
||||
$alias
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|RawSQL $table
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function innerJoin( $table, $alias = '' ) {
|
||||
return $this->join(
|
||||
JoinType::INNER,
|
||||
$table,
|
||||
$alias
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column1
|
||||
* @param string $column2
|
||||
* @param bool $quote
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function on( $column1, $column2, $quote = false ) {
|
||||
return $this->joinCondition(
|
||||
Operator::ON,
|
||||
$column1,
|
||||
$column2,
|
||||
$quote
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column1
|
||||
* @param string $column2
|
||||
* @param bool $quote
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function andOn( $column1, $column2, $quote = null ) {
|
||||
return $this->joinCondition(
|
||||
Operator::_AND,
|
||||
$column1,
|
||||
$column2,
|
||||
$quote
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column1
|
||||
* @param string $column2
|
||||
* @param bool $quote
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orOn( $column1, $column2, $quote = null ) {
|
||||
return $this->joinCondition(
|
||||
Operator::_OR,
|
||||
$column1,
|
||||
$column2,
|
||||
$quote
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw SQL JOIN clause
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array<int,mixed> ...$args
|
||||
*/
|
||||
public function joinRaw( $sql, ...$args ) {
|
||||
$this->joins[] = new RawSQL( $sql, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Join
|
||||
*
|
||||
* @param string $joinType
|
||||
* @param string|RawSQL $table
|
||||
* @param string|null $alias
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
private function join( $joinType, $table, $alias = '' ) {
|
||||
$this->joins[] = new Join(
|
||||
$joinType,
|
||||
$table,
|
||||
$alias
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add JoinCondition
|
||||
*
|
||||
* @param string $operator
|
||||
* @param string $column1
|
||||
* @param string $column2
|
||||
* @param bool $quote
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
private function joinCondition( $operator, $column1, $column2, $quote ) {
|
||||
$this->joins[] = new JoinCondition(
|
||||
$operator,
|
||||
$column1,
|
||||
$column2,
|
||||
$quote
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Join[]|JoinCondition[]|RawSQL[]
|
||||
*/
|
||||
public function getDefinedJoins() {
|
||||
return $this->joins;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\Aggregate;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\CRUD;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\FromClause;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\GroupByStatement;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\HavingClause;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\JoinClause;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\LimitStatement;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\MetaQuery;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\OffsetStatement;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\OrderByStatement;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\SelectStatement;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\TablePrefix;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\UnionOperator;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\WhereClause;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class QueryBuilder {
|
||||
use Aggregate;
|
||||
use CRUD;
|
||||
use FromClause;
|
||||
use GroupByStatement;
|
||||
use HavingClause;
|
||||
use JoinClause;
|
||||
use LimitStatement;
|
||||
use MetaQuery;
|
||||
use OffsetStatement;
|
||||
use OrderByStatement;
|
||||
use SelectStatement;
|
||||
use TablePrefix;
|
||||
use UnionOperator;
|
||||
use WhereClause;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSQL() {
|
||||
$sql = array_merge(
|
||||
$this->getSelectSQL(),
|
||||
$this->getFromSQL(),
|
||||
$this->getJoinSQL(),
|
||||
$this->getWhereSQL(),
|
||||
$this->getGroupBySQL(),
|
||||
$this->getHavingSQL(),
|
||||
$this->getOrderBySQL(),
|
||||
$this->getLimitSQL(),
|
||||
$this->getOffsetSQL(),
|
||||
$this->getUnionSQL()
|
||||
);
|
||||
|
||||
return $this->buildSQL($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL for a DELETE query. Only the FROM, WHERE, ORDER BY, and LIMIT clauses are included.
|
||||
* RETURNING is not supported.
|
||||
* Note that aliases are supported only on MySQL >= 8.0.24 and MariaDB >= 11.6.
|
||||
*
|
||||
* @see https://mariadb.com/docs/server/reference/sql-statements/data-manipulation/changing-deleting-data/delete
|
||||
* @see https://dev.mysql.com/doc/refman/8.4/en/delete.html
|
||||
*
|
||||
* @return string DELETE query.
|
||||
*/
|
||||
public function deleteSQL() {
|
||||
$sql = array_merge(
|
||||
$this->getFromSQL(),
|
||||
$this->getWhereSQL(),
|
||||
$this->getOrderBySQL(),
|
||||
$this->getLimitSQL()
|
||||
);
|
||||
|
||||
return 'DELETE ' . $this->buildSQL($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SQL query from the given parts.
|
||||
*
|
||||
* @param array $sql The SQL query parts.
|
||||
*
|
||||
* @return string SQL query.
|
||||
*/
|
||||
private function buildSQL( $sql ) {
|
||||
return str_replace(
|
||||
[ ' ', ' ' ],
|
||||
' ',
|
||||
implode( ' ', $sql )
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class JoinType extends Type {
|
||||
const INNER = 'INNER';
|
||||
const LEFT = 'LEFT';
|
||||
const RIGHT = 'RIGHT';
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Math extends Type {
|
||||
const SUM = 'SUM';
|
||||
const MIN = 'MIN';
|
||||
const MAX = 'MAX';
|
||||
const COUNT = 'COUNT';
|
||||
const AVG = 'AVG';
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Operator extends Type {
|
||||
// _AND and _OR constants are prefixed with underscore to be compatible with PHP 5.6
|
||||
const _AND = 'AND';
|
||||
const _OR = 'OR';
|
||||
const ON = 'ON';
|
||||
const BETWEEN = 'BETWEEN';
|
||||
const NOTBETWEEN = 'NOT BETWEEN';
|
||||
const EXISTS = 'EXISTS';
|
||||
const NOTEXISTS = 'NOT EXISTS';
|
||||
const IN = 'IN';
|
||||
const NOTIN = 'NOT IN';
|
||||
const LIKE = 'LIKE';
|
||||
const NOTLIKE = 'NOT LIKE';
|
||||
const NOT = 'NOT';
|
||||
const ISNULL = 'IS NULL';
|
||||
const NOTNULL = 'IS NOT NULL';
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Types;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract class Type {
|
||||
/**
|
||||
* Get Defined Types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getTypes() {
|
||||
return ( new ReflectionClass( static::class ) )->getConstants();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\DB\QueryBuilder\Concerns\WhereClause;
|
||||
|
||||
/**
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class WhereQueryBuilder {
|
||||
use WhereClause;
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSQL() {
|
||||
return $this->getWhereSQL();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user