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' => local_user()]);
40 function doSomething(\Friendica\Collection\Introductions $intros)
42 foreach ($intros as $intro) {
43 /** @var $intro \Friendica\Model\Introduction */
44 $introId = $intro->id;
48 /** @var $intros \Friendica\Collection\Introductions */
49 $intros = \Friendica\DI::intro()->select(['uid' => local_user()]);
54 ### Dependency Injection
56 Under this concept, we want class objects to carry with them the dependencies they will use.
57 Instead of calling global/static function/methods, objects use their own class members.
67 return \Friendica\Database\DBA::update('table', get_object_vars($this), ['id' => $this->id]);
77 * @var \Friendica\Database\Database
83 function __construct(\Friendica\Database\Database $dba)
90 return $this->dba->update('table', get_object_vars($this), ['id' => $this->id]);
95 The main advantage is testability.
96 Another one is avoiding dependency circles and avoid implicit initializing.
97 In the first example the method `save()` has to be tested with the `DBA::update()` method, which may or may not have dependencies itself.
99 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.
101 The main drawback is lengthy constructors for dependency-heavy classes.
102 To alleviate this issue we are using [DiCe](https://r.je/dice) to simplify the instantiation of the higher level objects Friendica uses.
104 We also added a convenience factory named `\Friendica\DI` that creates some of the most common objects used in modules.
108 Since we added a bunch of parameters to class constructors, instantiating objects has become cumbersome.
109 To keep it simple, we are using Factories.
110 Factories are classes used to generate other objects, centralizing the dependencies required in their constructor.
111 Factories encapsulate more or less complex creation of objects and create them redundancy free.
115 $model = new Model(\Friendica\DI::dba());
117 $model->key = 'value';
127 * @var \Friendica\Database\Database
131 function __construct(\Friendica\Database\Database $dba)
136 public function create()
138 return new Model($this->dba);
142 $model = \Friendica\DI::factory()->create();
144 $model->key = 'value';
149 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.
153 Last building block of our code architecture, repositories are meant as the interface between models and how they are stored.
154 In Friendica they are stored in a relational database but repositories allow models not to have to care about it.
155 Repositories also act as factories for the Model they are managing.
162 * @var \Friendica\Database\Database
168 function __construct(\Friendica\Database\Database $dba)
175 return $this->dba->update('table', get_object_vars($this), ['id' => $this->id]);
182 * @var \Friendica\Database\Database
186 function __construct(\Friendica\Database\Database $dba)
191 public function create()
193 return new Model($this->dba);
198 $model = \Friendica\DI::factory()->create();
200 $model->key = 'value';
211 class Repository extends Factory
214 * @var \Friendica\Database\Database
218 function __construct(\Friendica\Database\Database $dba)
223 public function create()
225 return new Model($this->dba);
228 public function save(Model $model)
230 return $this->dba->update('table', get_object_vars($model), ['id' => $model->id]);
234 $model = \Friendica\DI::repository()->create();
236 $model->key = 'value';
238 \Friendica\DI::repository()->save($model);