Relationship 1:1 v Nextras / ORM
- majo
- Člen | 21
Caute,
snazim sa pochopit Nextras/ORM (2.2) a zatial vsetko v pohode, az kym som neprisiel na relationships.
Mam 2 tabulky user a user_password (a vytvorene 2 entity, ktore su zapisane aj v UserRepository)
v user tabulke su nejake data s primarny klucom v stlpci id
potrebujem ziskat data s user_password ktory obsahuje stlpec user_id ($user->password->nejaka_property_s_userPassword)
Vztah je: 1 uzivatel ma 1 heslo (OneHasOne) – dovodom je, ze uzivatel sa moze prihlasovat viacerymi sposobmi, heslo je len jedno z nich, preto som to oddelil
/**
* User
*
* @property int $id {primary}
* @property string $username
* @property string $role
* @property int $active
*
* @property UserPassword $password {1:1 UserPassword::$user_id}
*/
class User extends Entity
{
}
/**
* UserPassword
*
* @property int $id {primary}
*
* @property User $user_id {1:1 User::$id}
*
* @property string $password
* @property int $attempts
* @property DateTime $last_attempt
*/
class UserPassword extends Entity
{
}
cize takto nejak som to vydedukoval, co mi ale vyhodi chybu:
OrmDemo\User::$password relationship with OrmDemo\UserPassword::$user_id is not symetric.
Viem, ze to je urcite cele zle, doteraz som „vyuzival“ doctrine a tam to nejak podobne islo.. Nenakopne ma niekto (nie do guli) tym spravnym smerom?
- majo
- Člen | 21
uz som nacisto bezradny, mozog mam zacykleny, uz fakt neviem co dalej, videl som snad vsetky exceptions ktore su tam, a neviem nato prist..
dokopal som to do „funkcnosti“, ze s entity User data vytiahnem bez problemu, ale s UserPassword nikoli..
pridal som property „password“ na skusku do entity User ci to pojde (a ide), lenze ja chcem aby bol klucom ID, ale budiz..
/**
* User
*
* @property int $id {primary}
* @property string $username
* @property string $role
* @property string $active
*
* @property UserPassword $password {1:1 UserPassword::$user_id, isMain=true}
*
*/
class User extends Entity
{
}
/**
* UserPassword
*
* @property int $id {primary}
* @property User $user_id {1:1 User::$password}
*
* @property string $password
* @property int $attempts
* @property DateTime $last_attempt
*
*/
class UserPassword extends Entity
{
}
pri pokuse:
$this->user = $this->orm->user->findBy(['username' => 'admin'])->fetch();
je vsetko OK, udaje sa nacitaju.
nasledne pri pokuse:
$this->user->password
zahlasi chybu: Undefined property App\Model\User::$user_id.
a vytvara dotazy:
SELECT `user`.* FROM `user` AS `user` WHERE `user`.`username` = 'admin'
SELECT `user`.* FROM `user` AS `user` WHERE `id` IN (1)
kde hodnota v zatvorke je vlastne hodnota stlpca password v tabulke User.. tak som si chcel overit ci je nutne mat iny stlpec vztahu medzi tymi dvoma tabulkami ako primarny kluc kde mi vyhadzovalo chybu ze „property musi mat moznost byt nulova“.. ale primarny kluc predsa nemoze byt nulovy..
uz viac asi nepokrocim.. nikto kto by mi povedal kde robim chybu??
- JZechy
- Člen | 161
@majo Nextras automaticky zbavuje sloupce sufixu _id, takže atributu by měl stačit název user.
Jinak, ono to poprvé je opravdu takové vyšší dívčí nastavovat poprvé vztahy mezi entitami, ale jak jich pár nastavíš, pak už pochopíš, jak to tam chodí, já zprvu taky strávil nad některými vztahy věky :D
Editoval JZechy (7. 2. 2017 20:22)
- hrach
- Člen | 1838
@majo myslim, ze v dokumentaci to zase tak spatne neni, kdyz mrknes sem: http://nextras.org/…elationships#… tak je videt, ze zadny _id se tam nepridava a nad kodem taky je napsano, ze ten sloupec se realne jmenuje se suffixem _id a ve ktere tabulce je, kdyz je ta strana primary. Ale zkusim tu doc vylepsit. Pripadne sem napis jaka exception ta je s jakym zapisem.
- majo
- Člen | 21
ok, takze som vyhodil s anotacii ten suffix _id a na password pridal do db..
User ma:
* User
* @property UserPassword|NULL $password {1:1 UserPassword::$user, isMain=true}
v databazi user upraveny nazov stlpca na password_id
* UserPassword
* @property User $user {1:1 User::$password}
v databaze user_password je nazov stlpca user_id
v tabulke je momentalne 1 zaznam user (password_id = 1) a 1 zaznam user_password (user_id = 1) ..
pri pokuse ziskat data s user:
$this->user = $this->orm->user->getById(1);
je vsetko v poriadku, az kym nesiahnem na property password
$this->user->password; // vrati NULL
mozno som uz blizko, alebo je aj dost mozne, ze som nieco dolezite nepochopil…
taktiez je podstatne, ze potrebujem aby bol primarny kluc $id v user klucom pre druhu tabulku kde su hesla (user_id) . Momentalna property password je len z dovodu, ze mi to zatial inak neslo.
A teda, ked urobim relationship na User::$id x UserPassword::$user dostanem chybu:
`Nextras\Orm\NullValueException
Property App\Model\User::$id is not nullable.`
Primarny kluc ale nemoze byt NULL.
Co sa tyka dokumentacie, je super. Len pri tebou odkazovanej pasazi (1:1 obojsmerne) ma plietla ta entita Ean a pritom je tam definovana entita Tag. Preto som skusal vydedukovat spravnu funkcnost, ku ktorej som sa zatial nedopatral :(
Editoval majo (8. 2. 2017 10:09)
- majo
- Člen | 21
ked spustim nieco taketo:
$this->user = $this->orm->user->getById(1);
var_dump($this->user->password);
tak var_dump je NULL. ale $this->user normalne obsahuje data s tabulky user..
V tracy je jediny dotaz:
SELECT `user
.* FROM user
AS user
WHERE
user
.id
= 1 LIMIT 1`
tabulka user:
CREATE TABLE `user
(
id
int(11) NOT NULL,
username
varchar(60) COLLATE utf8_slovak_ci NOT NULL,
role
varchar(255) COLLATE utf8_slovak_ci NOT NULL,
active
tinyint(1) NOT NULL,
password_id
int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci;
INSERT INTO user
(id
, username
,
role
, active
, password_id
) VALUES
(1, ‚admin‘, ‚user,admin‘, 1, 1);`
Tabulka user_password:
CREATE TABLE `user_password
(
id
int(11) NOT NULL,
user_id
int(11) NOT NULL,
password
varchar(60) COLLATE utf8_slovak_ci NOT NULL,
attempts
int(3) NOT NULL,
last_attempt
datetime DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci;
INSERT INTO user_password
(id
,
user_id
, password
, attempts
,
last_attempt
) VALUES
(1, 1, ‚$2y$10$QPEXXD8HM98bmHl6jkqPj.g7KTip9tQtLSd4rgn62frN/.045orRW‘, 0,
NULL);`
cache premazavam vzdy pred nejakou zmenou..
Editoval majo (8. 2. 2017 11:56)
- majo
- Člen | 21
ak zmenim s MyISAM na InoDB a nastavim:
ALTER TABLE `user
ADD CONSTRAINT user_ibfk_1
FOREIGN KEY (password_id
)
REFERENCES user_password
(user_id
);`
a
ALTER TABLE `user_password
ADD CONSTRAINT user_password_ibfk_1
FOREIGN KEY
(user_id
) REFERENCES user
(password_id
);`
tak na $this->user->password prebehnu tieto
dotazy:
SELECT `user
.* FROM user
AS user
WHERE
user
.id
= 1 LIMIT 1
SELECT user
.* FROM user
AS user
WHERE
id
IN (1)`
a vyhodi exception:
Nextras\Orm\InvalidArgumentException
Undefined property App\Model\User::$user.
- majo
- Člen | 21
caute, dnes som sa k tomu vratil, a aj tak mi to nejde akoby malo..
Relationships je nastavene spravne… ale ked chcem vytiahnut nejake data tak mi to vzdy vrati bud NULL (v pripade 1:1 – tu ani nezada dotaz do DB) alebo objekt Nextras\Orm\Relationships\OneHasMany (v pripade 1:M), ktory je bez vysledkov (zistene cez ->count() ).
Dotaz sa vygeneruje spravne, napr.
SELECT `user`.* FROM `user` AS `user` WHERE `user`.`username` = 'admin' LIMIT 1
SELECT `user_permanent`.* FROM `user_permanent` AS `user_permanent` WHERE `user_permanent`.`user_id` IN (1)
ked druhy dotaz spustim v phpmyadmin tak mi bez problemu zobrazi vysledky ako maju byt..
je nejaky rozdiel ked pouzivam MyISAM alebo InnoDB s nastavenymi klucmi? Lebo ak aj nastavim kluce v InnoDB rovnako ako mam zapisane v entitach, tak je vysledok rovnaky (teda ziadny).
Dotaz:
SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL AND TABLE_NAME = 'user_permanent'
v phpmyadmin nevrati nic…
tak uz som fakt ze bezradny..
Editoval majo (9. 2. 2017 19:02)
- majo
- Člen | 21
skusim este ako posledny pokus polozit posledne otazky, ostatne su uz pase..
ak pri vztahu 1:1 vytvorim v tabulke user stlpec s nazvom property v ktorej definujem tento vztah, a zadam lubovolnu hodnotu vznikne takyto dotaz:
SELECT user_password
.* FROM user_password
AS
user_password
WHERE id
IN
(1)
kde hladana hodnota (1) je vlastne hodnota s toho vytvoreneho stlpca a hlada sa v stlpci ID, pritom definovany je stlpec UserPassword::$USER_ID .. to je bug alebo feature?
ak tento stlpec zrusim, tak sa ziadny dotaz do DB nevytvori a property s definiciou vztahu dostane rovno NULL, aj ked existuje
pri vztahu 1:M a neexistencii stlpca s nazvom property v ktorej definujem vztah vznikne dotaz:
SELECT user_permanent
.* FROM user_permanent
AS
user_permanent
WHERE
user_permanent
.user_id
IN (2)
pricom hladana hodnota je v poriadku (primarny kluc uzivatela), tak isto aj definovany stlpec v druhej tabulke.. avsak nevrati ziadny vysledok, aj ked su zaznamy v tabulke..
ak vytvorim stlpec a zadam nejaku hodnotu skonci to chybou:
TypeError
Argument 1 passed to Nextras\Orm\Relationships\HasMany::set() must be of the type array, integer given, called in D:\www\nette\nette\vendor\nextras\orm\src\Relationships\HasMany.php on line 77
dva uplne odlisne spravania… je to bug, feature, alebo som blby ja?
Editoval majo (9. 2. 2017 20:03)