Skip to content

Commit fea905a

Browse files
committed
Version 1.0
0 parents  commit fea905a

File tree

179 files changed

+11671
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

179 files changed

+11671
-0
lines changed

.githooks/pre-commit

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
3+
PHP_CS_FIXER="vendor/bin/php-cs-fixer"
4+
5+
if [ ! -x $PHP_CS_FIXER ]; then
6+
echo ""
7+
echo "php-cs-fixer not found. Try:"
8+
echo ""
9+
echo " composer install"
10+
echo ""
11+
exit 1
12+
fi
13+
14+
FILES=`git status --porcelain | grep -E '^[AM] +(src|tests).*\.php$' | cut -c 4- | tr '\n' ' '`
15+
if [ -z "$FILES" ]; then
16+
echo "No php files found in commit."
17+
else
18+
output=`php -l ${FILES}`
19+
OUT=$?
20+
if [ $OUT != '0' ]; then
21+
echo "$output"
22+
echo ""
23+
echo "Please correct and recommit"
24+
25+
exit 1
26+
fi
27+
28+
$PHP_CS_FIXER fix --config=.php-cs-fixer.dist.php ${FILES} >/dev/null 2>&1
29+
git add ${FILES}
30+
fi

.github/dependabot.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: composer
4+
directory: "/"
5+
schedule:
6+
interval: daily
7+
time: "10:00"
8+
open-pull-requests-limit: 10

.github/workflows/tests.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Tests
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
php-tests:
7+
runs-on: ${{ matrix.os }}
8+
strategy:
9+
fail-fast: true
10+
matrix:
11+
php: [8.2, 8.1]
12+
dependency-version: [prefer-stable]
13+
os: [ubuntu-latest, windows-latest]
14+
15+
name: ${{ matrix.os }} - PHP${{ matrix.php }} - ${{ matrix.dependency-version }}
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v3
20+
21+
- name: Cache dependencies
22+
uses: actions/cache@v3
23+
with:
24+
path: ~/.composer/cache/files
25+
key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
26+
27+
- name: Setup PHP
28+
uses: shivammathur/setup-php@v2
29+
with:
30+
php-version: ${{ matrix.php }}
31+
extensions: dom, curl, libxml, mbstring, zip, intl, pdo_sqlite
32+
coverage: none
33+
34+
- name: Install dependencies
35+
run: |
36+
composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction
37+
38+
- name: Execute tests
39+
run: vendor/bin/phpunit
40+

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
vendor/
2+
.idea/
3+
bin/
4+
composer.lock
5+
.php-cs-fixer.cache
6+
.phpunit.result.cache
7+
phpunit.xml
8+

.php-cs-fixer.dist.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
/*
3+
* This document has been generated with
4+
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.0.0-rc.1|configurator
5+
* you can change this configuration by importing this file.
6+
*
7+
*/
8+
9+
$config = include 'vendor/phpfui/phpunit-syntax-coverage/PhpCsFixer.php';
10+
11+
return $config->setFinder(PhpCsFixer\Finder::create()
12+
->exclude('vendor')
13+
->in(__DIR__.'\src')
14+
->in(__DIR__.'\tests')
15+
);

CODE_OF_CONDUCT.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6+
7+
## Our Standards
8+
9+
Examples of behavior that contributes to creating a positive environment include:
10+
11+
* Using welcoming and inclusive language
12+
* Being respectful of differing viewpoints and experiences
13+
* Gracefully accepting constructive criticism
14+
* Focusing on what is best for the community
15+
* Showing empathy towards other community members
16+
17+
Examples of unacceptable behavior by participants include:
18+
19+
* The use of sexualized language or imagery and unwelcome sexual attention or advances
20+
* Trolling, insulting/derogatory comments, and personal or political attacks
21+
* Public or private harassment
22+
* Publishing others' private information, such as a physical or electronic address, without explicit permission
23+
* Other conduct which could reasonably be considered inappropriate in a professional setting
24+
25+
## Our Responsibilities
26+
27+
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28+
29+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30+
31+
## Scope
32+
33+
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34+
35+
## Enforcement
36+
37+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project owner. They will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38+
39+
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40+
41+
## Attribution
42+
43+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44+
45+
[homepage]: http://contributor-covenant.org
46+
[version]: http://contributor-covenant.org/version/1/4/

