Skip to content

Commit

Permalink
chore: merge develop into feature/number-field (#528)
Browse files Browse the repository at this point in the history
* badge

* Feature/set custom edit exec button (#490)

* fix one test

* Setting current dependencies

* use custom exec button on edit action

* Update Model.php

* remove class, use seed

Co-authored-by: Imants Horsts <[email protected]>

* model default add field property (#454)

* use the object default add field property

* no need for double brackets.

* force tests

Co-authored-by: Romans Malinovskis <[email protected]>
Co-authored-by: Imants Horsts <[email protected]>

* Fix empty array condition (#498)

* more tests

* Apply fixes from StyleCI

* better implementation for addFields() and test cases (#499)

* better implementation for addFields() and test cases

* Apply fixes from StyleCI

* use shorthand method

* simplify code

* implement `exprNow()` method. Rely on dsql PR.

* Apply fixes from StyleCI

* pass

* add docs

Co-authored-by: Romans Malinovskis <[email protected]>

* Fix/ Small Action related fix (#502)

* Fix/ Small Action related fix

- Set Edit action exec button labe lto 'Save' by default
 - Set Edit action exec button colot to blue by default
- Set default description for Add action in model
- Add method to retreive model from Action

* Apply fixes from StyleCI

* fix comment

Co-authored-by: Imants Horsts <[email protected]>

* update multiple delete example (#503)

* now supports multiple filter options in getFields()

* Apply fixes from StyleCI

* Accept any DateTimeInterface impl. for datetime (#505)

* Accept any DateTimeInterface impl. for datetime

* Fix DateTime::getTimezone method name

* Fix setTimezone for any instance of DateTimeInterface

* Add microseconds persistence support for datetime/time types + fix normalization/cloning issue (#504)

* Fix datetime normalization cloning

* Add microseconds persistence support for datetime/time types

Co-authored-by: Imants Horsts <[email protected]>

* include comment about hooks and example how to execute them (#510)

* update composer

* Update release-drafter.yml

* Update bundler.yml

* Fix hasOne relation seed processing. It should replace not merge. (#512)

* New method $model->getTitles() (#513)

* Implement `getTitles()` method

* Apply fixes from StyleCI

* Update unit-tests.yml

* migration to migrator

* rename addHook to onHook (#514)

* fix #944 (#516)

* allow dots in table names, fix #515, fix #517

* Apply fixes from StyleCI

* Do not fail-fast PHP test matrix (#522)

* Simplify code (#519)

* Update release-drafter.yml

* Update release-drafter.yml

* Fix hook trait usage (#525)

* Hook args must be an array

* Fix hook onHook() usage

* Apply fixes from StyleCI

* initialization of fields and handling of expressions

* Apply fixes from StyleCI

* introduce hasPersistence and retrieval of setting

* Apply fixes from StyleCI

Co-authored-by: Imants Horsts <[email protected]>
Co-authored-by: Mimo <[email protected]>
Co-authored-by: Romans Malinovskis <[email protected]>
Co-authored-by: Alain Belair <[email protected]>
Co-authored-by: DarkSide <[email protected]>
Co-authored-by: Michael Voříšek <[email protected]>
  • Loading branch information
7 people authored Mar 28, 2020
1 parent a8bd575 commit 48aa012
Show file tree
Hide file tree
Showing 47 changed files with 739 additions and 545 deletions.
19 changes: 8 additions & 11 deletions .github/workflows/bundler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,29 @@ jobs:
- run: echo ${{ github.ref }}
- name: Update to stable dependencies
run: |
jq 'del(.require["atk4/core"]) | del(.require["atk4/dsql"]) | del(.["require-dev"]["atk4/schema"])' < composer.json > tmp && mv tmp composer.json
composer require --no-progress --no-suggest --prefer-dist --optimize-autoloader atk4/core atk4/dsql
composer require --no-progress --no-suggest --prefer-dist --optimize-autoloader --dev atk4/schema
composer update --no-progress --no-suggest --prefer-dist --optimize-autoloader
# replaces X keys with X-release keys
jq '. as $in | reduce (keys_unsorted[] | select(endswith("-release")|not)) as $k ({}; . + {($k) : (($k + "-release") as $kr | $in | if has($kr) then .[$kr] else .[$k] end) } )' < composer.json > tmp && mv tmp composer.json
v=$(echo ${{ github.ref }} | cut -d / -f 4)
echo "::set-env name=version::$v"
- uses: teaminkling/autocommit@master
with:
commit-message: Setting current dependencies
commit-message: Setting release dependencies
- uses: ad-m/github-push-action@master
with:
branch: ${{ github.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: pull-request
uses: repo-sync/pull-request@v2
uses: romaninsh/pull-request@master
with:
source_branch: "" # If blank, default: triggered branch
source_branch: "release/${{ env.version }}"
destination_branch: "master" # If blank, default: master
pr_title: "Releasing ${{ github.ref }} into master"
pr_title: "Releasing ${{ env.version }} into master"
pr_body: |
- [ ] Review changes (must include stable dependencies)
- [ ] Merge this PR into master (will delete ${{ github.ref }})
- [ ] Go to Releases and create TAG from master
----------
Do not merge master into develop
pr_reviewer: "romaninsh"
pr_assignee: "romaninsh"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ jobs:
runs-on: ubuntu-latest
steps:
# Drafts your next Release notes as Pull Requests are merged into "master"
- uses: toolmantim/release-drafter@v5.2.0
- uses: toolmantim/release-drafter@v5.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 2 additions & 1 deletion .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
container:
image: atk4/image:${{ matrix.php }} # https://github.com/atk4/image
strategy:
fail-fast: false
matrix:
php: ['7.2', '7.3', 'latest']
services:
Expand All @@ -31,7 +32,7 @@ jobs:
POSTGRES_USER: postgres
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- run: php --version
- name: Get Composer Cache Directory
id: composer-cache
Expand Down
98 changes: 64 additions & 34 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,39 +1,69 @@
{
"name": "atk4/data",
"type": "library",
"description": "Agile Data - Database access abstraction framework",
"keywords": ["framework", "orm", "query", "active record", "sql", "builder", "nosql", "mongodb", "mysql", "postgresql"],
"homepage": "https://github.com/atk4/data",
"license": "MIT",
"authors": [
{
"name": "Romans Malinovskis",
"email": "[email protected]",
"homepage": "https://nearly.guru/"
}
],
"require": {
"php": ">=7.2.0",
"ext-intl": "*",
"name": "atk4/data",
"type": "library",
"description": "Agile Data - Database access abstraction framework",
"keywords": [
"framework",
"orm",
"query",
"active record",
"sql",
"builder",
"nosql",
"mongodb",
"mysql",
"oracle",
"postgresql"
],
"homepage": "https://github.com/atk4/data",
"license": "MIT",
"authors": [
{
"name": "Romans Malinovskis",
"email": "[email protected]",
"homepage": "https://nearly.guru/"
}
],
"require": {
"php": ">=7.2.0",
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"atk4/core": "dev-develop",
"atk4/dsql": "dev-develop"
},
"require-dev": {
"atk4/schema": "dev-develop",
"phpunit/phpunit": "<6",
"phpunit/dbunit": ">=1.2",
"phpunit/phpcov": "*",
"codeclimate/php-test-reporter": "*"
},
"autoload": {
"psr-4": {"atk4\\data\\":"src/"}
},
"autoload-dev": {
"psr-4": {
"atk4\\data\\tests\\":"tests/",
"atk4\\data\\tests\\smbo\\":["tests/smbo","tests/smbo/lib"]
}
"atk4/core": "dev-develop",
"atk4/dsql": "dev-develop"
},
"require-release": {
"php": ">=7.2.0",
"ext-intl": "*",
"atk4/core": "^2.0",
"atk4/dsql": "^2.0"
},
"require-dev": {
"atk4/schema": "dev-develop",
"phpunit/phpunit": "<6",
"phpunit/dbunit": ">=1.2",
"phpunit/phpcov": "*",
"codeclimate/php-test-reporter": "*"
},
"require-dev-release": {
"atk4/schema": "^2.0",
"phpunit/phpunit": "<6",
"phpunit/dbunit": ">=1.2",
"phpunit/phpcov": "*",
"codeclimate/php-test-reporter": "*"
},
"autoload": {
"psr-4": {
"atk4\\data\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"atk4\\data\\tests\\": "tests/",
"atk4\\data\\tests\\smbo\\": [
"tests/smbo",
"tests/smbo/lib"
]
}
}
}
20 changes: 10 additions & 10 deletions docs/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Another scenario which could benefit by type substitution would be::
ATK Data allow class substitution during load and iteration by breaking "afterLoad"
hook. Place the following inside Transaction::init()::

$this->addHook('afterLoad', function ($m) {
$this->onHook('afterLoad', function ($m) {
if (get_class($this) != $m->getClassName()) {
$cl = '\\'.$this->getClassName();
$cl = new $cl($this->persistence);
Expand All @@ -98,7 +98,7 @@ of the record. Finally to help with performance, you can implement a switch::
..

if ($this->typeSubstitution) {
$this->addHook('afterLoad',
$this->onHook('afterLoad',
..........
)
}
Expand Down Expand Up @@ -155,7 +155,7 @@ which I want to define like this::
return;
}

$this->owner->addField('created_dts', ['type'=>'datetime', 'default'=>date('Y-m-d H:i:s')]);
$this->owner->addField('created_dts', ['type'=>'datetime', 'default'=>new \DateTime()]);

$this->owner->hasOne('created_by_user_id', 'User');
if(isset($this->app->user) and $this->app->user->loaded()) {
Expand All @@ -166,11 +166,11 @@ which I want to define like this::

$this->owner->addField('updated_dts', ['type'=>'datetime']);

$this->owner->addHook('beforeUpdate', function($m, $data) {
$this->owner->onHook('beforeUpdate', function($m, $data) {
if(isset($this->app->user) and $this->app->user->loaded()) {
$data['updated_by'] = $this->app->user->id;
}
$data['updated_dts'] = date('Y-m-d H:i:s');
$data['updated_dts'] = new \DateTime();
});
}

Expand Down Expand Up @@ -343,7 +343,7 @@ before and just slightly modifying it::
$this->owner->addMethod('restore', $this);
} else {
$this->owner->addCondition('is_deleted', false);
$this->owner->addHook('beforeDelete', [$this, 'softDelete'], null, 100);
$this->owner->onHook('beforeDelete', [$this, 'softDelete'], null, 100);
}
}

Expand Down Expand Up @@ -425,7 +425,7 @@ inside your model are unique::
$this->fields = [$this->owner->title_field];
}

$this->owner->addHook('beforeSave', $this);
$this->owner->onHook('beforeSave', $this);
}

function beforeSave($m)
Expand Down Expand Up @@ -488,7 +488,7 @@ Next we need to define reference. Inside Model_Invoice add::
$j->hasOne('invoice_id', 'Model_Invoice');
}, 'their_field'=>'invoice_id']);

$this->addHook('beforeDelete',function($m){
$this->onHook('beforeDelete',function($m){
$m->ref('InvoicePayment')->action('delete')->execute();

// If you have important per-row hooks in InvoicePayment
Expand Down Expand Up @@ -623,7 +623,7 @@ Here is how to add them. First you need to create fields::
I have declared those fields with never_persist so they will never be used by
persistence layer to load or save anything. Next I need a beforeSave handler::

$this->addHook('beforeSave', function($m) {
$this->onHook('beforeSave', function($m) {
if(isset($m['client_code']) && !isset($m['client_id'])) {
$cl = $this->refModel('client_id');
$cl->addCondition('code',$m['client_code']);
Expand Down Expand Up @@ -712,7 +712,7 @@ section. Add this into your Invoice Model::
Next both payment and lines need to be added after invoice is actually created,
so::

$this->addHook('afterSave', function($m, $is_update){
$this->onHook('afterSave', function($m, $is_update){
if(isset($m['payment'])) {
$m->ref('Payment')->insert($m['payment']);
}
Expand Down
2 changes: 1 addition & 1 deletion docs/design.rst
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ Hooks can help you perform operations when object is being persisted::
// addField() declaration
// addExpression('is_password_expired')

$this->addHook('beforeSave', function($m) {
$this->onHook('beforeSave', function($m) {
if ($m->isDirty('password')) {
$m['password'] = encrypt_password($m['password']);
$m['password_change_date'] = $m->expr('now()');
Expand Down
14 changes: 7 additions & 7 deletions docs/hooks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Example with beforeSave
The next code snippet demonstrates a basic usage of a `beforeSave` hook.
This one will update field values just before record is saved::

$m->addHook('beforeSave', function($m) {
$m->onHook('beforeSave', function($m) {
$m['name'] = strtoupper($m['name']);
$m['surname'] = strtoupper($m['surname']);
});
Expand Down Expand Up @@ -85,7 +85,7 @@ model will assume the operation was successful.

You can also break beforeLoad hook which can be used to skip rows::

$model->addHook('afterLoad', function ($m) {
$model->onHook('afterLoad', function ($m) {
if ($m['date'] < $m->date_from) {
$m->breakHook(false); // will not yield such data row
}
Expand Down Expand Up @@ -136,7 +136,7 @@ of save.

You may actually drop validation exception inside save, insert or update hooks::

$m->addHook('beforeSave', function($m) {
$m->onHook('beforeSave', function($m) {
if ($m['name'] = 'Yagi') {
throw new \atk4\data\ValidationException(['name'=>"We don't serve like you"]);
}
Expand Down Expand Up @@ -193,7 +193,7 @@ and your update() may not actually update anything. This does not normally
generate an error, however if you want to actually make sure that update() was
effective, you can implement this through a hook::

$m->addHook('afterUpdateQuery',function($m, $update, $st) {
$m->onHook('afterUpdateQuery',function($m, $update, $st) {
if (!$st->rowCount()) {
throw new \atk4\core\Exception([
'Update didn\'t affect any records',
Expand All @@ -213,7 +213,7 @@ In some cases you want to prevent default actions from executing.
Suppose you want to check 'memcache' before actually loading the record from
the database. Here is how you can implement this functionality::

$m->addHook('beforeLoad',function($m, $id) {
$m->onHook('beforeLoad',function($m, $id) {
$data = $m->app->cacheFetch($m->table, $id);
if ($data) {
$m->data = $data;
Expand All @@ -239,13 +239,13 @@ This can be used in various situations.

Save information into auditLog about failure:

$m->addHook('onRollback', function($m){
$m->onHook('onRollback', function($m){
$m->auditLog->registerFailure();
});

Upgrade schema:

$m->addHook('onRollback', function($m, $exception) {
$m->onHook('onRollback', function($m, $exception) {
if ($exception instanceof \PDOException) {
$m->schema->upgrade();
$m->breakHook(false); // exception will not be thrown
Expand Down
16 changes: 11 additions & 5 deletions docs/model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ object you can load/unload individual records (See Single record Operations belo
$m->load(8);
....

and even perform operations on multiple records (See Multiple record Operations below)::
and even perform operations on multiple records (See `Persistence Actions` below)::

$m = new User($db);
$m->addCondition('expired', true);

$m->deleteAll();
$m->action('delete')->execute(); // performs mass delete, hooks are not executed
$m->each('delete'); // deletes each record, hooks are executed

When data is loaded from associated Persistence, it is automatically converted into
a native PHP type (such as DateTime object) through a process called Typecasting. Various
Expand Down Expand Up @@ -185,7 +187,7 @@ To invoke code from `init()` methods of ALL models (for example soft-delete logi
you use Persistence's "afterAdd" hook. This will not affect ALL models but just models
which are associated with said persistence::

$db->addHook('afterAdd', function($p, $m) use($acl) {
$db->onHook('afterAdd', function($p, $m) use($acl) {

$fields = $m->getFields();

Expand Down Expand Up @@ -389,7 +391,7 @@ a hook::

$this->addField('name');

$this->addHook('validate', function($m) {
$this->onHook('validate', function($m) {
if ($m['name'] == 'C#') {
return ['name'=>'No sharp objects are allowed'];
}
Expand Down Expand Up @@ -435,7 +437,7 @@ action - `send_gift`.
There are some advanced techniques like "SubTypes" or class substitution,
for example, this hook may be placed in the "User" class init()::

$this->addHook('afterLoad', function($m) {
$this->onHook('afterLoad', function($m) {
if ($m['purchases'] > 1000) {
$this->breakHook($this->asModel(VIPUser::class);
}
Expand Down Expand Up @@ -738,6 +740,10 @@ Title Field
Return title field value of currently loaded record.

.. php:method:: public getTitles
Returns array of title field values of all model records in format [id => title].

.. _caption:

Model Caption
Expand Down
4 changes: 2 additions & 2 deletions docs/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ If your persistence does not support expressions (e.g. you are using Redis or
MongoDB), you would need to define the field differently::

$model->addField('gross');
$model->addHook('beforeSave', function($m) {
$model->onHook('beforeSave', function($m) {
$m['gross'] = $m['net'] + $m['vat'];
});

Expand All @@ -186,7 +186,7 @@ you want it to work with NoSQL, then your solution might be::

// persistence does not support expressions
$model->addField('gross');
$model->addHook('beforeSave', function($m) {
$model->onHook('beforeSave', function($m) {
$m['gross'] = $m['net'] + $m['vat'];
});

Expand Down
Loading

0 comments on commit 48aa012

Please sign in to comment.