Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require array in reference/join defaults #820

Merged
merged 3 commits into from
Dec 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class JobReport extends Job {
$invoice_lines = $invoice->ref('Lines');

// Build relation between job and invoice line
$this->hasMany('InvoiceLines', $invoice_lines)
$this->hasMany('InvoiceLines', ['model' => $invoice_lines])
->addField('invoiced', ['aggregate'=>'sum', 'field'=>'total', 'type'=>'money']);

// Next we need to see how much is reported through timesheets
Expand All @@ -152,7 +152,7 @@ class JobReport extends Job {
$timesheet->addExpression('cost', '[hours]*[hourly_rate]');

// Build relation between Job and Timesheets
$this->hasMany('Timesheets', $timesheet)
$this->hasMany('Timesheets', ['model' => $timesheet])
->addField('reported', ['aggregate'=>'sum', 'field'=>'cost', 'type'=>'money']);

// Finally lets calculate profit
Expand Down Expand Up @@ -356,7 +356,7 @@ class Client extends \Atk4\Data\Model {

$this->addFields(['name','address']);

$this->hasMany('Project', new Project());
$this->hasMany('Project', ['model' => [Project::class]]);
}
}
```
Expand Down
22 changes: 11 additions & 11 deletions docs/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ store extra fields there. In your code::
As you implement single Account and multiple Transaction types, you want to relate
both::

$account->hasMany('Transactions', new Transaction());
$account->hasMany('Transactions', ['model' => [Transaction::class]]);

There are however two difficulties here:

Expand All @@ -42,9 +42,9 @@ Best practice for specifying relation type
Although there is no magic behind it, I recommend that you use the following
code pattern when dealing with multiple types::

$account->hasMany('Transactions', new Transaction());
$account->hasMany('Transactions:Deposit', new Transaction\Deposit());
$account->hasMany('Transactions:Transfer', new Transaction\Transfer());
$account->hasMany('Transactions', ['model' => [Transaction::class]]);
$account->hasMany('Transactions:Deposit', ['model' => [Transaction\Deposit::class]]);
$account->hasMany('Transactions:Transfer', ['model' => [Transaction\Transfer::class]]);

You can then use type-specific reference::

Expand Down Expand Up @@ -510,12 +510,12 @@ Next we need to define reference. Inside Model_Invoice add::

$this->hasMany('InvoicePayment');

$this->hasMany('Payment', [function($m) {
$this->hasMany('Payment', ['model' => function($m) {
$p = new Model_Payment($m->persistence);
$j = $p->join('invoice_payment.payment_id');
$j->addField('amount_closed');
$j->hasOne('invoice_id', 'Model_Invoice');
}, 'their_field'=>'invoice_id']);
}, 'their_field' => 'invoice_id']);

$this->onHookShort(Model::HOOK_BEFORE_DELETE, function(){
$this->ref('InvoicePayment')->action('delete')->execute();
Expand Down Expand Up @@ -776,7 +776,7 @@ define Model_Document::
One option here is to move 'Model_Contact' into model property, which will be
different for the extended class::

$this->hasOne('client_id', $this->client_class);
$this->hasOne('client_id', ['model' => [$this->client_class]]);

Alternatively you can replace model in the init() method of Model_Invoice::

Expand All @@ -797,9 +797,9 @@ field only to offer payments made by the same client. Inside Model_Invoice add::

$this->hasOne('client_id', 'Client');

$this->hasOne('payment_invoice_id', function($m){
$this->hasOne('payment_invoice_id', ['model' => function($m){
return $m->ref('client_id')->ref('Payment');
});
}]);

/// how to use

Expand All @@ -825,9 +825,9 @@ Agile Data allow you to define multiple references between same entities, but
sometimes that can be quite useful. Consider adding this inside your Model_Contact::

$this->hasMany('Invoice', 'Model_Invoice');
$this->hasMany('OverdueInvoice', function($m){
$this->hasMany('OverdueInvoice', ['model' => function($m){
return $m->ref('Invoice')->addCondition('due','<',date('Y-m-d'))
});
}]);

This way if you extend your class into 'Model_Client' and modify the 'Invoice'
reference to use different model::
Expand Down
4 changes: 2 additions & 2 deletions docs/design.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,15 @@ Code (add inside `init()`)::
protected function init(): void {
parent::init();

$this->hasMany('Order', new Model_Order());
$this->hasMany('Order', ['model' => [Model_Order::class]]);
}
}

class Model_Order extends \Atk4\Data\Model {
protected function init(): void {
parent::init();

$this->hasOne('Client', new Model_Client());
$this->hasOne('Client', ['model' => [Model_Client::class]]);

// addField declarations
}
Expand Down
62 changes: 30 additions & 32 deletions docs/references.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ possible to add other reference types. The basic ones are really easy to
use::

$m = new Model_User($db, 'user');
$m->hasMany('Orders', new Model_Order());
$m->hasMany('Orders', ['model' => [Model_Order::class]]);
$m->load(13);

$orders_for_user_13 = $m->ref('Orders');
Expand All @@ -28,7 +28,7 @@ so that you could only access orders for the user with ID=13. The following is
also possible::

$m = new Model_User($db, 'user');
$m->hasMany('Orders', new Model_Order());
$m->hasMany('Orders', ['model' => [Model_Order::class]]);
$m->addCondition('is_vip', true);

$orders_for_vips = $m->ref('Orders');
Expand Down Expand Up @@ -58,7 +58,7 @@ not reside inside the same database?
You can specify it like this::

$m = new Model_User($db_array_cache, 'user');
$m->hasMany('Orders', new Model_Order($db_sql));
$m->hasMany('Orders', ['model' => [Model_Order::class, $db_sql]]);
$m->addCondition('is_vip', true);

$orders_for_vips = $m->ref('Orders');
Expand Down Expand Up @@ -100,17 +100,15 @@ If you are worried about performance you can keep 2 models in memory::
hasMany Reference
=================

.. php:method:: hasMany($link, $model);
.. php:method:: hasMany($link, ['model' => $model]);

There are several ways how to link models with hasMany::

$m->hasMany('Orders', new Model_Order()); // using object
$m->hasMany('Orders', ['model' => [Model_Order::class]]); // using seed

$m->hasMany('Order', function($m, $r) { // using callback
$m->hasMany('Order', ['model' => function($m, $r) { // using callback
return new Model_Order();
});

$m->hasMany('Order'); // will use factory new Model_Order
}]);


Dealing with many-to-many references
Expand All @@ -127,7 +125,7 @@ It is possible to perform reference through an 3rd party table::
->join('invoice_payment.payment_id')
->addFields(['amount_allocated','invoice_id']);

$i->hasMany('Payments', $p);
$i->hasMany('Payments', ['model' => $p]);

Now you can fetch all the payments associated with the invoice through::

Expand All @@ -143,7 +141,7 @@ available. Both models will relate through ``currency.code = exchange.currency_c
$c = new Model_Currency();
$e = new Model_ExchangeRate();

$c->hasMany('Exchanges', [$e, 'their_field'=>'currency_code', 'our_field'=>'code']);
$c->hasMany('Exchanges', ['model' => $e, 'their_field'=>'currency_code', 'our_field'=>'code']);

$c->addCondition('is_convertable',true);
$e = $c->ref('Exchanges');
Expand All @@ -162,7 +160,7 @@ Concatenating Fields

You may want to display want to list your related entities by concatenating. For example::

$user->hasMany('Tags', new Tag())
$user->hasMany('Tags', ['model' => [Tag::class]])
->addField('tags', ['concat'=>',', 'field'=>'name']);

This will create a new field for your user, ``tags`` which will contain all comma-separated
Expand All @@ -175,7 +173,7 @@ Reference hasMany makes it a little simpler for you to define an aggregate field

$u = new Model_User($db_array_cache, 'user');

$u->hasMany('Orders', new Model_Order())
$u->hasMany('Orders', ['model' => [Model_Order::class]])
->addField('amount', ['aggregate'=>'sum']);

It's important to define aggregation functions here. This will add another field
Expand All @@ -188,7 +186,7 @@ example::
You can also define multiple fields, although you must remember that this will
keep making your query bigger and bigger::

$invoice->hasMany('Invoice_Line', new Model_Invoice_Line())
$invoice->hasMany('Invoice_Line', ['model' => [Model_Invoice_Line::class]])
->addFields([
['total_vat', 'aggregate'=>'sum'],
['total_net', 'aggregate'=>'sum'],
Expand Down Expand Up @@ -239,7 +237,7 @@ containing your optional arguments::

Alternatively you may also specify either 'aggregate'::

$book->hasMany('Pages', new Page())
$book->hasMany('Pages', ['model' => [Page::class]])
->addField('page_list', [
'aggregate'=>$book->refModel('Pages')->expr('group_concat([number], [])', ['-'])
]);
Expand All @@ -261,7 +259,7 @@ the conditioning will be done differently. refLink is useful when defining
sub-queries::

$m = new Model_User($db_array_cache, 'user');
$m->hasMany('Orders', new Model_Order($db_sql));
$m->hasMany('Orders', ['model' => [Model_Order::class]]);
$m->addCondition('is_vip', true);

$sum = $m->refLink('Orders')->action('fx0', ['sum', 'amount']);
Expand Down Expand Up @@ -292,7 +290,7 @@ reference itself. In such case refModel() comes in as handy shortcut of doing
hasOne reference
================

.. php:method:: hasOne($link, $model)
.. php:method:: hasOne($link, ['model' => $model])

$model can be an array containing options: [$model, ...]

Expand All @@ -302,7 +300,7 @@ This reference allows you to attach a related model to a foreign key::
$o = new Model_Order($db, 'order');
$u = new Model_User($db, 'user');

$o->hasOne('user_id', $u);
$o->hasOne('user_id', ['model' => $u]);

This reference is similar to hasMany, but it does behave slightly different.
Also this reference will define a system new field ``user_id`` if you haven't
Expand Down Expand Up @@ -341,7 +339,7 @@ process and the loadAny() will look like this:
By passing options to hasOne() you can also differentiate field name::

$o->addField('user_id');
$o->hasOne('User', [$u, 'our_field'=>'user_id']);
$o->hasOne('User', ['model' => $u, 'our_field' => 'user_id']);

$o->load(1)->ref('User')['name'];

Expand All @@ -359,7 +357,7 @@ the field::
$i = new Model_Invoice($db)
$c = new Model_Currency($db);

$i->hasOne('currency_id', $c)
$i->hasOne('currency_id', ['model' => $c])
->addField('currency_name', 'name');


Expand All @@ -373,7 +371,7 @@ be renamed, just as we did above::
$u = new Model_User($db)
$a = new Model_Address($db);

$u->hasOne('address_id', $a)
$u->hasOne('address_id', ['model' => $a])
->addFields([
'address_1',
'address_2',
Expand All @@ -400,7 +398,7 @@ easier way how to define currency title::

$i = new Invoice($db)

$i->hasOne('currency_id', new Currency())
$i->hasOne('currency_id', ['model' => [Currency::class]])
->addTitle();

This would create 'currency' field containing name of the currency::
Expand All @@ -424,7 +422,7 @@ By default name of the field will be calculated by removing "_id" from the end
of hasOne field, but to override this, you can specify name of the title field
explicitly::

$i->hasOne('currency_id', new Currency())
$i->hasOne('currency_id', ['model' => [Currency::class]])
->addTitle(['field'=>'currency_name']);

User-defined Reference
Expand All @@ -435,9 +433,9 @@ User-defined Reference
Sometimes you would want to have a different type of relation between models,
so with `addRef` you can define whatever reference you want::

$m->addRef('Archive', function($m) {
$m->addRef('Archive', ['model' => function($m) {
return $m->newInstance(null, ['table' => $m->table.'_archive']);
});
}]);

The above example will work for a table structure where a main table `user` is
shadowed by a archive table `user_archive`. Structure of both tables are same,
Expand All @@ -449,7 +447,7 @@ Note that you can create one-to-many or many-to-one relations, by using your
custom logic.
No condition will be applied by default so it's all up to you::

$m->addRef('Archive', function($m) {
$m->addRef('Archive', ['model' => function($m) {
$archive = $m->newInstance(null, ['table' => $m->table.'_archive']);

$m->addField('original_id', ['type' => 'int']);
Expand All @@ -458,7 +456,7 @@ No condition will be applied by default so it's all up to you::
$archive->addCondition('original_id', $m->getId());
// only show record of currently loaded record
}
});
}]);

Reference Discovery
===================
Expand Down Expand Up @@ -524,14 +522,14 @@ when SQL is confused about which table to use.
To avoid this problem Agile Data will automatically alias tables in sub-queries.
Here is how it works::

$item->hasMany('parent_item_id', new Model_Item())
$item->hasMany('parent_item_id', ['model' => [Model_Item::class]])
->addField('parent', 'name');

When generating expression for 'parent', the sub-query will use alias ``pi``
consisting of first letters in 'parent_item_id'. (except _id). You can actually
specify a custom table alias if you want::

$item->hasMany('parent_item_id', [new Model_Item(), 'table_alias'=>'mypi'])
$item->hasMany('parent_item_id', ['model' => [Model_Item::class], 'table_alias' => 'mypi'])
->addField('parent', 'name');

Additionally you can pass table_alias as second argument into :php:meth:`Model::ref()`
Expand All @@ -548,10 +546,10 @@ that relate to itself. Here is example::
$this->addField('name');
$this->addField('age');
$i2 = $this->join('item2.item_id');
$i2->hasOne('parent_item_id', [$m, 'table_alias'=>'parent'])
$i2->hasOne('parent_item_id', ['model' => $m, 'table_alias'=>'parent'])
->addTitle();

$this->hasMany('Child', [$m, 'their_field'=>'parent_item_id', 'table_alias'=>'child'])
$this->hasMany('Child', ['model' => $m, 'their_field'=>'parent_item_id', 'table_alias'=>'child'])
->addField('child_age',['aggregate'=>'sum', 'field'=>'age']);
}
}
Expand Down Expand Up @@ -607,7 +605,7 @@ Consider the following two models::
parent::init();
$this->addField('name');

$this->hasOne('contact_id', new Model_Contact());
$this->hasOne('contact_id', ['model' => [Model_Contact::class]]);
}
}

Expand Down
Loading