5 * [Developer Intro](help/Developers-Intro)
7 Friendica uses class structures inspired by Domain-Driven-Design programming patterns.
8 This page is meant to explain what it means in practical terms for Friendica development.
12 - https://designpatternsphp.readthedocs.io/en/latest/Structural/DependencyInjection/README.html
13 - https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
14 - https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
15 - https://designpatternsphp.readthedocs.io/en/latest/Creational/FactoryMethod/README.html
16 - https://designpatternsphp.readthedocs.io/en/latest/Creational/Prototype/README.html
20 ### Models and Collections
22 Instead of anonymous arrays of arrays of database field values, we have Models and collections to take full advantage of PHP type hints.
26 function doSomething(array $intros)
28 foreach ($intros as $intro) {
29 $introId = $intro['id'];
33 $intros = \Friendica\Database\DBA::selectToArray('intros', [], ['uid' => Session::getLocalUser()]);
41 function doSomething(\Friendica\Contact\Introductions\Collection\Introductions $intros)
43 foreach ($intros as $intro) {
44 /** @var $intro \Friendica\Contact\Introductions\Entity\Introduction */
45 $introId = $intro->id;
49 /** @var $intros \Friendica\Contact\Introductions\Collection\Introductions */
50 $intros = \Friendica\DI::intro()->selectForUser(Session::getLocalUser());
55 ### Dependency Injection
57 Under this concept, we want class objects to carry with them the dependencies they will use.
58 Instead of calling global/static function/methods, objects use their own class members.
68 return \Friendica\Database\DBA::update('table', get_object_vars($this), ['id' => $this->id]);
78 * @var \Friendica\Database\Database
84 function __construct(\Friendica\Database\Database $dba)
91 return $this->dba->update('table', get_object_vars($this), ['id' => $this->id]);
96 The main advantage is testability.
97 Another one is avoiding dependency circles and avoid implicit initializing.
98 In the first example the method `save()` has to be tested with the `DBA::update()` method, which may or may not have dependencies itself.
100 In the second example we can mock `\Friendica\Database\Database`, e.g. overload the class by replacing its methods by placeholders, which allows us to test only `Model::save()` and nothing else implicitly.
102 The main drawback is lengthy constructors for dependency-heavy classes.
103 To alleviate this issue we are using [DiCe](https://r.je/dice) to simplify the instantiation of the higher level objects Friendica uses.
105 We also added a convenience factory named `\Friendica\DI` that creates some of the most common objects used in modules.
109 Since we added a bunch of parameters to class constructors, instantiating objects has become cumbersome.
110 To keep it simple, we are using Factories.
111 Factories are classes used to generate other objects, centralizing the dependencies required in their constructor.
112 Factories encapsulate more or less complex creation of objects and create them redundancy free.
116 $model = new Model(\Friendica\DI::dba());
118 $model->key = 'value';
128 * @var \Friendica\Database\Database
132 function __construct(\Friendica\Database\Database $dba)
137 public function create()
139 return new Model($this->dba);
143 $model = \Friendica\DI::factory()->create();
145 $model->key = 'value';
150 Here, `DI::factory()` returns an instance of `Factory` that can then be used to create a `Model` object without having to care about its dependencies.
154 Last building block of our code architecture, repositories are meant as the interface between models and how they are stored.
155 In Friendica they are stored in a relational database but repositories allow models not to have to care about it.
156 Repositories also act as factories for the Model they are managing.
163 * @var \Friendica\Database\Database
169 function __construct(\Friendica\Database\Database $dba)
176 return $this->dba->update('table', get_object_vars($this), ['id' => $this->id]);
183 * @var \Friendica\Database\Database
187 function __construct(\Friendica\Database\Database $dba)
192 public function create()
194 return new Model($this->dba);
199 $model = \Friendica\DI::factory()->create();
201 $model->key = 'value';
212 class Repository extends Factory
215 * @var \Friendica\Database\Database
219 function __construct(\Friendica\Database\Database $dba)
224 public function create()
226 return new Model($this->dba);
229 public function save(Model $model)
231 return $this->dba->update('table', get_object_vars($model), ['id' => $model->id]);
235 $model = \Friendica\DI::repository()->create();
237 $model->key = 'value';
239 \Friendica\DI::repository()->save($model);