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

Make $defaults param in Model::hasXxx() methods required #1184

Merged
merged 10 commits into from
Mar 15, 2024
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ $salary->where('emp_no', $employees);

// join with another table for more data
$salary
->join('employees.emp_id', 'emp_id')
->join('employees.emp_id')
->field('employees.first_name');

// finally, fetch result
Expand Down
22 changes: 11 additions & 11 deletions docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,12 @@ protected function init(): void

$this->getOwner()->addField('created_dts', ['type' => 'datetime', 'default' => new \DateTime()]);

$this->getOwner()->hasOne('created_by_user_id', 'User');
$this->getOwner()->hasOne('created_by_user_id', ['model' => [User::class]]);
if (isset($this->getApp()->user) && $this->getApp()->user->isLoaded()) {
$this->getOwner()->getField('created_by_user_id')->default = $this->getApp()->user->getId();
}

$this->getOwner()->hasOne('updated_by_user_id', 'User');
$this->getOwner()->hasOne('updated_by_user_id', ['model' => [User::class]]);

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

Expand Down Expand Up @@ -457,8 +457,8 @@ class Model_InvoicePayment extends \Atk4\Data\Model
{
parent::init();

$this->hasOne('invoice_id', 'Model_Invoice');
$this->hasOne('payment_id', 'Model_Payment');
$this->hasOne('invoice_id', ['model' => [Model_Invoice::class]]);
$this->hasOne('payment_id', ['model' => [Model_Payment::class]]);
$this->addField('amount_closed');
}
}
Expand All @@ -469,13 +469,13 @@ class Model_InvoicePayment extends \Atk4\Data\Model
Next we need to define reference. Inside Model_Invoice add:

```
$this->hasMany('InvoicePayment');
$this->hasMany('InvoicePayment', ['model' => [Model_InvoicePayment::class]]);

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

$this->onHookShort(Model::HOOK_BEFORE_DELETE, function () {
Expand Down Expand Up @@ -506,7 +506,7 @@ that shows how much amount is closed and `amount_due`:

```
// define field to see closed amount on invoice
$this->hasMany('InvoicePayment')
$this->hasMany('InvoicePayment', ['model' => [Model_InvoicePayment::class]])
->addField('total_payments', ['aggregate' => 'sum', 'field' => 'amount_closed']);
$this->addExpression('amount_due', ['expr' => '[total] - coalesce([total_payments], 0)']);
```
Expand Down Expand Up @@ -574,7 +574,7 @@ class Model_Invoice extends \Atk4\Data\Model

...

$this->hasOne('category_id', 'Model_Category');
$this->hasOne('category_id', ['model' => [Model_Category::class]]);

...
}
Expand Down Expand Up @@ -711,7 +711,7 @@ In theory Document's 'contact_id' can be any Contact, however when you create
define Model_Document:

```
$this->hasOne('client_id', 'Model_Contact');
$this->hasOne('client_id', ['model' => [Model_Contact::class]]);
```

One option here is to move 'Model_Contact' into model property, which will be
Expand Down Expand Up @@ -743,7 +743,7 @@ add 'payment_invoice_id' that points to 'Model_Payment'. However we want this
field only to offer payments made by the same client. Inside Model_Invoice add:

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

$this->hasOne('payment_invoice_id', ['model' => function (self $m) {
return $m->ref('client_id')->ref('Payment');
Expand Down Expand Up @@ -773,7 +773,7 @@ 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('Invoice', ['model' => [Model_Invoice::class]]);
$this->hasMany('OverdueInvoice', ['model' => function (self $m) {
return $m->ref('Invoice')->addCondition('due', '<', date('Y-m-d'))
}]);
Expand Down
2 changes: 1 addition & 1 deletion docs/joins.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ $user->addField('username');
$jContact = $user->join('contact');
$jContact->addField('address');
$jContact->addField('county');
$jContact->hasOne('Country');
$jContact->hasOne('Country', ['model' => [Country::class]]);
```

This code will load data from two tables simultaneously and if you do change any
Expand Down
3 changes: 2 additions & 1 deletion docs/model.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ $model->addField('secret', ['neverPersist' => true]);
$model->addField('old_field', ['actual' => 'new_field']);

