Doctrine a počet čtenářů článku

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Fyasko
Člen | 106
+
0
-

Ahoj opět se obracím na znalé. Snažím se Z doctrine vytáhnout ke každému článku počet čtenářů kvůli řazení, ale druhý den se nedaří.

Takto vypadá Entita pro články

<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Kdyby\Doctrine;

/**
 * @ORM\Entity
 * @ORM\Table(name="articles")
 *
 */
class Article extends Doctrine\Entities\BaseEntity
{

    use Doctrine\Entities\Attributes\Identifier;

    /**
     * @ORM\OneToMany(targetEntity="Reader", mappedBy="article", orphanRemoval=true, cascade={"persist", "remove"})
     */
    public $readers;

	public function __construct()
    {
        $this->readers = new ArrayCollection();
    }

	....
?>

Toto je entita která ukládá unikátní čtenáře

<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Kdyby\Doctrine;

/**
 * @ORM\Entity
 * @ORM\Table(name="readers")
 *
 */
class Reader extends Doctrine\Entities\BaseEntity
{

    use Doctrine\Entities\Attributes\Identifier;

    /**
     * @ORM\ManyToOne(targetEntity="Article", inversedBy="readers")
     * @ORM\JoinColumn(name="id_article", referencedColumnName="id")
     */
    public $id_article;

    /** @ORM\Column(type="string", length=200) */
    public $ip;

	....
?>

Toto je dotaz kterým se snažím získat výsledek

<?php
return new ResultSet($this->repository->createQuery("
					SELECT a, COUNT(b.id) // zkoušel jsem COUNT(b), COUNT(b.id_article)
					FROM App\Entity\Article a
					JOIN a.readers b));
?>

Když řadím podle autora, který je ManyToOne tak je vše v pořádku, ale mě se nedaří ani vytáhnout ty čísla, natož řadit(ale to už by bylo vpho).

Laděnka hlásí
Undefined index: article

Všem budu vděčný za jakékoliv reakce. Předem díky.

chap
Člen | 81
+
0
-

neměl by jsi mít toto? … vlastnost id_article predelat na article = reference na Article zvlast to ID

/**
 * @var integer
 *
 * @ORM\Column(name="id_article", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
protected $id_article;
	/**
 * @ORM\ManyToOne(targetEntity="Article", inversedBy="readers")
 * @ORM\JoinColumn(name="id_article", referencedColumnName="id")
 */
public $article;
Fyasko
Člen | 106
+
0
-

Jsem v Doktríně začátečník, takže pokud tvrdíš že bych měl pak zřejmě ano :) . Každopádně po doplnění jsem stále na stejné chybě.

chap
Člen | 81
+
0
-

Ted koukam, ze tam mas use Doctrine\Entities\Attributes\Identifier;, který přidává sloupec ID tkaže asi jen toto:

/**
 * @ORM\ManyToOne(targetEntity="Article", inversedBy="readers")
 * @ORM\JoinColumn(name="id_article", referencedColumnName="id")
 */
public $article;

Smazal jsi cache? co píše konzole
php index.php orm:validate-schema

Martk
Člen | 661
+
+1
-

Máš špatně mapující položku:

targetEntity="Reader", mappedBy="article", orphanRemoval=true, cascade={"persist", "remove"}

Ale v entitě Reader se nenachází žádná položka s názvem article, proto to hlásí undefined index article
Správně je:
targetEntity="Reader", mappedBy="id_article", orphanRemoval=true, cascade={"persist", "remove"}

Tento řádek se dá vynechat (nepíšu, že to je špatně, můžeš to tam nechat):
@ORM\JoinColumn(name="id_article", referencedColumnName="id")

Fyasko
Člen | 106
+
0
-

Pokud přidám tento sloupec do entity Article, tak se mi v tabulce „articles“ vytvoří sloupec který tam být nemá. Pokud bylo myšleno dát ho do entity Reader, tak sloupec který tam již je $id_article, je identický .Ta vazba v db funguje správně, takže to opět zase asi špatně chápu :)

Validate vypisuje toto:

<?php
[Mapping]  FAIL - The entity-class 'App\Entity\Article' mapping is invalid:
* The association App\Entity\Article#user refers to the inverse side field App\Entity\User#articles which does not exist.

