Skip to content

Commit 2bbb6bb

Browse files
Merge pull request #4 from liam-wiltshire/add-trait
Add trait, update to match default model
2 parents 8b266eb + 39df94b commit 2bbb6bb

File tree

6 files changed

+180
-73
lines changed

6 files changed

+180
-73
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Memory:26MiB
8181
liam-wiltshire/laravel-jit-loader is available as a composer package:
8282
`composer require liam-wiltshire/laravel-jit-loader`
8383

84-
Once installed, have your models extend the `\LiamWiltshire\LaravelJitLoader\Model` class instead of the default eloquent model, and JIT loading will be automatically enabled.
84+
Once installed, use the `\LiamWiltshire\LaravelJitLoader\Concerns\AutoloadsRelationships` trait in your model, or have your models extend the `\LiamWiltshire\LaravelJitLoader\Model` class instead of the default eloquent model, and JIT loading will be automatically enabled.
8585

8686
# Limitations
8787
This is an early release based on specific use cases. At the moment the autoloading will only be used when the relationship is loaded like a property e.g. `$user->company->name` instead of `$user->company()->first()->name`. I am working on supporting relations loaded in alternate ways, however there is more complexity in that so there isn't a fixed timescale as of yet!
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace LiamWiltshire\LaravelJitLoader\Concerns;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use LogicException;
7+
use Illuminate\Database\Eloquent\Relations\Relation;
8+
use Illuminate\Database\Eloquent\Collection;
9+
10+
/**
11+
* Trait AutoloadsRelationships
12+
* @package LiamWiltshire\LaravelJitLoader\Concerns
13+
*/
14+
trait AutoloadsRelationships
15+
{
16+
/**
17+
* The maximum collection size that we will autoload for
18+
* @var int
19+
*/
20+
protected $autoloadThreshold = 6000;
21+
22+
/**
23+
* @var ?Collection
24+
*/
25+
protected $parentCollection = null;
26+
27+
private function shouldAutoLoad(): bool
28+
{
29+
return ($this->parentCollection
30+
&& count($this->parentCollection) > 1
31+
&& count($this->parentCollection) <= $this->autoloadThreshold);
32+
}
33+
34+
/**
35+
* Load the relationship for the given method, and then get a relationship value from a method.
36+
* @param string $method
37+
* @return mixed
38+
*
39+
* @throws LogicException
40+
*/
41+
public function getRelationshipFromMethod($method)
42+
{
43+
$relation = $this->$method();
44+
45+
if (!$relation instanceof Relation) {
46+
throw new LogicException(
47+
sprintf('%s::%s must return a relationship instance.', static::class, $method)
48+
);
49+
}
50+
51+
if ($this->shouldAutoLoad()) {
52+
$this->parentCollection->loadMissing($method);
53+
}
54+
55+
return tap($relation->getResults(), function ($results) use ($method) {
56+
$this->setRelation($method, $results);
57+
});
58+
}
59+
60+
/**
61+
* Create a new Eloquent collection, and assign all models as a member of this collection
62+
*
63+
* @param array $models
64+
* @return Collection
65+
*/
66+
public function newCollection(array $models = []): Collection
67+
{
68+
$collection = new Collection($models);
69+
unset($models);
70+
71+
foreach ($collection as &$model) {
72+
$model->parentCollection = &$collection;
73+
}
74+
75+
return $collection;
76+
}
77+
78+
/**
79+
* Disable autoloading of relationships via this model
80+
* @return Model
81+
*/
82+
public function disableAutoload(): Model
83+
{
84+
$this->autoloadThreshold = 0;
85+
return $this;
86+
}
87+
}

src/Model.php

Lines changed: 2 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
namespace LiamWiltshire\LaravelJitLoader;
44

5-
use LogicException;
6-
use Illuminate\Database\Eloquent\Relations\Relation;
7-
use Illuminate\Database\Eloquent\Collection;
5+
use LiamWiltshire\LaravelJitLoader\Concerns\AutoloadsRelationships;
86
use Illuminate\Database\Eloquent\Model as EloquentModel;
97

