Yii Framework Forum: Dane do portletu z dwóch modeli - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Dane do portletu z dwóch modeli Rate Topic: -----

#1 User is offline   robikon 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 32
  • Joined: 17-October 11

Posted 04 June 2012 - 05:43 AM

Witam.
Posiadam na stronie portlet który wyświetla kategorie pobrań dla plików, np:

Regulaminy
Pliki
itd.

i po kliknięciu odpowiedniej kategorii na stronie mam spis plików tylko z tej kategorii. Chciałem dołożyć do tego jeszcze aby obok nazwy kategorii informacje o ilości plików w danej kategorii, np:

Regulaminy (2)
Pliki (1)
Inne (0)

Kod portletu:

<?php
Yii::import('zii.widgets.CPortlet');
 
class DownloadCategory extends CPortlet
{
    public $title='Kategoria';
    public $decorationCssClass='portletdownload-decoration';
    public $titleCssClass='portletdownload-title';
    public $contentCssClass='portletdownload-content';
     
    public function getDownloadCategory()
    {
        return Typpobrania::model()->findDownloadCategory();
    }
 
    protected function renderContent()
    {
        $this->render('downloadCategory');
    }
}
?>


Kod funkcji z modelu:

public function findDownloadCategory()
{
    return $this->findAll();
}


Kod widoku:

<ul>
	<?php foreach($this->getDownloadCategory() as $downloads): ?>
	<li> <?php echo CHtml::link(CHtml::encode($downloads->nazwa), $downloads->getUrl()); ?> </li>
	<?php endforeach; ?>
</ul>


Ponieważ chcę aby były wyświetlone wszystkie nazwy kategorii dlatego dane dla portletu są z tabeli Typpobrania, gdzie są dwa pola: id i nazwa, ale ma to ta wadę że nie mogę zrobić zliczenia ile plików wg danej kategorii występuje ponieważ są one umieszczone w tabeli połączonej Pobrania.
Obie tabele są połączone relacjami:
Typpobrania:
'pobrania' => array(self::HAS_MANY, 'Pobrania', 'typpobrania_id'),

Pobrania:
'typpobrania' => array(self::BELONGS_TO, 'Typpobrania', 'typpobrania_id'),


Oczywiście mogę to zrobić wg modelu Pobrania, ale wtedy nie mam kategorii w których nie ma żadnych plików.

W SQL-u byłoby to tak:
SELECT nazwa, (SELECT count(typpobrania_id) FROM tbl_pobrania WHERE typpobrania_id = p.id) AS ile FROM tbl_typpobrania p

tylko jak to wcisnąć do tego modelu ?
0

#2 User is offline   Mariusz W. 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 24
  • Joined: 15-December 11
  • Location:Poland/Warsaw

Posted 04 June 2012 - 12:58 PM

Nie najefektywniejsza metoda, ale najłatwiejsza bo już wszystko masz :)
W pętli foreach daj:
echo count($downloads->pobrania);

Ta da :)
Posted Image
Posted Image
0

#3 User is offline   aquasite.pl 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 20-May 11

Posted 04 June 2012 - 01:06 PM

Obstawiam, że przyda Ci się to:
http://www.yiiframew...atistical-query
Jeśli nie to wrzuć tu schemat tabel z bazy danych.
Posted Image
Agencja interaktywna Itzen.pl
Informatyczne rozwiązania dla firm.
Programowanie, Pozycjonowanie, Testy A/B, Reklama.
0

#4 User is offline   robikon 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 32
  • Joined: 17-October 11

Posted 04 June 2012 - 04:44 PM

Wydaje mi się, że sprawę załatwiłoby FindAllBySql() w funkcji findDownloadCategory(), które w wyniku podałoby właściwy zestaw pól, tylko moje próby zpisania tego sql'a:

SELECT nazwa, (SELECT count( typpobrania_id ) FROM tbl_pobrania WHERE typpobrania_id = p.id) AS ile
FROM tbl_typpobrania p

coś nie wychodzą.
0

#5 User is offline   Mariusz W. 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 24
  • Joined: 15-December 11
  • Location:Poland/Warsaw

Posted 05 June 2012 - 01:27 AM

Nie próbowałeś mojego rozwiązania? :)

<ul>
        <?php foreach($this->getDownloadCategory() as $downloads): ?>
        <li> <?php echo CHtml::link(CHtml::encode($downloads->nazwa).'('.count($downloads->pobrania).')', $downloads->getUrl()); ?> </li>
        <?php endforeach; ?>
</ul>

Posted Image
Posted Image
1

#6 User is offline   robikon 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 32
  • Joined: 17-October 11

Posted 05 June 2012 - 02:17 AM

View PostMariusz W., on 05 June 2012 - 01:27 AM, said:

Nie próbowałeś mojego rozwiązania? :)