// or even into a different table
$model->join('new_table')->addField('extra_field');
$model->join('new_table')
->addField('extra_field');
```

Model also has a property `$table`, which indicate name of default table/collection/file to be
Expand Down
6 changes: 3 additions & 3 deletions docs/persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ protected function init(): void
$this->getOwner()->hasOne(
$f . '_currency_id',
[
'model' => $this->currency_model ?? new Currency(),
'model' => [Currency::class],
'system' => true,
]
);
Expand Down Expand Up @@ -783,7 +783,7 @@ In conjunction with Model::refLink() you can produce expressions for creating
sub-selects. The functionality is nicely wrapped inside HasMany::addField():

```
$client->hasMany('Invoice')
$client->hasMany('Invoice', ['model' => [Model_Invoice::class]])
->addField('total_gross', ['aggregate' => 'sum', 'field' => 'gross']);
```

Expand All @@ -798,7 +798,7 @@ This operation is actually consisting of 3 following operations:
Here is a way how to intervene with the process:

```
$client->hasMany('Invoice');
$client->hasMany('Invoice', ['model' => [Model_Invoice::class]]);
$client->addExpression('last_sale', ['expr' => function (Model $m) {
return $m->refLink('Invoice')
->setOrder('date desc')
Expand Down
28 changes: 0 additions & 28 deletions docs/persistence/sql/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -541,34 +541,6 @@ $q->join('address.user_id'); // address.user_id = id
// JOIN `address` ON `address`.`user_id`=`id`
```

You can also pass array as a first argument, to join multiple tables:

```
$q->table('user u');
$q->join(['a' => 'address', 'c' => 'credit_card', 'preferences']);
```

The above code will join 3 tables using the following query syntax:

```sql
join
address as a on a.id = u.address_id
credit_card as c on c.id = u.credit_card_id
preferences on preferences.id = u.preferences_id
```

However normally you would have `user_id` field defined in your supplementary
tables so you need a different syntax:

```
$q->table('user u');
$q->join([
'a' => 'address.user_id',
'c' => 'credit_card.user_id',
'preferences.user_id',
]);
```

The second argument to join specifies which existing table/field is
used in `on` condition:

Expand Down
2 changes: 1 addition & 1 deletion docs/persistence/sql/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ $salary->where('emp_no', $employees);

// join with another table for more data
$salary
->join('employees.emp_id', 'emp_id')
->join('employees.emp_id')
->field('employees.first_name');

// finally, fetch result
Expand Down
7 changes: 4 additions & 3 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ unions but only if the database server supports those operations.
Developer would normally create a declaration like this:

```
$user->hasMany('Order')->addField('total', ['aggregate' => 'sum']);
$user->hasMany('Order', ['model' => [Order::class]])
->addField('total', ['aggregate' => 'sum']);
```

It is up to Agile Data to decide what's the most efficient way to implement
Expand Down Expand Up @@ -273,7 +274,7 @@ class Model_User extends Model
$j->addField('address_1');
$j->addField('address_2');
$j->addField('address_3');
$j->hasOne('country_id', 'Country');
$j->hasOne('country_id', ['model' => [Model_Country::class]]);
}
}
```
Expand Down Expand Up @@ -441,7 +442,7 @@ As per our database design - one user can have multiple 'system' records:

```
$m = new Model_User($db);
$m->hasMany('System');
$m->hasMany('System', ['model' => [Model_System::class]]);
```

Next you can load a specific user and traverse into System model:
Expand Down
7 changes: 2 additions & 5 deletions docs/references.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ There are several ways how to link models with hasMany:
```
$m->hasMany('Orders', ['model' => [Model_Order::class]]); // using seed

$m->hasMany('Order', ['model' => function (Model $m, $r) { // using callback
$m->hasMany('Order', ['model' => static function (Model $m, Reference $r, array $defaults) { // using callback
return new Model_Order();
}]);
```
Expand Down Expand Up @@ -154,10 +154,7 @@ available. Both models will relate through `currency.code = exchange.currency_co

```
$c = new Model_Currency();
$e = new Model_ExchangeRate();

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

$c->hasMany('Exchanges', ['model' => [Model_ExchangeRate::class], 'theirField' => 'currency_code', 'ourField' => 'code']);
$c->addCondition('is_convertible', true);
$e = $c->ref('Exchanges');
```
Expand Down
2 changes: 0 additions & 2 deletions docs/typecasting.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ Many databases will allow you to use different types for ID fields.
In SQL the 'id' column will usually be "integer", but sometimes it can be of
a different type.

The same applies for references ($m->hasOne()).

### Supported types

- 'string' - for storing short strings, such as name of a person. Normalize will trim the value.
Expand Down
10 changes: 5 additions & 5 deletions src/Model/Join.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ abstract class Join
*
* If you are using the following syntax:
*
* $user->join('contact', 'default_contact_id')
* $user->join('contact.default_contact_id')
*
* Then the ID connecting tables is stored in foreign table and the order
* of saving and delete needs to be reversed. In this case $reverse
Expand Down Expand Up @@ -371,7 +371,7 @@ public function leftJoin(string $foreignTable, array $defaults = []): self
*
* @return Reference\HasOne
*/
public function hasOne(string $link, array $defaults = [])
public function hasOne(string $link, array $defaults): Reference
{
$defaults['joinName'] = $this->getJoinNameFromShortName();

Expand All @@ -385,7 +385,7 @@ public function hasOne(string $link, array $defaults = [])
*
* @return Reference\HasMany
*/
public function hasMany(string $link, array $defaults = [])
public function hasMany(string $link, array $defaults): Reference
{
return $this->getOwner()->hasMany($link, $defaults);
}
Expand All @@ -400,7 +400,7 @@ public function hasMany(string $link, array $defaults = [])
*
* @return Reference\ContainsOne
*X/
public function containsOne(string $link, array $defaults = []) // : Reference
public function containsOne(string $link, array $defaults): Reference
{
$defaults['joinName'] = $this->getJoinNameFromShortName();

Expand All @@ -416,7 +416,7 @@ public function containsOne(string $link, array $defaults = []) // : Reference
*
* @return Reference\ContainsMany
*X/
public function containsMany(string $link, array $defaults = []) // : Reference
public function containsMany(string $link, array $defaults): Reference
{
return $this->getOwner()->containsMany($link, $defaults);
}
Expand Down
10 changes: 5 additions & 5 deletions src/Model/ReferencesTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ trait ReferencesTrait
* @param array<mixed> $seed
* @param array<string, mixed> $defaults
*/
protected function _addReference(array $seed, string $link, array $defaults = []): Reference
protected function _addReference(array $seed, string $link, array $defaults): Reference
{
$this->assertIsModel();

Expand Down Expand Up @@ -69,7 +69,7 @@ public function addReference(string $link, array $defaults): Reference
*
* @return Reference\HasOne|Reference\HasOneSql
*/
public function hasOne(string $link, array $defaults = []) // : Reference
public function hasOne(string $link, array $defaults): Reference
{
return $this->_addReference($this->_defaultSeedHasOne, $link, $defaults); // @phpstan-ignore-line
}
Expand All @@ -81,7 +81,7 @@ public function hasOne(string $link, array $defaults = []) // : Reference
*
* @return Reference\HasMany
*/
public function hasMany(string $link, array $defaults = []) // : Reference
public function hasMany(string $link, array $defaults): Reference
{
return $this->_addReference($this->_defaultSeedHasMany, $link, $defaults); // @phpstan-ignore-line
}
Expand All @@ -93,7 +93,7 @@ public function hasMany(string $link, array $defaults = []) // : Reference
*
* @return Reference\ContainsOne
*/
public function containsOne(string $link, array $defaults = []) // : Reference
public function containsOne(string $link, array $defaults): Reference
{
return $this->_addReference($this->_defaultSeedContainsOne, $link, $defaults); // @phpstan-ignore-line
}
Expand All @@ -105,7 +105,7 @@ public function containsOne(string $link, array $defaults = []) // : Reference
*
* @return Reference\ContainsMany
*/
public function containsMany(string $link, array $defaults = []) // : Reference
public function containsMany(string $link, array $defaults): Reference
{
return $this->_addReference($this->_defaultSeedContainsMany, $link, $defaults); // @phpstan-ignore-line
}
Expand Down
3 changes: 2 additions & 1 deletion src/Persistence/Sql/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,8 @@ protected function _renderWith(): ?string
* $q->join('address.code', 'user.code', 'inner');
*
* You can use expression for more complex joins
* $q->join('address',
* $q->join(
* 'address',
* $q->orExpr()
* ->where('user.billing_id', 'address.id')
* ->where('user.technical_id', 'address.id')
Expand Down
15 changes: 7 additions & 8 deletions src/Reference.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Atk4\Data;

use Atk4\Core\DiContainerTrait;
use Atk4\Core\Factory;
use Atk4\Core\InitializerTrait;
use Atk4\Core\TrackableTrait;

Expand Down Expand Up @@ -263,16 +262,16 @@ protected function createTheirModelBeforeInit(array $defaults): Model
}

if (is_object($m)) {
$theirModel = Factory::factory(clone $m, $defaults);
$theirModelSeed = clone $m;
} else {
$modelDefaults = $m;
$theirModelSeed = [$modelDefaults[0]];
unset($modelDefaults[0]);
$defaults = array_merge($modelDefaults, $defaults);

$theirModel = Factory::factory($theirModelSeed, $defaults);
\Closure::bind(static fn () => Model::_fromSeedPrecheck($m, false), null, Model::class)();
$theirModelSeed = [$m[0]];
unset($m[0]);
$defaults = array_merge($m, $defaults);
}

$theirModel = Model::fromSeed($theirModelSeed, $defaults);

return $theirModel;
}

Expand Down
6 changes: 3 additions & 3 deletions src/Reference/HasOneSql.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ private function _addField(string $fieldName, bool $theirFieldIsTitle, ?string $
return $theirModel->action('field', [$theirFieldName]);
},
], $defaults, [
// allow to set our field value by an imported foreign field, but only when
// the our field value is null
// allow to set our field value by an imported foreign field, but only when the our field value is null
'readOnly' => false,
]));

Expand Down Expand Up @@ -159,7 +158,8 @@ public function refLink(array $defaults = []): Model
/**
* Add a title of related entity as expression to our field.
*
* $order->hasOne('user_id', 'User')->addTitle();
* $order->hasOne('user_id', ['model' => [User::class]])
* ->addTitle();
*
* This will add expression 'user' equal to ref('user_id')['name'];
*
Expand Down
Loading
Loading