[Laravel] Eloquent ORM, ophalen many-to-many related objects

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • rnark
  • Registratie: November 2009
  • Laatst online: 17-07 17:29
Hallo allemaal,

Ik had mijn vraag al gesteld in het algemene Laravel topic. Maar dat bleek niet handig dus ik stel hem hier nog een keer in een los topic.

Ik ben sinds kort bezig met Laravel. Nu loop ik tegen een probleem aan, heb al van alles geprobeerd maar ik kom er niet uit. Ook de documentatie en Google kunnen me niet helpen. Wat ik probeer is het volgende:

Mijn modellen:
PHP: WedstrijdAfstand.php
1
2
3
4
5
6
7
8
9
10
11
<?php

class WedstrijdAfstand extends \Eloquent
{
    protected $table = 'wedstrijd_afstanden';
    
    public function wedstrijd_codes()
    {
        return $this->belongsToMany('WedstrijdCode', 'wedstrijd_afstand_wedstrijd_code', 'wedstrijd_afstand_id', 'wedstrijd_code_id');      
    }
}


PHP: WedstrijdCode.php
1
2
3
4
5
6
7
8
9
10
11
<?php

class WedstrijdCode extends \Eloquent
{
    protected $table = 'wedstrijd_codes';
    
    public function wedstrijd_afstand()
    {
        return $this->belongsToMany('WedstrijdAfstand', 'wedstrijd_afstand_wedstrijd_code', 'wedstrijd_afstand_id', 'wedstrijd_code_id');
    }
}


Ik heb dus twee modellen: WedstrijdAfstand (tabel: wedstrijd_afstanden) en WedstrijdCode (tabel: wedstrijd_codes). De codes zijn gekoppeld aan de afstanden door middel van de tabel wedstrijd_afstand_wedstrijd_code.

De database is als volgt opgebouwd en gevuld:

SQL: toertocht_afstanden
1
2
3
| id | afstand |
|  1 |   50.00 |
|  2 |   75.00 |

SQL: toertocht_codes
1
2
3
| id | naam           |
|  1 | Tijdwaarneming |
|  2 | Verzorging     |

SQL: wedstrijd_afstand_wedstrijd_code
1
2
3
4
| id | wedstrijd_afstand_id | wedstrijd_code_id |
|  1 | 1                    | 1                 |
|  2 | 2                    | 2                 |
|  3 | 2                    | 1                 |


Als ik dan vervolgens voor een bepaalde afstand de codes wil ophalen gebruik ik de volgende 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
<?php
$afstanden = WedstrijdAfstand::all();

foreach($afstanden as $afstand)
{   
    echo '<h1>' . $afstand->afstand . '</h1>';  
    
    echo '<ul>';
    
    foreach($afstand->wedstrijd_codes()->get() as $code)
    {
        echo '<li>' . $code->naam . '</li>';
    }
    
    echo '</ul>';
    
    echo '<ul>';
    
    foreach($afstand->wedstrijd_codes as $code)
    {
        echo '<li>' . $code->naam . '</li>';
    }
    
    echo '</ul>';
}


Ik verwacht hierbij de volgende output:

code:
1
2
3
4
5
6
7
8
9
10
11
50.00

- Tijdwaarneming
- Tijdwaarneming

75.00

- Tijdwaarneming
- Verzorging
- Tijdwaarneming
- Verzorging


Het 'probleem' is dus dat de bovenste foreach wel werkt, maar de onderste code niet. Ik krijg dan de error: Invalid argument supplied for foreach(). Het gaat dan om regel 19 in bovenstaande code.

Volgens de documentatie zou dit wel moeten werken voor many-to-many relaties.

Ik gebruik Homestead met de volgende PHP versie:
code:
1
2
3
4
5
6
vagrant@homestead:~$ php -v
PHP 5.6.3-1+deb.sury.org~trusty+1 (cli) (built: Nov 19 2014 19:38:33) 
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies
    with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans


Doe ik iets verkeerd? Of is dit verwacht gedrag?

Alvast bedankt.

[ Voor 0% gewijzigd door rnark op 25-01-2015 20:18 . Reden: Fixed typo in WedstrijdCode class ]


Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 22:19
Kan je beide resultaten bekijken? Var_dump of dd()

