Modyfikacja {Summary} W Template Cgridview

Witam serdecznie.

Mam taki oto problem. Chciałbym zmodyfikować {summary} w template CGridView - domyślnie {summary} wyświetla dane w takich sposób: {start} - {end} z {count}. Mam przykładową bazę danych bloga z postami, gdzie posty są przypisane do ich autora. Ja chciałbym w {summary} wyświetlić wyniki, które wskazywałyby ile jest łącznie postów danego użytkownika oraz ile jest łącznie postów wszystkich użytkowników w całej bazie danych. Coś na zasadzie {zlicz wszystkie posty przypisane do aktualnie zalogowanego użytkownika} - {zlicz wszystkie posty w bazie danych}. Ewentualnie jeśli byłoby to bardzo trudne aby zrobić to w CGridView to mógłbym to zrobić niezależnie od CGridView. Aczkolwiek chciałbym, aby to było związane z CGridView, a to dlatego, że: Tworzę na przykład kilka kategorii postów dla wszystkich użytkowników: np. samochody, książki itp. czyli zwyczajne działy. I później np. użytkownik filtrując swoje posty wyswietla wszystkie swoje posty z działu "samochody", to chciałbym, żeby to podsuomwanie o którym pisałem powyżej w sytuacji, gdy ktoś wyswietla posty z danego działu - wyświetlało takie zestawienie: {zlicz posty użytkownika z działu samochody} - {zlicz wszystkie posty w bazie z działu samochody}.

Czy ktoś mógłby mnie jakoś naprowadzić na rozwiązanie tego problemu?

Z góry dziękuję

Pozdrawiam

Tomasz

Za wyświetlanie treści w "summary" odpowiada właściwość $summaryText.

CGridView zamienia w $summaryText następujące zwroty na wartości liczbowe:

{start}

{end}

{count}

{page}

{pages}

Możesz więc zrobić np tak:





$this->widget('zii.widgets.grid.CGridView', array(

    'dataProvider'=>$dataProvider,

    'summaryText' => count(Post::model()->findByAttributes(array('userid'=>Yii::app()->user->id)))

        . ' Twoich postów, ' . count(Post::model()->findAll()) . ' wszystkich postów, strona: {page}',

));




Przykład powyżej to tylko zarys. Oczywiście ilość postów możesz zrobić wg relacji STAT zamiast findem wybierać, etc.

Thommee dzięki za naprowadzanie. Twoja metoda działa, ale nie we wszystkich przypadkach. Nie uwzglednia sytuacji, gdy np. filtruje posty, tj. gdy chce aby cgridview wyświetlił mi posty z działu samochody- czyli. ilość Twoich postów z działu samochody / ilosć wszystkich postów w bazie z działu samochody. Jak dostosować summaryText, aby "widział" filtrowanie? Bo przykład podany przez Ciebie poniżej zawsze wyswietla to samo, czyli ilość postów z bazy gdzie id wprowadzajacego = id zalogowanego (bez uwzglednienia filtrowania) / ilość wszystkich postów (bez uwzględnienia filtrowania).

Pozdrawiam

Aby przykład działał z filtrowaniem, możemy go delikatnie zmodyfikować.

Proponuję takie coś:

  • w modelu zmodyfikować metodę "search", aby przyjmowała dodatkowe kryteria.

  • do widoku przekazać model (zamiast obiektu CActiveDataProvider) i tam dokonywać wyszukiwań

Dzięki temu będziemy mogli wyszukiwać rekordy wg różnych kryteriów zawierające te same dane z filtrów:




// model Post: - dodanie obsługi dodatkowych kryteriów


    /**

     * @param array $externalCriteria kryteria 

     * @return CActiveDataProvider

     */

    public function search(array $externalCriteria = array()) // <= dodatkowe kryteria

    {

        $criteria=new CDbCriteria;

        $criteria->mergeWith($externalCriteria);  // <= merge kryteriów z filtrami


    // pozostała częśc kodu



Plik widoku: do niego przekazujemy cały model i uruchamiamy metodę "search"

w zależności od potrzeb - z odpowiednimi kryteriami. W naszym przypadku użyliśmy ‘condition’

by ograniczyć wyniki tylko do tych rekordów, które w kolumnie "userid" mają wartość "id" aktualnie

zalogowanego usera. Posłużyliśmy się także właściwością "totalItemCount" by wydobyć ilość tychże rekordów.




// Plik widoku

/** @var $model Post */


$this->widget('zii.widgets.grid.CGridView', array(

    'dataProvider'=>$model->search(),

    'summaryText' => $model->search(array(

        'condition' => 'userid = ' . Yii::app()->user->id))->totalItemCount

      . ' Twoich postów, {count} wszystkich postów, strona: {page}',

));

Thommee dzięki wielkie, już prawie wszystko działa :) z jedynym problemem:) Ja w dataProvider używaniem metody search z modelu, ale z uwzględnieniem zakresu przy wyszukiwaniu tj. w modelu mam zakres “owner”