[Mapping]  FAIL - The entity-class 'App\Entity\Group' mapping is invalid:
* The mappings App\Entity\Group#group and App\Entity\User#group are inconsistent with each other.

[Mapping]  FAIL - The entity-class 'App\Entity\User' mapping is invalid:
* The mappings App\Entity\User#user and App\Entity\Article#user are inconsistent with each other.
* The association App\Entity\User#group refers to the inverse side field App\Entity\Group#users which does not exist.
* The association App\Entity\User#group2 refers to the inverse side field App\Entity\Group#users which does not exist.

[Database] OK - The database schema is in sync with the mapping files.
?>

Takže mapování na Reader by mělo být asi dobře ne? .. A ano cache jsem mazal :)

chap napsal(a):

Ted koukam, ze tam mas use Doctrine\Entities\Attributes\Identifier;, který přidává sloupec ID tkaže asi jen toto:

/**
 * @ORM\ManyToOne(targetEntity="Article", inversedBy="readers")
 * @ORM\JoinColumn(name="id_article", referencedColumnName="id")
 */
public $article;

Smazal jsi cache? co píše konzole
php index.php orm:validate-schema

Fyasko
Člen | 106
+
0
-

Tak jo, pohli jsme se dopředu :) . Nyní už mu nevadí index, ale pro jistotu nevrátí vůbec nic :D

Trying to get property of non-object

Antik napsal(a):

Máš špatně mapující položku:

targetEntity="Reader", mappedBy="article", orphanRemoval=true, cascade={"persist", "remove"}

Ale v entitě Reader se nenachází žádná položka s názvem article, proto to hlásí undefined index article
Správně je:
targetEntity="Reader", mappedBy="id_article", orphanRemoval=true, cascade={"persist", "remove"}

Tento řádek se dá vynechat (nepíšu, že to je špatně, můžeš to tam nechat):
@ORM\JoinColumn(name="id_article", referencedColumnName="id")

Fyasko
Člen | 106
+
0
-

Zkusil jsem napsat dotaz takto:

<?php
return new ResultSet($this->repository->createQuery("
                    SELECT a, b // zkoušel jsem COUNT(b), COUNT(b.id_article)
                    FROM App\Entity\Article a
                    JOIN a.readers b));
?>

a to vrátí počet výsledků podle záznamů v tabulce readers, což je úplně zle.

Fyasko
Člen | 106
+
0
-

Dotáhl jsem to validování na stav níže pro jistotu a najednou mi na dql, který je výše vyskočil počet záznamů správně. Poté jsem v šabloně vypsal {count($article->readers)} a zdá se, že to vypisuje správná data. Jen by mě zajímalo proč mu vadí ten COUNT už v dotazu?
[Mapping] OK – The mapping files are correct.
[Database] OK – The database schema is in sync with the mapping files.

Edit:
proměmnná {count($article->readers)} je funkční ikdyž ten JOIN vůbec nepoužiju.

Editoval Fyasko (23. 3. 2016 14:20)

leninzprahy
Člen | 150
+
0
-

Fyasko napsal(a):

Dotáhl jsem to validování na stav níže pro jistotu a najednou mi na dql, který je výše vyskočil počet záznamů správně. Poté jsem v šabloně vypsal {count($article->readers)} a zdá se, že to vypisuje správná data. Jen by mě zajímalo proč mu vadí ten COUNT už v dotazu?
[Mapping] OK – The mapping files are correct.
[Database] OK – The database schema is in sync with the mapping files.

Edit:
proměmnná {count($article->readers)} je funkční ikdyž ten JOIN vůbec nepoužiju.

Jen pro pořádek, mappedBy="xy" odkazuje na property $xy, pokud se má sloupec v databázi jmenovat jinak, je potřeba to definovat @ORM\JoinColumn(name="xyz" ...)

COUNT() v sekci SELECT mu vadí, protože ho nemůže namapovat do žádné entity.

{count($article->readers)} by mělo fungovat vždy, jen když bude v dotazu JOIN, vytáhnou se všechny záznamy jedním dotazem, pokud tam nebude, položí se nejprve jeden dotaz na všechny články, a pak ke každému článku jeden dotaz na jeho readers.

Fyasko
Člen | 106
+
0
-

