OOP PHP -> een child een parent waarde laten aanpassen

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Marque van Leeuwen

Marque van Leeuwen

13/03/2017 12:19:27
Quote Anchor link
Situatie:

Ik heb mijn hoofd-class. Die heeft onder andere het classnaamID. Dit is de database ID waarde van de gegevens in de class. Deze is read-only, want ik wil niet dat die verder in het programma wordt aangepast.

Ik heb ook een DB-class, dat een extend is van deze hoofd-class. Zodra deze de gegevens in de tabel heeft opgeslagen, kijkt hij of hij heeft te maken met een update (waarbij de classnaamID al bestond) of een nieuw record (waarbij de classnaamID null was). In dat laatste geval, moet dus de classnaamID gevuld worden met de AutoIncrement waarde uit de database.

Ik HOOPTE het te kunnen doen door:
class Hoofdclass {
protected $_hoofdclassId;
protected {andere waarden}

[andere functies, waaronder __construct, die zorgt dat $this->_hoofdclassId = null ]
}


class DbClass extends Hoofdclass {
public function writeToDb($connection) {
[ zootje DB code, maar geen extra waarden ]
$mysqli->query($query);

if (!isset($self->_hoofdclassId) {
$self->_hoofdclassId = $mysqli->insert_id;
}
}


function writeaway(dbClass $WorkObject, $connection) {
$WorkObject->writeToDb($connection);
}

$workValues = new Hoofdclass();

[Meer code]
writeaway($workValues,$dbConnection);



Dit werkt dus niet want PHP verwacht dat $workValue een DbClass is, maar het IS dus de parent daarvan. De makkelijkste oplossing is dus om ook gewoon een setID aan te maken in de Hoofdclass en de Database functionaliteiten er ook in te plaatsen, maar liever leer ik hoe ik een waarde van de parent afscherm, die ik in een overerving wel kan instellen.

A newbee thanks you!
 
PHP hulp

PHP hulp

27/12/2024 23:46:37
 
Ward van der Put
Moderator

Ward van der Put

13/03/2017 12:45:19
Quote Anchor link
Je zou grofweg twee dingen anders moeten aanpakken.

Ten eerste is een child die een property van de parent wijzigt fundamenteel verkeerd. We kunnen daar een hele verhandeling aan wijden, maar kort samengevat komt het erop neer dat jij hier de ID van de child zelf wilt instellen, niet van de parent omdat die parent ook nog andere children kan hebben … met een andere ID.

Ten tweede helpt het als je een scheiding maakt tussen dingen die iets zijn en dingen die iets doen. Hier is de nieuwe databaserecord een ding dat iets is. Het ding dat daarmee iets doet, de record opslaan in de database, is een ander object van een andere klasse.

Ik zou in dit geval nog een data mapper invoegen tussen de database en het databaseobject:

DbClass <-> WorkObjectMapper <-> WorkObject

Het WorkObject weet niets van het bestaan van de database of de mapper: het is gewoon een ding dat iets is. De mapper is de brug tussen de database en het databaseobject: de mapper weet hoe je een WorkObject maakt en de mapper weet hoe je dat in de database opslaat of uit de database haalt. De databaseklasse weet tot slot helemaal niets van het bestaan van databaseobjecten of hun mappers, maar implementeert alleen de standaardfunctionaliteit voor databasebeheer.
 
Marque van Leeuwen

Marque van Leeuwen

13/03/2017 13:13:02
Quote Anchor link
Ok, dat is goed te volgen. Zal zo iets verder in Doctorine duiken. Maar de essentiele vraag is eigenlijk hierbij nog niet ondervangen (of ik snap het nog niet goed). De WorkObject heeft een waarde voor de ID. Dit kan hij via een "get"-commando afgeven, maar er is geen "set"-commando hiervoor gemaakt.

Volgens mij blijft in jouw voorbeeld "DbClass <-> WorkObjectMapper <-> WorkObject", nog steeds het probleem dat de WorkObjectMapper niet de mogelijkheid heeft deze ID-waarde aan te passen, zodat een call naar "WorkObject->getId()" nog steeds niet de zojuist opgeslagen waarde kan afgeven.

OF (en dan snap ik het inderdaad verkeerd), laat je de instance die ik in de code verder gebruik, geen type WorkObject zijn, maar een type DbClass? In dat geval behoud de eindcode de mogelijkheid om de ID alsnog aan te passen (ja, ik zou er een protected functie van de SetId kunnen maken).

Toevoeging op 13/03/2017 13:15:23:

(ps: mijn eerder benoemde "HoofdClass" is in principe ook alleen de datavelden, met een set en get voor de waarden, alsmede een set en get van een array, met een teller functie. De bewerking zit in andere delen van het programma, die dus de "set" en "get"'s aansturen)
 
Ward van der Put
Moderator

Ward van der Put

13/03/2017 14:07:17
Quote Anchor link
Als je een nieuw WorkObject maakt, heeft dat nog geen ID. Het krijgt pas een ID bij het opslaan in de database, wat de verantwoordelijkheid van de mapper is. Ik zou hier daarom een methode setID() toevoegen aan het WorkObject en die methode aanroepen in de mapper na een succesvolle INSERT. Dezelfde methode kun je later hergebruiken wanneer je de mapper met SELECT een bestaand WorkObject uit de database laat halen.

De truc — of kunst ;-) — is dat je hierbij een soort "pass thru" uitvoert met de mapper als doorgeefluik: je geeft niet alleen het object door aan de mapper, maar stelt daarbij tegelijk de nieuwe ID in. Dat kan met een pass by reference en/of door de mapper het dan gewijzigde object te laten retourneren. Schematisch:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class WorkObjectMapper
{
    /**
     * Save a work object.
     *
     * @param WorkObject $work_object
     * @return WorkObject
     */

    public function save(WorkObject &$work_object)
    {

         // INSERT-query uitvoeren en de last insert ID opvragen
         // <...>

         // Nieuwe ID setten

         $work_object->setID($last_insert_id);

         // Gewijzigd object retourneren
         return $work_object;
    }
}

?>
 
Remco nvt

Remco nvt

13/03/2017 16:48:13
Quote Anchor link
Quote:
Als je e..... Het krijgt pas een ID bij het opslaan in de database, wat d.....mapper is.

Dit is enkel het geval als je auto generated ID veld hebt.

Even uitgaande dat we met een mysql database te maken hebben.
Je zou dan voor je ID veld in elk geval een auto_increment op een integer veld moeten hebben.
Als dat niet geval is moet je ID veld wel zelf invullen. Ik zou je dat adviseren om naar UUID te kijken RFC4122. Aanrader van implementatie in PHP hier te vinden.
 
Ward van der Put
Moderator

Ward van der Put

14/03/2017 07:13:08
Quote Anchor link
Remco van Bers op 13/03/2017 16:48:13:
Dit is enkel het geval als je auto generated ID veld hebt.

Dat is altijd het geval. Als je een unieke ID gebruikt om een object te kunnen onderscheiden van andere objecten in een verzameling, moet je die ID vaststellen op het niveau van de gehele populatie en niet dat van het individuele object. Welk mechanisme je daarbij gebruikt om tot een unieke ID te komen, een auto-increment of iets anders, bijvoorbeeld een volgnummer op basis van datum van tijd, doet er niet toe.
 
Remco nvt

Remco nvt

14/03/2017 11:45:17
Quote Anchor link
Nee hoor Ward, heb genoeg use-cases waarbij je ver voordat het ooit ergens in een database (sql/array/...) komt een identifier maakt en die gaat gebruiken. Het is maar vanaf welke insteek je kijkt. Ik ben van mening dat een object prima weet wat hij is. In wat voor collectie die hangt is niet relevant voor dat object.

Voor bovenstaande vraag is dit hieronder waarschijnlijk helemaal niet van toepassing.

Zodra jij dingen async gaat doen ontkom je niet om eerst identifiers al te genereren voordat het underhaupt ooit ergens wordt opgeslagen (als het al wordt opgeslagen).

Stel ik heb een collectie van Users. Daar wil ik een nieuwe User aan toevoegen.
Dan maak bijvoorbeeld in mijn UserDomain een User aan en die geef ik een identifier (een UUID)

$userId = Uuid::uuid4()
$newUser = new DomainUser($userId);

Nu kan ik met die $newUser alles doen wat ik wil. Ik kan hem in Array's gooien, ik kan hem in een command zetten en die op de messageBus. Ik kan hem lokaal gaan opslaan. Ik kan hem in de gehele applicatie al gebruiken voor ik uberhaupt iets opsla. Want de identifier is al bekend waar ik hem mee ga opslaan (DB/Array/Whatever).
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.