public function scopes()

    {

        return array(

            'owner'=>array(

                'condition'=>"userid = ".Yii::app()->user->getId(),

            ),

}



więc mój cgridview wygląda tak:




$this->widget('zii.widgets.grid.CGridView', array(

    'dataProvider'=>$model->owner()->search(),

    'summaryText' => $model->search(array(

        'condition' => 'userid = ' . Yii::app()->user->id))->totalItemCount

      . ' Twoich postów, {count} wszystkich postów, strona: {page}',

));

i w tej sytuacji sumamryText zawsze wyświetla taką samą liczbę postów czyli zawsze ilosc Twoich postów = ilość wszystkich postów.

Mógłbyś mnie naprowadzić jeszcze w tej kwestii? Z góry dzięki

Pozdrawiam




$this->widget('zii.widgets.grid.CGridView', array(

    

    'summaryText' => $model->search(array(

        'condition' => 'userid = ' . Yii::app()->user->id))->totalItemCount

      . ' Twoich postów, '

      . $model->search()->totalItemCount . ' wszystkich postów, strona: {page}',

    'dataProvider'=>$model->owner()->search(),

));



Chyba chodzi Tobie o coś takiego.

…a skoro zawsze używasz owner’a to:




$this->widget('zii.widgets.grid.CGridView', array(

    

    'summaryText' => '{count} Twoich postów, '

      . $model->search()->totalItemCount . ' wszystkich postów, strona: {page}',

    'dataProvider'=>$model->owner()->search(),

));



Thommee, zauważyłem, że kod działa poprawnie pod warunkiem, że ‘dataProvider’=>$model->owner()->search(), znajduje się pod summaryText. Zaś gdy ‘dataProvider’=>$model->owner()->search(), znajduje się nad summaryText, to działanie jest błędne. Czy to normalne zachowanie? Czy kolejność wpisu ‘dataProvider’ w cgridview powinna mieć znaczenie ?

Tak, to normalne. Celowo przeniosłem fragment " ‘dataProvider’=>$model->owner()->search(), " niżej.

Zwróć uwagę na to, że $model zawsze wskazuje na ten sam obiekt (to samo miejsce w pamięci). Dlatego: gdy " ‘dataProvider’=>$model->owner()->search(), " uruchomisz jako pierwsze (wraz ze scopem “owner()”), to w kolejnych wywołaniach masz już ten scope zaaplikowany. Nawet gdy niżej robisz $model->search() to scope owner nadal jest aktywny, co powoduje niechciane zachowanie.

Thommee, masz u mnie browara:) Dzięki za pomoc. A tak przy okazji, mogę gdzieś w dokumentacji yii przeczytać o tym konkretnym zachowaniu? tj. kolejności wywołania obiektu $model w widoku, czy może to zachowanie niezależne od yii tylko specyfika php?

Jest to specyfika php. Pracujesz na tym samym obiekcie więc jeśli zrobisz w nim zmiany w 1. wywołaniu, to drugie będzie pracować na zmienionym obiekcie.

Thomee, mam jeszcze pytanko, w kodzie poniżej dodałem do metody search dodatkowe externalCriteria - jak mogę sprawdzić w widoku, czy metoda search jest wywołana z dodatkowymi externalCriteria, czy też externalCriteria jest puste?. Np chcę w widoku co innego wyswietlić gdy externalCriteria jest puste, i też co innego gdy externalCriteria zawiera jakieś elementy?




    /**

     * @param array $externalCriteria kryteria 

     * @return CActiveDataProvider

     */

    public function search(array $externalCriteria = array()) // <= dodatkowe kryteria

    {

        $criteria=new CDbCriteria;

        $criteria->mergeWith($externalCriteria);  // <= merge kryteriów z filtrami



Pozdrawiam i dziękuję.

Hmm…

Bez modyfikacji kodu się nie da.

Możesz np:

  • do widoku przekazać model, a w miejscu gdzie masz podać dataProvidera zrobić:

'dataProvider' => $model->search(/*Twoje kryteria*/)

różne w zależności od potrzeb

Możesz także:

  • w kontrolerze sprawdzać czy są externalCriteria i w zależności od tego czy są - do widoku przekazać $dataProvider1 lub $dataProvider2. W samym widoku sprawdzasz czy istnieje $dataProvider1 - jeśli tak to pokazujesz dane w pierwszy sposób, analegicznie dla $dataProvider2.