Er gebeurt eea. automagisch met namen, met snake_case en studlycamelCase. Wat als je je methode wedstrijdCodes() noemt? Of zonder hoofdletters/underscore even testen?

Acties:
  • 0 Henk 'm!

Anoniem: 111703

Ik ken Laravel niet fantastisch goed (maar goed genoeg om het heel erg kut te vinden, met die ontzettend beroerde ORM implementatie :P), maar ik zie drie dingen:

[list]• Je geeft in de Eloquent::belongsToMany maarliefst 4 argumenten mee. Als je je houdt aan de naamgeving conventies (wat je volgens mij netjes doet), hoeft dat helemaal niet. Een $this->belongsToMany('WedstrijdCode') volstaat bijvoorbeeld.
• De WedstrijdCode::wedstrijd_afstand() doet een $this->belongsToMany('wedstrijdCode', ...). Huh? Een WedstrijdCode hoort bij meerdere WedstrijdCodes? Moet dat niet $this->belongstoMany('wedstrijdAfstand') te zijn?
• In de eerste foreach doe je een (chained) function call. In de tweede foreach een property access, maar in beide gevallen dezelfde results verwacht. Is dat wel de bedoeling? Ik weet dat Laravel zo inconsistent als de neten is, maar dit is wel heel gek.

:)

snake-case en camel-case door elkaar heen... brrrr.....

[ Voor 5% gewijzigd door Anoniem: 111703 op 25-01-2015 19:42 ]


Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 22:19
Anoniem: 111703 schreef op zondag 25 januari 2015 @ 19:32:
Ik ken Laravel niet fantastisch goed (maar goed genoeg om het heel erg kut te vinden, met die ontzettend beroerde ORM implementatie :P), maar ik zie drie dingen:

[list]• Je geeft in de Eloquent::belongsToMany maarliefst 4 argumenten mee. Als je je houdt aan de naamgeving conventies (wat je volgens mij netjes doet), hoeft dat helemaal niet. Een $this->belongsToMany('WedstrijdCode') volstaat bijvoorbeeld.
• De WedstrijdCode::wedstrijd_afstand() doet een $this->belongsToMany('wedstrijdCode', ...). Huh? Een WedstrijdCode hoort bij meerdere WedstrijdCodes? Moet dat niet $this->belongstoMany('wedstrijdAfstand') te zijn?
• In de eerste foreach doe je een function call. In de tweede foreach een property access. Is dat wel de bedoeling? Ik weet dat Laravel zo inconsistent als de neten is, maar dit is wel heel gek.

:)

snake-case en camel-case door elkaar heen... brrrr.....
Wat is er mis met het Active Record ORM van Laravel? Ik heb er nooit problemen mee, en als je gewoon de conventies aanhoudt wordt het een stuk simpeler. Als je niet van AR houdt moet je idd geen Eloquent gebruiken maar Doctrine of een ander ORM. Laravel-bashing voegt verder ook niet zoveel toe, als je constructief wil reageren doe dat dan in het algemene Laravel topic..

De naam-conventies werken vooral goed als je engelse termen gebruikt (ivm singular/plural conversies, iig voor de tabel namen). Maar mogelijk gaat het hier inderdaad ook wel goed.

Het 2de punt klopt inderdaad, maar dat wordt volgens mij niet gebruikt in dit voorbeeld.

Puntje 3, dat was wat rnark bedoelde waarschijnlijk. Met de function call ($afstand->wedstrijd_codes()) krijg je de query-builder. Dus als je er nog een orderBy/where clausule oid aan toe wil voegen, is dat wel makkelijk. De property-access roept automatisch die methode +get() aan, zodat je direct het resultaat krijgt.

Maar daar gaan ze dus vanuit dat de conventie is dat je methodes camelCase ziijn, dus wedstrijdCodes() ipv wedstrijd_codes(). En je properties zijn over het algemeen snake_case, dus wedstrijd_codes.

[ Voor 3% gewijzigd door Barryvdh op 25-01-2015 19:46 ]


Acties:
  • 0 Henk 'm!

  • rnark
  • Registratie: November 2009
  • Laatst online: 17-07 17:29