<ul>
        <?php foreach($this->getDownloadCategory() as $downloads): ?>
        <li> <?php echo CHtml::link(CHtml::encode($downloads->nazwa).'('.count($downloads->pobrania).')', $downloads->getUrl()); ?> </li>
        <?php endforeach; ?>
</ul>



Twoja propozycja jest OK i ją zastosowałem, tylko nie wiem na jakiej zasadzie działa ta cześć kodu:

count($downloads->pobrania)

więc próbowałem z FindAllBySql() bo wiem co z czego, a tu funkcja:

public function findDownloadCategory()
{
    return $this->findAll();
}


jest w modelu w którym są tyko 2 kolumny id i nazwa, więc skąd ten "count" wie że ma zliczać wg pola "typpobrania_id" z modelu "Pobrania"?
Chyba, że relacje to załatwiają?
A czy funkcja findDownloadCategory()nie powinna mieć odniesienia do tej relacji i wygladać tak:

public function findDownloadCategory()
    {
        return $this->with('pobrania')->findAll();
    }

0

#7 User is offline   drylko 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 86
  • Joined: 13-September 09
  • Location:Poland

Posted 10 June 2012 - 03:57 PM

Czesc

View Postrobikon, on 05 June 2012 - 02:17 AM, said:

Twoja propozycja jest OK i ją zastosowałem, tylko nie wiem na jakiej zasadzie działa ta cześć kodu:

count($downloads->pobrania)



Lazy loading. Czyli w momencie wywolania count($downloads->pobrania) odpala sie getter, ktory dochodzi do wniosku, ze wlasnosc pobrania to relacja o takiej nazwie. Wykonuje zatem sql, ktory znajduje wszystkie rekordy pasujace do relacji i zwraca te rekordy w postaci tablicy. Nastepnie count zwraca ilosc elementow w tej tablicy. Nie jest to wydajne, poniewaz dla kazdego rekordu tego samego typu co $downloads musisz wykonac osobny sql pobierajacy wszystkie 'pobrania'... Chyba, ze uzyjesz wczesniej modyfikatora with.

Czasami bywa tak, ze lepiej uzywac findBySql niz liczyc na to, ze wszystko zalatwi za Ciebie aktywny rekord. Jezeli bardzo zalezy Ci na tym, zeby wszystkie pobrane elementy byly obiektami uzyj populateRecords

d.
1

#8 User is offline   raydeal 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 21-January 12
  • Location:Southern Poland

Posted 11 June 2012 - 03:38 PM

Czesc,

@robikon modele po czym dziedzicza? po ActiveRecord czy po CModel?

Wlasciwie to nie ma wielkiego znaczenia bo zawsze mozesz w AR skorzystac z natywnego sqla.

Mozesz sprobowac tak:
public function findDownloadCategory()
    {
       $sql= 'SELECT nazwa, (SELECT count( typpobrania_id ) FROM tbl_pobrania WHERE typpobrania_id = p.id) AS ile
FROM tbl_typpobrania p'; 
       $connection = Yii::app()->db;
       $command=$connection->createCommand($sql);
       $result = $command->queryAll();
       return $result;
    }

Albo mozesz wykorzystac Query Buildera zapisujac tak (wynik powinien byc taki sam):
public function findDownloadCategory()
    {
       $result = Yii::app()->db->createCommand()->select('p.nazwa, (SELECT count( typpobrania_id ) FROM tbl_pobrania WHERE typpobrania_id = p.id) AS ile')
                                                 ->from('tbl_typpobrania p')->queryAll();

       return $result;
    }


Jesli chodzi o samo zapytanie to lepszy (ale to jeszcze zalezy kiedy :) ) bylby zapis w stylu:
SELECT tp.nazwa, COUNT(pob.typpobrania_id) AS ile
FROM tbl_typpobrania tp
JOIN tbl_pobrania pob ON (pob.typpobrania_id = tp.id)
GROUP BY tp.nazwa

czyli procedura mialaby postac np:
public function findDownloadCategory()
    {
       $result = Yii::app()->db->createCommand()->select('tp.nazwa, COUNT(pob.typpobrania_id) AS ile')
                                                ->from('tbl_typpobrania tp')
                                                ->join('tbl pobrania pob', 'pob.typpobrania_id = tp.id')
                                                ->group('tp.nazwa')
                                                ->queryAll();

       return $result;
    }


Tak jak napisal @drylko, jesli zalezaloby Ci bardzo, zeby zwracany wynik byl typowym AR to kazde zwrocenie wyniku powinienes zapisac jako:
 return $this->populateRecords($result); 

1

#9 User is offline   robikon 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 32
  • Joined: 17-October 11

Posted 14 June 2012 - 01:44 PM

Szczerze dziękuję, za wszystkie podpowiedzi i przykłady użycia składni SQL w zapytaniach. Fajnie wytłumaczone.
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users