datamappers?
ik dacht, en wilde dus weten of dat een goede manier is, om voor elk object wat een database gebruikt, een apart opbject te maken, een mapper. een voorbeeldje:
object User, die gebruikt de UserMapper (extended van een algemeen databaseobject), om bijv userId op te halen
of is het beter om dit in het object User te doen? ik denk zelf van niet, maar wat denken jullie?
Gewijzigd op 29/08/2013 15:04:44 door Jeroen VD
Ik heb nu voor elk 'onderdeel' of db table een eigen class, maar wil heel graag een extra 'laag' aanbrengen, een datamapper of default model...
Classes die ik nu oa heb;
- Background.model.php
- Button.model.php
- Carousel.model.php
- Factory.model.php
- FactoryBrand.model.php
- FactoryCategories.model.php
- FactoryCategory.model.php
- FactoryProduct.model.php
- FactoryProducts.model.php
Etc.....
Is dit in de basis een goede structuur? Of moet ik toch anders denken?
Gr, Ken
overduidelijk je eerste optie.
kijk eens naar de grotere frameworks,
daar zie je duidelijk één database class en voor bijna elke tabel in de database een eigen Entity-class. De 'user' entity heeft dan alle properties zoals die ook in de tabel Users als kolommen voorkomen. Daarnaast heeft deze class getters en setters.
Dankzij ORM weten we hoe deze properties in de database worden opgeslagen.
Maar voor ieder object een eigen (afgeleide) mapper kan natuurlijk ook.
Toevoeging op 29/08/2013 14:57:28:
wat mij betreft de mappers niet extenden van de database class maar de mappers moeten de database class gebruiken.
en met de databaseclass bedoel ik de verbinding enzo... dat de mapper alleen zijn getters en setters heeft, zodat de verbinding eenmaal aangemaakt wordt, met zo weinig mogelijk code?
@ken, jij bedoeld elke tabel een aparte class geven?.... dan is jouw database structuur op het eerste gezicht behoorlijk inefficient
Elke tabel (op koppeltabellen na) zijn vertegenwoordigt door een class (entity) in OO. De database is vertegenwoordigt door een Database klasse en daartussen in heb je datamappers, die zijn specifiek voor 1 entity.
willekeurige klasse -> tabel klasse -> Mapper klasse (die zijn verbinding etc haalt uit de database klasse) -> database tabel
en naamgevingsconventies hierbij, of is dat gewoon tableTablename.class en tablenameMapper.class etc
Entity -> DataMapper -> Database => DB
Dus bijv:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
class User
{
private $name;
private $age;
// ...
}
class UserMapper implements DataMapperInterface
{
public function findById($id)
{
$result = ...; // perform SELECT query
return $this->populate($result);
}
public function populate(array $result)
{
$u = new User();
$u->setName($result['name']);
$u->setAge($result['age']);
return $u;
}
}
class PDOMySQLDatabase extends AbstractPDODatabase
{
// ... db methods
}
?>
class User
{
private $name;
private $age;
// ...
}
class UserMapper implements DataMapperInterface
{
public function findById($id)
{
$result = ...; // perform SELECT query
return $this->populate($result);
}
public function populate(array $result)
{
$u = new User();
$u->setName($result['name']);
$u->setAge($result['age']);
return $u;
}
}
class PDOMySQLDatabase extends AbstractPDODatabase
{
// ... db methods
}
?>
Waarschijnlijk ga je een GeneralDataMapper maken, aangezien de methods create, find, save en delete vaak hetzelfde zijn. Je kan zelfs met __call werken en ook de method findById en findByAge in deze klasse verwerken. Het enige wat je dan nog nodig hebt is een populate en extract method, die informatie in/uit een Entity stoppen/halen en natuurlijk custom methods, zoals findByNameOrderedByAge().
Even je code tussen de code-tags gezet, omdat dat niet meer automatisch gaat bij de php-tags[/modedit]
Gewijzigd op 29/08/2013 23:37:22 door Nick Dijkstra
ik snap het bijna helemaal..... ligt het aan mij, of is die PDOMySQKDatabase een tikkeltje overbodig? wat doet die? waarom kun je in de mapper niet de complete query uitvoeren, waarbij je een simpel connectieobject toevoegt?
Quote:
is die PDOMySQKDatabase een tikkeltje overbodig? wat doet die? waarom kun je in de mapper niet de complete query uitvoeren, waarbij je een simpel connectieobject toevoegt?
Op deze manier ben ik niet afhankelijk van de manier van opslag, precies het nut van OO dus. Ik hoef alleen een andere klasse te instantiëren en ik kan een sqlite db gebruiken. Ik kan zelfs een nieuwe adapter maken en gaan werken met de MySQLi extensie of zelfs met een xml bestand. Dat kan ik allemaal doen door maar 1 regel te veranderen, anders moet ik elke datamapper aanpassen.
Als ik nu een functie wil hebben ( zoiets als toArray() ) die de private properties uit de User class (en ook andere entities) haalt en in een associatieve array teruggeeft? wordt dat dan een onderdeel van de DataMapperInterface?
Wel is het zo dat de DataMapper dit moet doen, dus heb ik een method extract (oid) in mijn datamapper die dit doet. Deze roept simpelweg de EntityUtil aan:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
class UserMapper extends AbstractDataMapper
{
protected function extract(User $user)
{
return EntityUtil::toArray($user);
}
protected function populate(array $data)
{
$user = new User($data['name']);
$user->setAge($data['age']);
return $user;
}
}
class EntityUtil
{
static public function toArray($entity)
{
$entityReflection = new \ReflectionClass($entity);
$data = ...; // gebruik reflection om data te krijgen
return $data;
}
}
?>
class UserMapper extends AbstractDataMapper
{
protected function extract(User $user)
{
return EntityUtil::toArray($user);
}
protected function populate(array $data)
{
$user = new User($data['name']);
$user->setAge($data['age']);
return $user;
}
}
class EntityUtil
{
static public function toArray($entity)
{
$entityReflection = new \ReflectionClass($entity);
$data = ...; // gebruik reflection om data te krijgen
return $data;
}
}
?>
Gewijzigd op 30/08/2013 11:10:51 door Wouter J
p.s. die db methods, zijn dat methods die de query daadwerkelijk uitvoeren, en je in de mapper alleen de query doorgeeft?
Quote:
daarvoor heb je toch een geinstantieerd object van PDOMySQLDatabase nodig IN die method? of mag dat dan weer wel?
Ja, je injecteert de Database instance in je DataMapper:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class UserMapper ...
{
private $db;
public function __construct(DatabaseInterface $db)
{
$this->db = $db;
}
public function findById($id)
{
return $this->populate($this->db->query(...)->getResult('FETCH_ASSOC'));
}
}
// in gebruik
$db = new ...Database(...); // dit doe je 1 keer
$usermapper = new UserMapper($db); // geeft db instance mee
$usermapper->findById(2);
?>
class UserMapper ...
{
private $db;
public function __construct(DatabaseInterface $db)
{
$this->db = $db;
}
public function findById($id)
{
return $this->populate($this->db->query(...)->getResult('FETCH_ASSOC'));
}
}
// in gebruik
$db = new ...Database(...); // dit doe je 1 keer
$usermapper = new UserMapper($db); // geeft db instance mee
$usermapper->findById(2);
?>
Gewijzigd op 30/08/2013 16:09:30 door Wouter J
in ieder geval bedankt, ga er mee stoeien :)
Jeroen VD op 29/08/2013 15:04:06:
@ken, jij bedoeld elke tabel een aparte class geven?.... dan is jouw database structuur op het eerste gezicht behoorlijk inefficient
Jeroen, kan goed begrijpen dat je dit denkt. Opzet van de database is ook wel anders dan mijn bericht doet vermoeden. Ik kan in ieder geval heel goed op weg met alle antwoorden. Dat was eigenlijk al een beetje wat ik zocht :) Bedankt voor je individuele reactie!
Dank je Wouter ik heb nu even niet de gelegenheid om hier echt mee te gaan stoeien maar wellicht kom ik nog terug met een vraagje.