LICENSE

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Copyright 2019 Bruce K. Wells
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a
4+
copy of this software and associated documentation files (the "Software"),
5+
to deal in the Software without restriction, including without limitation
6+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
7+
and/or sell copies of the Software, and to permit persons to whom the
8+
Software is furnished to do so, subject to the following conditions: The
9+
above copyright notice and this permission notice shall be included in all
10+
copies or substantial portions of the Software.
11+
12+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18+
DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# PHPFUI\ORM [![Tests](https://github.com/phpfui/ORM/actions/workflows/tests.yml/badge.svg)](https://github.com/phpfui/ORM/actions?query=workflow%3Atests) [![Latest Packagist release](https://img.shields.io/packagist/v/phpfui/ORM.svg)](https://packagist.org/packages/phpfui/ORM) ![](https://img.shields.io/badge/PHPStan-level%206-brightgreen.svg?style=flat)
2+
3+
### PHPFUI\ORM a minimal Object Relational Mapper (ORM) for MySQL, MariaDB and SQLite3
4+
Why another PHP ORM? In writing minimal and fast websites, it was determined that existing PHP ORM solutions were overly complex. **PHPFUI\ORM** is less than 6k lines of code in under 50 files. It is designed to have a minimal memory footprint and excellent execution times for most database needs.
5+
6+
**PHPFUI\ORM** is not an attempt to write an abstraction around SQL as other ORMs do, rather it is a way to work with SQL that closely matches the semantics of SQL, with the power of PHP objects. It allows PHP to manipulate SQL queries without having to write SQL in plain text. This is very useful for queries generated via user interfaces where the user is given a lot of flexability in how a query is defined.
7+
8+
## Features
9+
- **Active Records** that present a fully type checked object interface and implement basic CRUD functionality.
10+
- **Active Tables** for full table operations including support for where, having, limits, ordering, grouping, joins and unions.
11+
- **Data Cursors** that implement **iterable** and **Countable** eliminating the need for full arrays read into memory.
12+
- **Validation** for fully customizable and translatable backend validation.
13+
- **Virtual Fields** for get and set semantics.
14+
- **Migrations** simple migrations offer atomic up and down migrations.
15+
- **Relations** for parent, children, one to one, many to many, and custom relationships.
16+
- **Type Safe** to prevent stupid type errors.
17+
- **Raw SQL Query Support** execute any valid SQL command.
18+
- **MultiDatabase Support** built on PDO with support for MySQL, MariaDB and SQLite.
19+
20+
## Usage
21+
### Setup
22+
```php
23+
$pdo = new \PHPFUI\ORM\PDOInstance($yourConnectionString);
24+
// permform any custom configuration settings needed on $pdo
25+
\PHPFUI\ORM::addConnection($pdo);
26+
```
27+
28+
### Active Record Example
29+
```php
30+
$book = new \App\Record\Book();
31+
$book->title = 'PHP ORM: The Right Way';
32+
$book->price = 24.99;
33+
34+
$author = new \App\Record\Author();
35+
$author->name = 'Bruce Wells';
36+
37+
$book->author = $author; // Save the author
38+
$book->save(); // Save the book
39+
```
40+
41+
### Active Table Example
42+
```php
43+
$bookTable = new \App\Table\Book();
44+
$bookTable->setWhere(new \PHPFUI\ORM\Condition('title', '%orm%', new \PHPFUI\ORM\Operator\Like()));
45+
$bookTable->join('author');
46+
47+
foreach ($bookTable->getDataObjectCursor() as $book)
48+
{
49+
echo "{$book->title} by {$book->name} is $ {$book->price}\n";
50+
}
51+
52+
// discount all PHP books to 19.99
53+
$bookTableUpdater = new \App\Table\Book();
54+
$bookTableUpdater->setWhere(new \PHPFUI\ORM\Condition('title', '%PHP%', new \PHPFUI\ORM\Operator\Like()));
55+
$bookTableUpdater->update(['price' => 19.99]);
56+
57+
foreach ($bookTableUpdater->getRecordCursor() as $book)
58+
{
59+
echo "{$book->title} by {$book->author->name} is now $ {$book->price}\n";
60+
}
61+
```
62+
63+
### Validation Example
64+
```php
65+
$book->title = 'This title is way to long for the database and will return a validation error. We should write a migration to make it varchar(255)!';
66+
$errors = $book->validate();
67+
foreach ($errors as $field => $fieldErrors)
68+
{
69+
echo "Field {$field} has the following errors:\n";
70+
foreach ($fieldErrors as $error)
71+
{
72+
echo $error . "\n";
73+
}
74+
}
75+
```
76+
77+
### Migration Example
78+
Migrations are atomic and can be run in groups or individually up or down.
79+
80+
```php
81+
namespace App\Migration;
82+
83+
class Migration_1 extends \PHPFUI\ORM\Migration
84+
{
85+
86+
public function description() : string
87+
{
88+
return 'Lengthen book.title field to 255';
89+
}
90+
91+
public function up() : bool
92+
{
93+
return $this->alterColumn('book', 'title', 'varchar(255) not null');
94+
}
95+
96+
public function down() : bool
97+
{
98+
return $this->alterColumn('book', 'title', 'varchar(50) not null');
99+
}
100+
}
101+
```
102+
103+
## Type Safety
104+
### Exceptions Supported
105+
Exceptions are generated in the following conditions:
106+
- Accessing field or offset that does not exist
107+
- Deleting records without a where condition (can be overridden)
108+
- Incorrect type for Operator (must be an array for **IN** for example)
109+
- Passing an incorrect type as a primary key
110+
- Invalid join type
111+
- Requesting a **RecordCursor** with a table join
112+
- Joining on an invalid table
113+
114+
All of the above exceptions are programmer errors and strictly enforced. Empty queries are not considered errors. SQL may also return [Exceptions](https://www.php.net/manual/en/class.exception.php) if invalid fields are used.
115+
116+
### Type Conversions
117+
If you set a field to the wrong type, the library logs an error then converts the type via the appropriate PHP cast.
118+
119+
## Multiple Database Support
120+
While this is primarily a single database ORM, you can switch databases at run time. Save the value from `$connectionId = \PHPFUI\ORM::addConnection($pdo);` and then call `\PHPFUI\ORM::useConnection($db);` to switch. `\PHPFUI\ORM::addConnection` will set the current connection.
121+
122+
The programmer must make sure the proper database is currently selected when database reads or writes happen and that any primary keys are correctly handled.
123+
124+
### Copy tables example:
125+
```php
126+
// get the current connection just for fun
127+
$currentConnection = \PHPFUI\ORM::getConnection();
128+
129+
$cursors = [];
130+
// getRecordCursor will bind the cursor to the current database instance
131+
$cursors[] = (new \App\Table\Author())->getRecordCursor();
132+
$cursors[] = (new \App\Table\Book())->getRecordCursor();
133+
134+
// set up a new database connection
135+
$pdo = new \PDO($newConnectionString);
136+
$newConnectionId = \PHPFUI\ORM::addConnection($pdo);
137+
138+
foreach ($cursors as $cursor)
139+
{
140+
foreach ($cursor as $record)
141+
{
142+
$record->insert(); // insert into new database ($newConnectionId)
143+
}
144+
}
145+
// back to the original database
146+
\PHPFUI\ORM::useConnection($currentConnection);
147+
```
148+
149+
## Documentation
150+
+ [Setup](docs/1. Setup.md)
151+
+ [Active Record](docs/2. Active Record.md)
152+
+ [Active Table](docs/3. Active Table.md)
153+
+ [Cursors](docs/4. Cursors.md)
154+
+ [Virtual Fields](docs/5. Virtual Fields.md)
155+
+ [Migrations](docs/6. Migrations.md)
156+
+ [Validation](docs/7. Validation.md)
157+
+ [Translations](docs/8. Translations.md)
158+
+ [Miscellaneous](docs/9. Miscellaneous.md)
159+
160+
## Full Class Documentation
161+
[PHPFUI/ORM](http://phpfui.com/?n=PHPFUI\ORM)
162+
163+
## License
164+
PHPFUI is distributed under the MIT License.
165+
166+
## PHP Versions
167+
This library only supports **modern** versions of PHP which still receive security updates. While we would love to support PHP from the late Ming Dynasty, the advantages of modern PHP versions far out weigh quaint notions of backward compatibility. Time to upgrade.

Tests/App/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Ignore everything
2+
*
3+
4+
# But not these files...
5+
!.gitignore
6+
7+
# ...even if they are in subdirectories
8+
!*/

Tests/Fixtures/Definition/Alpha.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Tests\Fixtures\Definition;
4+
5+
abstract class Alpha extends \PHPFUI\ORM\Record
6+
{
7+
public static bool $autoIncrement = false;
8+
9+
public static array $fields = [
10+
'alpha' => ['sqltype', 'string', 19, false, '', false, ],
11+
];
12+
13+
public static string $primaryKey = '';
14+
15+
public static string $table = '';
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Tests\Fixtures\Definition;
4+
5+
abstract class Alpha_numeric extends \PHPFUI\ORM\Record
6+
{
7+
public static bool $autoIncrement = false;
8+
9+
public static array $fields = [
10+
'alpha_numeric' => ['sqltype', 'string', 19, false, '', false, ],
11+
];
12+
13+
public static string $primaryKey = '';
14+
15+
public static string $table = '';
16+
}

Tests/Fixtures/Definition/Card.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Tests\Fixtures\Definition;
4+
5+
abstract class Card extends \PHPFUI\ORM\Record
6+
{
7+
public static bool $autoIncrement = false;
8+
9+
public static array $fields = [
10+
'card' => ['sqltype', 'string', 19, false, '', false, ],
11+
];
12+
13+
public static string $primaryKey = '';
14+
15+
public static string $table = '';
16+
}

0 commit comments

Comments
 (0)