Pravda, pomocí {count($article->readers)} se ptá na každý článek zvlášť kolik má čtenářů.
To mappedBy jsem myslím už pochopil(snad :) ). Díky tomu jsem odstranil chyby v tom mapování.

Dobře, tak pokud ho nemůže namapovat do žádné entity, jak docílím toho aby mohl?
Entity jsou nahoře ukázané obě.

Fyasko
Člen | 106
+
0
-

Ve finále mi jde vlastně o to, zobrazit např. 20 nejčtenějších článků. Řazení je už jen podle sloupců v entitě Article

leninzprahy
Člen | 150
+
0
-

Fyasko napsal(a):

Ve finále mi jde vlastně o to, zobrazit např. 20 nejčtenějších článků. Řazení je už jen podle sloupců v entitě Article

Zkusil bych něco jako:

SELECT a, COUNT(b) AS HIDDEN cnt
FROM App\Entity\Article a
JOIN a.readers b
ODER BY cnt DESC
Oli
Člen | 1215
+
0
-

Pokud to chceš jen kvůli tomu řazení, tak si myslím, že ta bi-directional vazba je zbytečná. Píšu z hlavy, ale myslím, že by mohlo jít něco jako

$this->repository->createQueryBuilder()
	->select('a, COUNT(r.id) AS readers')
	->from(Reader::class, 'r')
	->join('r.article_id', 'a')
	->orderBy('readers', 'ASC')
Fyasko
Člen | 106
+
0
-

Když přidám HIDDEN, tak to projde, ale já bych raději abych byl navedenen na důvod proč to nejede. Toto není jediný případ využití na webu a potřeboval bych pomoc s tím abych mi COUNT fungovalo i bez HIDDEN

leninzprahy napsal(a):

Fyasko napsal(a):

Ve finále mi jde vlastně o to, zobrazit např. 20 nejčtenějších článků. Řazení je už jen podle sloupců v entitě Article

Zkusil bych něco jako:

SELECT a, COUNT(b) AS HIDDEN cnt
FROM App\Entity\Article a
JOIN a.readers b
ODER BY cnt DESC
leninzprahy
Člen | 150
+
0
-

Tím HIDDEN říkáš, že tě to ve výsledku nezajímá, Doctrine se tento sloupec nesnaží namapovat do výsledné entity…

http://lmgtfy.com/?…

Fyasko napsal(a):

Když přidám HIDDEN, tak to projde, ale já bych raději abych byl navedenen na důvod proč to nejede. Toto není jediný případ využití na webu a potřeboval bych pomoc s tím abych mi COUNT fungovalo i bez HIDDEN

leninzprahy napsal(a):

Fyasko napsal(a):

Ve finále mi jde vlastně o to, zobrazit např. 20 nejčtenějších článků. Řazení je už jen podle sloupců v entitě Article

Zkusil bych něco jako:

SELECT a, COUNT(b) AS HIDDEN cnt
FROM App\Entity\Article a
JOIN a.readers b
ODER BY cnt DESC
Fyasko
Člen | 106
+
0
-

Tomu rozumím, ale furt to není to, čeho bych rád dosáhl(naučil se). Potřeboval bych pochopit proč mi to nechce spočítat už v dql. To je v podstatě to podstatné.

leninzprahy napsal(a):

Tím HIDDEN říkáš, že tě to ve výsledku nezajímá, Doctrine se tento sloupec nesnaží namapovat do výsledné entity…

http://lmgtfy.com/?…

Fyasko napsal(a):

Když přidám HIDDEN, tak to projde, ale já bych raději abych byl navedenen na důvod proč to nejede. Toto není jediný případ využití na webu a potřeboval bych pomoc s tím abych mi COUNT fungovalo i bez HIDDEN

leninzprahy napsal(a):

Fyasko napsal(a):

Ve finále mi jde vlastně o to, zobrazit např. 20 nejčtenějších článků. Řazení je už jen podle sloupců v entitě Article

Zkusil bych něco jako:

SELECT a, COUNT(b) AS HIDDEN cnt
FROM App\Entity\Article a
JOIN a.readers b
ODER BY cnt DESC
leninzprahy
Člen | 150
+
0
-