108
/**
@@ -13,73 +11,5 @@
1311
*/
1412
class Model extends EloquentModel
1513
{
16-
/**
17-
* The maximum collection size that we will autoload for
18-
* @var int
19-
*/
20-
protected $autoloadThreshold = 6000;
21-
22-
/**
23-
* @var ?Collection
24-
*/
25-
protected $parentCollection = null;
26-
27-
28-
private function shouldAutoLoad(): bool
29-
{
30-
return ($this->parentCollection
31-
&& count($this->parentCollection) > 1
32-
&& count($this->parentCollection) <= $this->autoloadThreshold);
33-
}
34-
35-
/**
36-
* Load the relationship for the given method, and then get a relationship value from a method.
37-
* @param string $method
38-
* @return mixed
39-
*
40-
* @throws LogicException
41-
*/
42-
public function getRelationshipFromMethod($method)
43-
{
44-
45-
$relations = $this->$method();
46-
if (!$relations instanceof Relation) {
47-
throw new LogicException(
48-
sprintf('%s::%s must return a relationship instance.', static::class, $method)
49-
);
50-
}
51-
52-
if ($this->shouldAutoLoad()) {
53-
$this->parentCollection->loadMissing($method);
54-
}
55-
return $this->$method()->getResults();
56-
}
57-
58-
/**
59-
* Create a new Eloquent collection, and assign all models as a member of this collection
60-
*
61-
* @param array $models
62-
* @return Collection
63-
*/
64-
public function newCollection(array $models = []): Collection
65-
{
66-
$collection = new Collection($models);
67-
unset($models);
68-
69-
foreach ($collection as &$model) {
70-
$model->parentCollection = &$collection;
71-
}
72-
73-
return $collection;
74-
}
75-
76-
/**
77-
* Disable autoloading of relationships via this model
78-
* @return Model
79-
*/
80-
public function disableAutoload(): Model
81-
{
82-
$this->autoloadThreshold = 0;
83-
return $this;
84-
}
14+
use AutoloadsRelationships;
8515
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: liam
5+
* Date: 28/02/19
6+
* Time: 10:48
7+
*/
8+
9+
namespace LiamWiltshire\LaravelJitLoader\Tests\Concerns;
10+
11+
12+
use LiamWiltshire\LaravelJitLoader\Tests\TestCase;
13+
use LiamWiltshire\LaravelJitLoader\Tests\TraitModel;
14+
15+
class AutoloadsRelationshipsTest extends TestCase
16+
{
17+
public function testGetRelationshipFromMethodWithNonExistentRelationshipThrowsException()
18+
{
19+
$model = new TraitModel();
20+
$this->expectException(\LogicException::class);
21+
$this->expectExceptionMessage('TraitModel::nonExistentRelationship must return a relationship instance.');
22+
$model->getRelationshipFromMethod('nonExistentRelationship');
23+
}
24+
25+
public function testGetRelationshipFromMethodAfterDisableAutoLoadCalledDoesntAutoLoad()
26+
{
27+
$models = TraitModel::all();
28+
$related = $models[0]->disableAutoload()->myRelationship;
29+
30+
$this->assertFalse($models[1]->relationLoaded('myRelationship'));
31+
}
32+
33+
public function testGetRelationshipFromMethodOverThresholdDoesntAutoLoad()
34+
{
35+
$models = TraitModel::all();
36+
$models[0]->setAutoloadThreshold(2);
37+
$related = $models[0]->myRelationship;
38+
39+
$this->assertFalse($models[1]->relationLoaded('myRelationship'));
40+
}
41+
42+
43+
public function testGetRelationshipFromMethodUnderThresholdDoesAutoLoad()
44+
{
45+
$models = TraitModel::all();
46+
$related = $models[0]->myRelationship;
47+
48+
$this->assertTrue($models[1]->relationLoaded('myRelationship'));
49+
}
50+
}

tests/TestCase.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,16 @@ public function migrateIdentitiesTable()
4545
DummyModel::create(array('dummy_model_id' => 2));
4646
DummyModel::create(array('dummy_model_id' => 1));
4747

48+
Manager::schema()->create('trait_models', function($table) {
49+
$table->increments('id');
50+
$table->integer('trait_model_id');
51+
$table->timestamps();
52+
});
53+
TraitModel::create(array('trait_model_id' => 5));
54+
TraitModel::create(array('trait_model_id' => 4));
55+
TraitModel::create(array('trait_model_id' => 3));
56+
TraitModel::create(array('trait_model_id' => 2));
57+
TraitModel::create(array('trait_model_id' => 1));
58+
4859
}
4960
}

tests/TraitModel.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace LiamWiltshire\LaravelJitLoader\Tests;
4+
5+
6+
use Illuminate\Database\Eloquent\Model;
7+
use LiamWiltshire\LaravelJitLoader\Concerns\AutoloadsRelationships;
8+
9+
class TraitModel extends Model {
10+
11+
use AutoloadsRelationships;
12+
13+
protected $fillable = ['trait_model_id'];
14+
15+
public function myRelationship()
16+
{
17+
return $this->hasOne(TraitModel::class);
18+
}
19+
20+
public function nonExistentRelationship()
21+
{
22+
return false;
23+
}
24+
25+
public function setAutoloadThreshold(int $autoloadThreshold)
26+
{
27+
$this->autoloadThreshold = $autoloadThreshold;
28+
}
29+
}

0 commit comments

Comments
 (0)