2016-08-02 57 views
6

Mam do czynienia z dziwnym problemem w Yii2 Mam zapytanie, które ma jedno sprzężenie z tabelą agenta i (jedną do wielu) relację zadań z zadaniem działa dobrze, ale problem jest to, że zwraca wszystko w sznurku. Poniżej znajduje się zapytanie:Yii2 Active Record Odpowiedź JSON, typ casting issue

$query = self::find() 
     ->select("job.*, agent.first_name,agent.last_name") 
     ->leftJoin('agent', 'job.agent_id = agent.id') 
     ->with('tasks') 
     ->asArray() 
     ->all(); 

i JSON zakodowany wynik:

{ 
    "success": true, 
    "data": [ 
    { 
    "id": "10", 
    "customer_id": "1", 
    "job_type": "normal", 
    "created": "2016-06-22 10:19:25", 
    "first_name": "Shayan", 
    "last_name": "", 
    "tasks": [ 
    { 
     "id": "10", 
     "job_id": "10", 
     "title": "bring food", 
     "instruction": null, 
     "created": "2016-06-22 10:19:25", 

    }, 
    { 
     "id": "10", 
     "job_id": "10", 
     "title": "bring pizza", 
     "instruction": null, 
     "created": "2016-06-22 10:19:25", 

    }, 
    ] 
} 

jeśli zauważy pola jak id, customer_id i job_id one wszystkie są całkowitą ale powróci jako ciąg. Ale jeśli usunę -> asArray() z powyższej kwerendy, zwróci ona prawidłowy typ castingu, ale problem jest pomijanie relacyjnych i pola leftJoin agenta tabeli, zwraca tylko pola tabeli zadań tutaj jest odpowiedź po usunięciu -> asArray() z powyższego zapytania.

{ 
"success": true, 
"data": [ 

{ 
    "id": 10, 
    "customer_id": 1, 
    "name": null, 
    "job_type": "normal", 
    "created": "2016-06-22 10:19:25", 
}, 

Jeśli zauważysz w powyżej odpowiedzi nie mają stoły czynnik FIRST_NAME LAST_NAME i relacyjnych danych zadania całkowicie pominięte ale id i customer_id jest liczbą całkowitą.

Czy ktoś napotkał ten sam problem? twoja pomoc byłaby bardzo ceniona. Z góry dzięki.

Odpowiedz

12

Chciałem się upewnić, że tak właśnie jest. Testowałem to sam z dość podobnym zapytaniem, a moje wyniki są bardzo podobne:

array(2) { 
    [0]=> 
    array(5) { 
    ["id"]=> 
    string(1) "1" 
    ["name"]=> 
    string(5) "Admin" 
    // ... 
    } 
// ... 
} 

W moim przypadku otrzymuję również wszystkie typy jako ciągi. Tak więc, jeśli zamierzasz sprawdzić dane wejściowe i ich typ za pomocą if ($data[0]['id'] === 1), otrzymasz wynik false, ponieważ jest to string.

Ale musisz dodać przed zmienną (int), aby przekształcić ją w inną typecast. Byłoby to: (int) $data[0]['id'].

Następnie var_dump((int) $data[0]['id']); (w moim przypadku) da int(1) zamiast string(1) "1".

Można również sprawdzić w instrukcji warunkowych:

((int) $data[0]['id'] === 1) ? exit('Integer') : exit('Not integer'); 

bez pisania (int) jako przedrostek da Not integer rezultat natomiast z prefiksem przyniesie Integer.

Jeśli nie chcesz, aby pisząc te przedrostki w każdej funkcji można napisać coś takiego:

$data[0]['id'] = (int) $data[0]['id']; 

A teraz $data[0]['id'] będzie integer w przyszłych zastosowań.


Nowe rozwiązanie:

To nowe rozwiązanie zwróci obiekt z tablicami, a nie tylko tablic.

// Method that gives data back. In this case, user with ID == 10. 
public static function getData() 
{ 
    $dataProvider = new ActiveDataProvider([ 
     'query' => self::findOne(['id' => 10])->attributes 
    ]); 

    return $dataProvider; 
} 

W Controller (jak zawsze) przekazać ten obiekt:

$data = User::getData(); 

return $this->render('user', [ 
      //... 
      'data' => $data 
     ]); 

a następnie w przeglądarce można uzyskać dostęp do wartości (w prawidłowym typecast) tak:

$data->query['columnName']; 

Więc, w celu sprawdzenia tożsamości:

($data->query['id'] === 10 ? exit('ok') : exit('nok')); 

Otrzymasz odpowiedź ok (typecast: liczba całkowita, wartość: 10).

+3

Nie powinno być typu automatycznego odlewania zamiast robić to ręcznie Czy istnieje jakiś sposób obejścia tego problemu? –

+0

Niestety, nie widzę sposobu, aby to zmienić (lub przynajmniej nie jestem tego świadomy), ponieważ jest to [domyślne zachowanie] (https://github.com/yiisoft/yii2/issues/9329#issuecomment- 128343292), według autora. Ale może to być błąd lub coś takiego. Pracowałem też z prefiksami, nie jest to takie trudne. –

+1

Ale jeśli użyjesz tylko all() zamiast asArray() -> all(), zwróci to poprawny typ danych, ale problem spowoduje, że zwróci on tylko dane z jednej tabeli, która pomija powiązania i łączy. –

7

Jest to oczekiwane zachowanie, a także documented:

Uwaga: Chociaż metoda ta pozwala zaoszczędzić pamięć i poprawia wydajność, to jest bliżej dolnej DB warstwy abstrakcji i stracisz najbardziej aktywnej funkcji Record . Bardzo ważne rozróżnienie leży w typie danych wartości kolumny. Po zwróceniu danych w wystąpieniach rekordu aktywnego wartości kolumn będą automatycznie typowane zgodnie z rzeczywistymi typami kolumn; z drugiej strony, gdy zwracasz dane w tablicach, wartości kolumn będą ciągami znaków (ponieważ są wynikiem PDO bez żadnego przetwarzania), niezależnie od ich rzeczywistych typów kolumn.

Na drugiej kwestii, w celu pobrania dodatkowych pól w aktywnej klasy rekordu trzeba tworzyć dodatkowe właściwości w klasie do nich:

class MyRecord extends \yii\db\ActiveRecord 
{ 
    public $first_name; 
    public $last_name; 

    // ... 
}