Lijst van mogelijke waarden combineren met de daadwerkelijke

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • TheNephilim
  • Registratie: September 2005
  • Laatst online: 09-09 12:00
Het lukt me niet om in Laravel met Eloquent een lijst van mogelijke waarden weer te geven en die te combineren met de daadwerkelijke waarden. In dit geval gaat het om een prijs. Stel je de volgende tabelstructuur voor:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
costs
- id
- name
- default_price

cost_values
- id
- cost_id
- item_id
- price

item
- id
- name


Op de edit-pagina van item wil ik een lijst van costs weergeven, bijvoorbeeld zo:

HTML:
1
2
3
4
5
<ul>
    @foreach($costs as $cost)
        <li>{{ $cost->name }} | {{ $cost->default_price }} | {{ $cost_value_for_this_item->price }}</li>
    @endforeach
</ul>


Maar hoe kom ik dan (op een nette manier) aan $cost_value_for_this_item->price met dat $cost->id en $item->id?

Iets als \App\CostValue::where(['item_id' => $item->id, cost_id' => $cost->id])->first()->price werkt, maar dan moet je er rekening mee houden dat hij niet bestaat. Op die manier word het al snel erg lelijk en er zijn vast betere manieren.

Heeft iemand hier suggesties?

Beste antwoord (via TheNephilim op 08-04-2016 11:39)


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ik ben niet bekend met Eloquent maar in "SQL land" noemt men dat gewoon een left/right (outer) join... Dat lijkt me wel een term waar je iets mee zou moeten kunnen vinden i.c.m. het Eloquent keyword? Ik mis echter, volgens mij, de relevante query (DB::table('costs')->select(...)) of niet?

Then again vraag ik me bij herlezen van je topicstart af of ik je vraag wel helemaal begrijp...

[ Voor 56% gewijzigd door RobIII op 06-04-2016 23:47 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Alle reacties


Acties:
  • Beste antwoord
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ik ben niet bekend met Eloquent maar in "SQL land" noemt men dat gewoon een left/right (outer) join... Dat lijkt me wel een term waar je iets mee zou moeten kunnen vinden i.c.m. het Eloquent keyword? Ik mis echter, volgens mij, de relevante query (DB::table('costs')->select(...)) of niet?

Then again vraag ik me bij herlezen van je topicstart af of ik je vraag wel helemaal begrijp...

[ Voor 56% gewijzigd door RobIII op 06-04-2016 23:47 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • DirkZzZ
  • Registratie: September 2007
  • Laatst online: 04-09 10:02
De vraag is mij niet geheel duidelijk.

Jij haalt dus altijd alle waardes op uit de "costs" tabel wanneer jij een item bewerkt, en vervolgens moet er gekeken worden of er voor dit specifieke item en de specifieke prijsvermelding een uitzondering bestaat in de "cost_values" tabel? En de combinatie tussen cost_id en item_id in de "cost_values" tabel is uniek?

Als het mogelijk is dat hij niet bestaat dan zul je er toch rekening mee moeten houden, hoe je het ook wendt of keert.

Als de vraag is hoe houd ik mijn view schoon, dit zou je kunnen doen door de lijst waarover jij gaat itereren al compleet aan de view mee te geven. En dat de invulling hiervan dus al in bijvoorbeeld jouw controller gebeurt.

Wil jij dit soort lijstjes in meerdere views binnen je controller gebruiken dan zou je er een methode voor kunnen aanmaken binnen jouw controller, komt het vaker voor binnen jouw applicatie dan zou je het in een aparte class kunnen stoppen.

Een ietwat lomp voorbeeld:

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
//Item Model
class Item extends Model
{
    public function costValues()
    {
        return $this->hasMany(CostValue::class);
    }
}

// Controller
    $item = Item::with('costValues')->findOrFail(1);
    $itemCostValue = $item->costValues->keyBy('cost_id');
    $costs = Cost::all();

    foreach ($costs AS $cost) {
        $cost->price = 'n.v.t.';

        if ($itemCostValue->has($cost->id)) {
            $cost->price = $itemCostValue->get($cost->id)->price;
        }
    }

//View

    foreach($costs AS $cost){
        echo "{$cost->name} || {$cost->default_price} || {$cost->price} <br/>";
    }


Ik weet niet of dit duidelijk is, en of dit überhaupt jouw vraag beantwoord?

Acties:
  • 0 Henk 'm!

  • TheNephilim
  • Registratie: September 2005
  • Laatst online: 09-09 12:00
RobIII schreef op woensdag 06 april 2016 @ 23:40:
Ik ben niet bekend met Eloquent maar in "SQL land" noemt men dat gewoon een left/right (outer) join... Dat lijkt me wel een term waar je iets mee zou moeten kunnen vinden i.c.m. het Eloquent keyword? Ik mis echter, volgens mij, de relevante query (DB::table('costs')->select(...)) of niet?

Then again vraag ik me bij herlezen van je topicstart af of ik je vraag wel helemaal begrijp...
Haha, ja dat klopt een LEFT JOIN of sub-SELECT zou dit probleem oplossen denk ik. Daar zou ik nog eens op kunnen zoeken in de Laravel documentatie, want ik wil zoiets graag met Eloquent oplossen. Als dat kan natuurlijk.
DirkZzZ schreef op donderdag 07 april 2016 @ 01:41:
De vraag is mij niet geheel duidelijk.

Jij haalt dus altijd alle waardes op uit de "costs" tabel wanneer jij een item bewerkt, en vervolgens moet er gekeken worden of er voor dit specifieke item en de specifieke prijsvermelding een uitzondering bestaat in de "cost_values" tabel? En de combinatie tussen cost_id en item_id in de "cost_values" tabel is uniek?

Als het mogelijk is dat hij niet bestaat dan zul je er toch rekening mee moeten houden, hoe je het ook wendt of keert.

Als de vraag is hoe houd ik mijn view schoon, dit zou je kunnen doen door de lijst waarover jij gaat itereren al compleet aan de view mee te geven. En dat de invulling hiervan dus al in bijvoorbeeld jouw controller gebeurt.

Wil jij dit soort lijstjes in meerdere views binnen je controller gebruiken dan zou je er een methode voor kunnen aanmaken binnen jouw controller, komt het vaker voor binnen jouw applicatie dan zou je het in een aparte class kunnen stoppen.

Een ietwat lomp voorbeeld:

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
//Item Model
class Item extends Model
{
    public function costValues()
    {
        return $this->hasMany(CostValue::class);
    }
}

// Controller
    $item = Item::with('costValues')->findOrFail(1);
    $itemCostValue = $item->costValues->keyBy('cost_id');
    $costs = Cost::all();

    foreach ($costs AS $cost) {
        $cost->price = 'n.v.t.';

        if ($itemCostValue->has($cost->id)) {
            $cost->price = $itemCostValue->get($cost->id)->price;
        }
    }

//View

    foreach($costs AS $cost){
        echo "{$cost->name} || {$cost->default_price} || {$cost->price} <br/>";
    }


Ik weet niet of dit duidelijk is, en of dit überhaupt jouw vraag beantwoord?
Ja zo, alleen wat jij hier nu doet, zou toch op een andere manier moeten kunnen.

---

Na even Googelen met de nieuwe inzichten, soms heb je even behoefte aan een andere invalshoek, heb ik iets gevonden wat werkt.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Cost extends Model
{
    public function cost_values()
    {
        return $this->hasMany(CostValue::class);
    }

    public function scopeForItem($query, $item_id)
    {
        $query->leftJoin('cost_values', function ($join) use ($item_id) {
            $join->on('cost_values.cost_id', '=', 'costs.id')
                 ->where('cost_values.item_id', '=', $item_id);
        })->addSelect('*', 'price');
    }
}


^ Query scope toegevoegd aan het Cost model (https://laravel.com/docs/5.1/eloquent#query-scopes).

PHP:
1
2
3
4
5
<?php

foreach($costs()->forItem($item->id)->get() as $cost) {
    echo "{$cost->name} || {$cost->default_price} || {$cost->price} <br/>";
}


^ In de view is nu de LEFT geJOINde price beschikbaar.