Asi stále úplně nerozumím, čemu nerozumíš, čeho chceš dosáhnout :)
Ono to v tom DQL spočítá, a pak to podle toho výsledek seřadí, jen se to nedostane do toho výsledku.

Zkus si prostudovat DQL SELECT Examples kde je to celkem hezky popsáno.

Pokud v tom výsledku ty počty chceš, stačí klíčové slovo HIDDEN smazat, jen výsledkem už nebude pole entit, ale pole polí, něco jako

[
	0 => [
		0   => Article,
		cnt => 10
	],
	1 => [
		0   => Article,
		cnt => 8
	],
	...
]

ale to mi přijde zbytečné, protože k tomu počtu se dostaneš z entity Article count($article->readers); nebo si můžeš dopsat metodu

class Article {
	...
	/** @return int */
	public function getReadersCount() {
		return count($this->readers);
	}
	...
}

Mimochodem, jako verzi Doctrine používáš?

Fyasko napsal(a):

Tomu rozumím, ale furt to není to, čeho bych rád dosáhl(naučil se). Potřeboval bych pochopit proč mi to nechce spočítat už v dql. To je v podstatě to podstatné.

leninzprahy napsal(a):

Tím HIDDEN říkáš, že tě to ve výsledku nezajímá, Doctrine se tento sloupec nesnaží namapovat do výsledné entity…

http://lmgtfy.com/?…

Fyasko napsal(a):

Když přidám HIDDEN, tak to projde, ale já bych raději abych byl navedenen na důvod proč to nejede. Toto není jediný případ využití na webu a potřeboval bych pomoc s tím abych mi COUNT fungovalo i bez HIDDEN

leninzprahy napsal(a):

Fyasko napsal(a):

Ve finále mi jde vlastně o to, zobrazit např. 20 nejčtenějších článků. Řazení je už jen podle sloupců v entitě Article

Zkusil bych něco jako:

SELECT a, COUNT(b) AS HIDDEN cnt
FROM App\Entity\Article a
JOIN a.readers b
ODER BY cnt DESC
Fyasko
Člen | 106
+
0
-

Používám verzi „kdyby/doctrine“: „^3.0“. No původní účel byl pouze najít např 10 nejčtenějších článků, ale z hlavy vymyslím dalších xy případů, kdy se ten COUNT hodí vytáhnout už v dotazu. Proto bych rád došel řešení proč to nejde :)

Btw pokud použiju

SELECT a, COUNT(b) AS HIDDEN cnt FROM App\Entity\Article a JOIN a.readers b ORDER BY cnt DESC

výsledek vrátí pouze jeden článek a to ten nejčtenější.

Editoval Fyasko (24. 3. 2016 23:02)

pepakriz
Člen | 246
+
0
-

Pokud rozumím správně otázce, pak ti tam chybí group by a.id nebo tak něco.

Fyasko
Člen | 106
+
0
-

Dá se nějakým způsobem vypsat přesný array, který ta doctrina vrátí? Když to GROUPnu, tak to nejspíše jede, ale nedokážu se dopátrat jak ty hodnotám přistupovat.

leninzprahy
Člen | 150
+
0
-

Koukám, že ty ten výsledek obaluješ ještě třídou ResultSet která nevím co přesně dělá, ale když si to vytáhneš:

$res = $this->repository->createQuery("
	SELECT a, COUNT(b) AS cnt
	FROM App\Entity\Article a
	JOIN a.readers b
	ODER BY cnt DESC")->getResult();

mělo by to $res obsahovat pole

[
    0 => [
        0   => Article,
        cnt => 10
    ],
    1 => [
        0   => Article,
        cnt => 8
    ],
    ...
]

Fyasko napsal(a):

Používám verzi „kdyby/doctrine“: „^3.0“. No původní účel byl pouze najít např 10 nejčtenějších článků, ale z hlavy vymyslím dalších xy případů, kdy se ten COUNT hodí vytáhnout už v dotazu. Proto bych rád došel řešení proč to nejde :)

Btw pokud použiju

SELECT a, COUNT(b) AS HIDDEN cnt FROM App\Entity\Article a JOIN a.readers b ORDER BY cnt DESC

výsledek vrátí pouze jeden článek a to ten nejčtenější.

Editoval leninzprahy (29. 3. 2016 13:09)