Bedankt Barryvdh, het probleem zat inderdaad in de naamgeving. Wanneer ik de methode wedstrijdCodes() noem werkt het inderdaad wel... Dat het zoiets simpels kon zijn 8)7

Het tweede punt van maximized is inderdaad een typo. Ik had deze methode nog niet geïmplementeerd en voor de volledigheid van dit topic er maar even bijgezet.

Verder probeer ik mezelf het gebruik van snake_case af te leren maar dat lukt niet altijd. Probeer er rekening mee te houden ;)

Voor de volledigheid van dit topic nog even:
PHP: WedstrijdAfstand.php
1
2
3
4
5
6
7
8
9
10
11
<?php

class WedstrijdAfstand extends \Eloquent
{
    protected $table = 'wedstrijd_afstanden';
    
    public function wedstrijdCodes()
    {
        return $this->belongsToMany('WedstrijdCode', 'wedstrijd_afstand_wedstrijd_code', 'wedstrijd_afstand_id', 'wedstrijd_code_id');      
    }
}


Bij deze implementatie werkt de automagische call naar wedstrijdCodes wel, in tegenstelling tot de code in de TS.

Acties:
  • 0 Henk 'm!

Anoniem: 111703

Barryvdh schreef op zondag 25 januari 2015 @ 19:44:
[...]


Wat is er mis met het Active Record ORM van Laravel? Ik heb er nooit problemen mee, en als je gewoon de conventies aanhoudt wordt het een stuk simpeler. Als je niet van AR houdt moet je idd geen Eloquent gebruiken maar Doctrine of een ander ORM. Laravel-bashing voegt verder ook niet zoveel toe, als je constructief wil reageren doe dat dan in het algemene Laravel topic..
Tja. Ik denk dat ik misschien erg verwend ben met de AR implementatie van Rails. Maar met name de wijze waarop relaties gedaan zijn in Eloquent zijn bijzonder awkward als je het mij vraagt.
rnark schreef op zondag 25 januari 2015 @ 20:17:
Bedankt Barryvdh, het probleem zat inderdaad in de naamgeving. Wanneer ik de methode wedstrijdCodes() noem werkt het inderdaad wel... Dat het zoiets simpels kon zijn 8)7

Het tweede punt van maximized is inderdaad een typo. Ik had deze methode nog niet geïmplementeerd en voor de volledigheid van dit topic er maar even bijgezet.

Verder probeer ik mezelf het gebruik van snake_case af te leren maar dat lukt niet altijd. Probeer er rekening mee te houden ;)

Voor de volledigheid van dit topic nog even:
PHP: WedstrijdAfstand.php
1
2
3
4
5
6
7
8
9
10
11
<?php

class WedstrijdAfstand extends \Eloquent
{
    protected $table = 'wedstrijd_afstanden';
    
    public function wedstrijdCodes()
    {
        return $this->belongsToMany('WedstrijdCode', 'wedstrijd_afstand_wedstrijd_code', 'wedstrijd_afstand_id', 'wedstrijd_code_id');      
    }
}


Bij deze implementatie werkt de automagische call naar wedstrijdCodes wel, in tegenstelling tot de code in de TS.
Mooi :)

En nu niet meer je variabelen en tabelnamen in het Nederlands doen, foei. :P

Acties:
  • 0 Henk 'm!

  • rnark
  • Registratie: November 2009
  • Laatst online: 17-07 17:29
Anoniem: 111703 schreef op zondag 25 januari 2015 @ 21:23:
[...]


Tja. Ik denk dat ik misschien erg verwend ben met de AR implementatie van Rails. Maar met name de wijze waarop relaties gedaan zijn in Eloquent zijn bijzonder awkward als je het mij vraagt.


[...]


Mooi :)

En nu niet meer je variabelen en tabelnamen in het Nederlands doen, foei. :P
Ook dat nog :o Gelukkig had dat niks met dit issue te maken, maar i.c.m. Laravel werkt het sowieso beter omdat je dan in elk geval de tabelnamen niet steeds los hoeft te definiëren.

Acties:
  • 0 Henk 'm!

Anoniem: 111703

Dat, en het feit dat het voor een eventueel Engels sprekende collega dan te begrijpen is wat er in godsnaam allemaal staat :+
Pagina: 1