Skip to content

Commit a3e0ea2

Browse files
authored
Merge pull request #37 from tattersoftware/soft-deletes
2 parents c443f1b + 17f79e0 commit a3e0ea2

File tree

5 files changed

+72
-28
lines changed

5 files changed

+72
-28
lines changed

README.md

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Tatter\Relations
22
Entity relationships for CodeIgniter 4
33

4-
[![](https://github.com/tattersoftware/codeigniter4-relations/workflows/PHPUnit/badge.svg)](https://github.com/tattersoftware/codeigniter4-relations/actions?query=workflow%3A%22PHPUnit)
5-
[![](https://github.com/tattersoftware/codeigniter4-relations/workflows/PHPStan/badge.svg)](https://github.com/tattersoftware/codeigniter4-relations/actions?query=workflow%3A%22PHPStan)
4+
[![](https://github.com/tattersoftware/codeigniter4-relations/workflows/PHPUnit/badge.svg)](https://github.com/tattersoftware/codeigniter4-relations/actions/workflows/phpunit.yml)
5+
[![](https://github.com/tattersoftware/codeigniter4-relations/workflows/PHPStan/badge.svg)](https://github.com/tattersoftware/codeigniter4-relations/actions/workflows/phpstan.yml)
6+
[![](https://github.com/tattersoftware/codeigniter4-relations/workflows/Deptrac/badge.svg)](https://github.com/tattersoftware/codeigniter4-relations/actions/workflows/deptrac.yml)
67
[![Coverage Status](https://coveralls.io/repos/github/tattersoftware/codeigniter4-relations/badge.svg?branch=develop)](https://coveralls.io/github/tattersoftware/codeigniter4-relations?branch=develop)
78

89
## Quick Start
@@ -19,10 +20,12 @@ Entity relationships for CodeIgniter 4
1920

2021
Install easily via Composer to take advantage of CodeIgniter 4's autoloading capabilities
2122
and always be up-to-date:
22-
* `> composer require tatter/relations`
23+
```shell
24+
> composer require tatter/relations
25+
```
2326

2427
Or, install manually by downloading the source files and adding the directory to
25-
`app/Config/Autoload.php`.
28+
**app/Config/Autoload.php***.
2629

2730
## Configuration (optional)
2831

@@ -50,21 +53,20 @@ methods and injecting relations into the returned results. Because this happens
5053
level, related items can be loaded ahead of time in batches ("eager loading").
5154

5255
Add the trait to your models:
53-
56+
```php
5457
use \Tatter\Relations\Traits\ModelTrait
58+
```
5559

5660
Related items can be requested by adding a `$with` property to your model:
57-
58-
```
61+
```php
5962
protected $with = 'groups';
6063
// or
6164
protected $with = ['groups', 'permissions'];
6265
```
6366

6467
... or by requesting it on-the-fly using the model `with()` method:
6568

66-
67-
```
69+
```php
6870
$users = $userModel->with('groups')->findAll();
6971
foreach ($users as $userEntity)
7072
{
@@ -82,17 +84,15 @@ and `__call()` methods to check for matching database tables. Because this happe
8284
item, related items can be retrieved or updated on-the-fly ("lazy loading").
8385

8486
Add the trait and its necessary properties to your entities:
85-
86-
```
87+
```php
8788
use \Tatter\Relations\Traits\EntityTrait
8889

8990
protected $table = 'users';
9091
protected $primaryKey = 'id';
9192
```
9293

9394
Related items are available as faux properties:
94-
95-
```
95+
```php
9696
$user = $userModel->find(1);
9797

9898
foreach ($user->groups as $group)
@@ -102,8 +102,7 @@ Related items are available as faux properties:
102102
```
103103

104104
... and can also be updated directly from the entity:
105-
106-
```
105+
```php
107106
$user->addGroup(3);
108107

109108
if ($user->hasGroups([1, 3]))
@@ -123,7 +122,7 @@ for "manyToMany" relationships.
123122
successful, **Relations** will use each table's model to find the related items. This keeps
124123
consistent the return types, events, and other aspects of your models. In addition to the
125124
return type, **Relations** will also adjust related items for singleton relationships:
126-
```
125+
```php
127126
// User hasMany Widgets
128127
$user = $userModel->with('widgets')->find($userId);
129128
echo "User {$user->name} has " . count($user->widgets) . " widgets.";
@@ -138,7 +137,7 @@ echo $widget->name . " belongs to " . $widget->user->name;
138137
**ModelTrait** supports nested relation calls, but these can be resource intensive so may
139138
be disabled by changing `$allowNesting` in the config. With nesting enabled, any related
140139
items will also load their related items (but not infinitely):
141-
```
140+
```php
142141
/* Define your models */
143142
class UserModel
144143
{
@@ -162,6 +161,14 @@ foreach ($groups as $group)
162161
}
163162
```
164163

164+
### Soft Deletes
165+
166+
If your target relations correspond to a CodeIgniter Model that uses [soft deletion](https://codeigniter.com/user_guide/models/model.html#usesoftdeletes)
167+
then you may include the table name in the `array $withDeletedRelations` property to include
168+
soft deleted items. This is particularly helpful for tight relationships, like when an item
169+
`belongsTo` another item that has been soft deleted. `$withDeletedRelations` works on both
170+
Entities and Models.
171+
165172
## Performance
166173

167174
*WARNING*: Be aware that **Relations** relies on a schema generated from the **Schemas**
@@ -170,7 +177,7 @@ request initiates the load. The schema will attempt to cache to prevent this del
170177
if your cache is not configured correctly you will likely experience noticeable performance
171178
degradation. The recommended approach is to have a cron job generate your schema regularly
172179
so it never expires and no user will trigger the un-cached load, e.g.:
173-
```
180+
```shell
174181
php spark schemas
175182
```
176183

src/Traits/BaseTrait.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,16 @@ public function _getRelations($tableName, $ids = null): array
151151

152152
// If the model is available then use it to get the result
153153
// (Bonus: triggers model's afterFind)
154-
$results = isset($table->model) ? $builder->find() : $builder->get()->getResult();
154+
if (isset($table->model)) {
155+
// Check if this table should include soft deletes
156+
if (isset($this->withDeletedRelations) && in_array($table->name, $this->withDeletedRelations, true)) {
157+
$builder->withDeleted();
158+
}
159+
160+
$results = $builder->find();
161+
} else {
162+
$results = $builder->get()->getResult();
163+
}
155164

156165
// Clean up
157166
unset($table, $builder);

tests/_support/Models/WorkerModel.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ class WorkerModel extends Model
99
{
1010
use ModelTrait;
1111

12-
protected $table = 'workers';
13-
protected $primaryKey = 'id';
14-
protected $returnType = 'object';
15-
protected $useSoftDeletes = true;
16-
protected $allowedFields = ['firstname', 'lastname', 'role', 'age'];
17-
protected $useTimestamps = true;
18-
protected $validationRules = [];
19-
protected $validationMessages = [];
20-
protected $skipValidation = false;
12+
protected $table = 'workers';
13+
protected $primaryKey = 'id';
14+
protected $returnType = 'object';
15+
protected $useSoftDeletes = true;
16+
protected $allowedFields = ['firstname', 'lastname', 'role', 'age'];
17+
protected $useTimestamps = true;
18+
protected $validationRules = [];
19+
protected $validationMessages = [];
20+
protected $skipValidation = false;
21+
protected $withDeletedRelations = [];
2122
}

tests/entity/RelationsTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,21 @@ public function testRelationsMatchModelWith()
110110
/** @var Factory $factory */
111111
$this->assertEquals($factory->workers, $workers);
112112
}
113+
114+
public function testWithDeletedRelations()
115+
{
116+
$object = (new MachineModel())->with(false)->find(4);
117+
$machine1 = new Machine((array) $object);
118+
$this->assertNull($machine1->factory);
119+
120+
$machine2 = new class () extends Machine {
121+
protected array $withDeletedRelations = ['factories'];
122+
};
123+
$machine2->fill((array) $object);
124+
125+
$result = $machine2->factory;
126+
127+
$this->assertNotNull($result);
128+
$this->assertSame('widget', $result->uid);
129+
}
113130
}

tests/model/MethodsTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,14 @@ public function testBelongsToNested()
8686

8787
$this->assertEquals($factories[3], $machines[6]->factory);
8888
}
89+
90+
public function testWithDeletedRelations()
91+
{
92+
$worker = $this->workers->with('factories')->find(4);
93+
$this->assertCount(1, $worker->factories);
94+
95+
$this->setPrivateProperty($this->workers, 'withDeletedRelations', ['factories']);
96+
$worker = $this->workers->with('factories')->find(4);
97+
$this->assertCount(2, $worker->factories);
98+
}
8999
}

0 commit comments

Comments
 (0)