1

(14 odpowiedzi, napisanych Model-Widok-Kontroler)

robal77 napisał/a:

No właśnie.... to że  pomiędzy tabelami występują relacje, nie znaczy że musisz hardcodować wszelkie możliwe asocjacje w modelach. 90% asocacji powinno być zbindowanych w locie, zależnie od potrzeb, wtedy wszytsko jest ok.

A kto powiedział, że nie stosuje bindowania w locie?
Miałem sporo przypadków, kiedy klienci wymagali stworzenia raportu, dla którego poziom skomplikowania powodował że jego skuteczne przeniesienie na ORM'a było niemożliwe.
Do prostych rzeczy - nadaje się idealnie, przy bardziej zaawansowanych - wysiada. Można tworzyć widoki, ale przecież nie o to w tym wszystkim chodzi...

Poza tym ilość zapytań jakie generuje Cake przy nawet niewielkim rekursywnym zagłębieniu modeli jest zatrważająca.

Co do enum - jest ładne, ale wolne. Spytajcie się dowolnego bazodanowca co będzie szybciej działało, a każdy wam powie że atrybuty typu całkowitego najlepiej nadają się do tworzenia kluczy ( i ich indeksowania) .
Przy min. 100tys. unikalnych wejść na stronę w ciągu dnia, nawet takie wydawało by się niewielkie rzeczy naprawdę mają znacznie.

2

(6 odpowiedzi, napisanych Ogólne)

Jest przeładowanie, ale tam jest chyba redirect a nie ukrywanie wiadomości... Ale w sumie w JS łatwo napisać np. przy użyciu jQuery jakąś funkcję, która będzie ukrywała Ci wszystkie divy o podanej klasie (np message) po x sekundach - możesz sobie ją includować w layoucie i będzie robiła dokładnie to czego oczekujesz.

3

(12 odpowiedzi, napisanych Uwierzytelnianie i autoryzacja)

Chciałbyś wykorzystywać ACL'a do ustawiania dostępu do każdej wywoływanej metody w modelu ?? smile Listy kontroli dostępu wykorzystuje się na wyższym poziomie niż dostęp do bazy BD. Świetnie spisuje się przy określaniu dostępu do kontrolerów i ich akcji.

4

(6 odpowiedzi, napisanych Ogólne)

Takie rzeczy tylko w JavaScript smile

5

(12 odpowiedzi, napisanych Uwierzytelnianie i autoryzacja)

ACL to component -> wykorzystuje się go w controllerze i tam powinno odbywać się sprawdzanie praw;

6

(14 odpowiedzi, napisanych Model-Widok-Kontroler)

Wydaje mi się, że jednak lepszym rozwiązaniem jest wywoływanie metody modelu tabeli słownikowej. Przy pobieraniu danych poprzez  inny model wzrost obciążenia będzie praktycznie niezauważalny, poza tym spokojnie można takie rzeczy trzymać w cache'u i kłopot zniknie zupełnie. Natomiast plusem jest to, że struktura aplikacji pozostanie przejrzysta.
Osobiście query() używam bardzo rzadko, ale często wykorzystanie ORM'a przy bardziej skomplikowanych zapytaniach zabija aplikacje, a w ciężkich przypadkach ich konstruowanie jest praktycznie niemożliwe.

@juby - 73 linijki to niezbyt wiele, zwłaszcza że nie wszystkie są wykorzystywane smile Poza tym po to używa się cache'a, żeby te dodatkowe linijki wywoływać jak najrzadziej.

7

(4 odpowiedzi, napisanych Instalacja i konfiguracja)

Zgadzam się.
Update aplikacji do nowszej wersji jest w tedy o wiele wygodniejszy.
Poza tym czasami zdarza się, że trzeba pozmieniać pewne rzeczy w "bebechach" jednej aplikacji, co nie koniecznie może dobrze wyjść pozostałym.

8

(14 odpowiedzi, napisanych Model-Widok-Kontroler)

Albo $this->NazwaModelu->bindModel( array( parametry  ) ); i potem $this->NazwaModelu->NowyModel->metoda();
Albo bardziej przyjemne rozwiązanie - ClassRegistry::init('NowyModel')->metoda();

9

(4 odpowiedzi, napisanych Instalacja i konfiguracja)

Tak - da się wykorzystywać jeden katalog Cake jako Core dla wielu projektów i uaktualniać tylko jeden katalog dla wszystkich projektów.
Skorzystaj z shella cake'a przy tworzeniu nowego projektu - tam sobie to możesz wszystko ustawić.

10

(2 odpowiedzi, napisanych Ogólne)

Pliki *.po służą do lokalizacji interface'u. Kod HTML powinien znajdować się tylko i wyłącznie w warstwie VIEW.

11

(10 odpowiedzi, napisanych Ogólne)

Forum jest raczej martwe....

12

(8 odpowiedzi, napisanych Model-Widok-Kontroler)

duke_piotr napisał/a:

A to nie o to chodzilo w jego problemie? Napisal ze ma jednego left joina i brakuje mu tylko drugiego. W ten sposob robiac findAll pobierze wszystkie Regiony i pasujace do nich Miasta i pasujace do nich Firmy.

Wydaje mi się, że skoro jest w kontrolerze Corporation, to chce dla konkretnej korporacji pobrać dane na temat regionu i miasta. Zresztą nie o to się tutaj teraz rozchodzi, bo cokolwiek chce pobrać to i tak powinno to działać już w tej chwili (o ile wszystko jest rzeczywiście dobrze skonfigurowane).

duke_piotr napisał/a:

Jezeli zle zrozumialem problem to przepraszam smile Jezeli dobrze to wg. mnie brakuje szczegolowego opisu polaczenia baz miedzy Regionami i Firmami, jest jednokierunkowe, a model Miasta powinien laczyc ze soba obydwie tabele.

Jeżeli chce pobrać dla danej firmy jej miasto i region, to nie potrzebuje więcej asocjacji niż ma w tej chwili, a ich dodanie tylko spowoduje potrzebę usuwania asocjacji "w locie".


Jeśli natomiast jest tak jak pisze duke_piotr, to wszystko tu jest źle wink

13

(8 odpowiedzi, napisanych Model-Widok-Kontroler)

duke_piotr napisał/a:

Czesc,
Nie jestem za dobry w to ale nie powinno byc $hasMany ?

$hasMany byłoby potrzebne gdyby chciał pobrać dla regionów wszystkie miasta, a dla miast wszystkie korporacje. Tak jak jest teraz - jest ok.

Flo, zapomnij o $query(). Tutaj na pewno to nie będzie potrzebne.

Spróbuj, zrobić $this->Corporation->Town->Region->findAll(); Jeśli pobierze Ci wszystkie regiony, to wtedy będzie to już zastanawiające...
Jeśli nie, to spróbuj zdefiniować zmienne $belongsTo w pełni, tzn.


$belongsTo = array(
    'Town' =>array(
        'className'=>'Town',
        'foreignKey'=>'town_id'
    )
);

14

(8 odpowiedzi, napisanych Model-Widok-Kontroler)

Usuń z modelu $recursive = 2;

W kontrolerze tuż przed findAll() dodaj $this->recursive = 2;
Twoja funkcja findAll() powinna wyglądać tak : $this->Corporation->findAll(null,null, 'Corporation.name desc');

Ewentualnie możesz podać recursive również w findAll() : $this->Corporation->findAll(null,null, 'Corporation.name desc',null,null, 2);

Natomiast wg nowych standardów może to wyglądać jeszcze tak:
$this->Corporation->find('All', array('order'=>array('Corporation.name desc'), 'recursive'=>2));

15

(3 odpowiedzi, napisanych Ogólne)

Nie mam porównania, ale na pewno jest również warty polecenia.
Wielu znajomych sobie go chwali, głównie za szybkość działania. Jeśli chcesz je porównać to IBM wypuścił serię artykułów w których porównuje Cake'a, Symfony i chyba Zend.
http://www.ibm.com/developerworks/libra … index.html
Może pomogą Ci one wybrać narzędzie, które będzie Ci najbardziej odpowiadać.

16

(3 odpowiedzi, napisanych Ogólne)

Ja na początku również nie miałem dużego doświadczenia w PHP. Właściwie od razu zacząłem szukać dla siebie odpowiedniego frameworka i cieszę się, że trafiłem na Cake'a jeszcze w wersji 1.1.x. Miałem dobre porównanie własnej wydajności - tego co pisałem dla siebie w Cake i tego co robiłem w pracy na firmowym pseudo 'frameworku'. Na prawdę opłaca się zainwestować swój czas, aby go poznać - ostatecznie na pewno rachunek wyjdzie na plus.
W razie problemów ze startem - pisz na forum albo na priv.
Pozdrawiam!

Witaj vegetassj.
Po pierwsze, nie widzę przyczyny dla której miałbyś blokować dostęp do tej akcji spoza requestAction(). Możesz ją sobie nazwać w dowolny sposób, tak że nikt normalny nie odgadnie jej nazwy, ale tak naprawdę dalej nie widzę powodu aby to robić.

Jeżeli chodzi o pobieranie menu, requestAction - jak najbardziej, ale najlepiej by był on  wywoływany w elemencie. Dlaczego? Ponieważ można go łatwo cache'ować smile
Np. w layoucie tam gdzie chcesz wstawić menu : echo $this->element('nazwa_elementu', array('cache'=>'1 day'); , a w tym elemencie możesz mieć coś jak: echo $this->requestAction('/controllerJakis/akcja', array('return')); - nie pamiętam teraz kodu składni dokładnie, ale coś w tym stylu powinno działać (popatrz do API).
Pamiętaj, że każdorazowe wywołanie requestAction to tak jakbyś wywołał nowego cake'a. Biorąc pod uwagę, że menu jest praktycznie na każdej stronie dużo lepiej jest takie informacje cache'ować.

Pozdrawiam.

Rozmawiałem z _psychic_'iem i zgodził się on na utworzenie polskiej wersji serwisu, która od teraz znajduje się pod adresem: http://book.cakephp.org/pl/view/3/the-manual . Poszukiwani są ochotnicy chętni do tłumaczenia dokumentacji na język polski! Aby dodawać własne tłumaczenia/komentarze wystarczy mieć konto w serwisie Bakery.

Pod adresem http://book.cakephp.org  powstała nowa aplikacja służąca do budowania dokumentacji dla cake'a. Dzięki temu każdy użytkownik będzie miał prawo zasugerować jakiś nowy dział dokumentacji, lub nawet dodać swój artykuł/tłumaczenie. Póki co nie ma wersji polskojęzycznej. Jeśli ktoś natknie się na IRCu (freenode - #cakephp) na Johna Davida Andersona (_psychic_), to warto mu zasugerować taką potrzebę.

20

(4 odpowiedzi, napisanych Model-Widok-Kontroler)

Komponent :

<?php

class tabMenuComponent extends Object
{

    var $controller = true;

    var $user_model = 'User';
    var $group_model = 'Group';
    var $menu_model = 'Menu';
    var $melement_model = 'Melement';
    var $msubelemen_model = 'Msubelement';
    var $components = array('Session');

 
    function startup(&$controller)
    {
        $this->controller = $controller;
    }
    
    function init($group_id){

        $menu = $this->controller->{$this->user_model}->{$this->group_model}->{$this->menu_model}->findAll(array('Menu.group_id'=>$group_id),null,null,null,null,2);
        $this->Session->write('full_menu', $menu[0]);
    }
    
    function getMenu(){
        return $this->Session->read('full_menu');
    }
}

?>

Helper:

<?php
class tabMenuHelper extends Helper{

    var $helpers = array('Html');
    var $li_class_main = "activated";
    var $li_class_sub = "activated_sub";
    
    var $main_menu_container = 'tnavmenu';
    var $sub_menu_container = 'tnavsubmenu';


    function showMenu($menu, $sub = true){
    
        $submenu = '';
        $result = "<div id=\"" . $this->main_menu_container  . "\"><ul>\n";
        
        foreach ($menu['Melement'] as $melement){
             $result.=$this->getMenuElement($melement, $submenu, $sub);
        }
        $result .= "</ul></div>\n";
        
        if ($sub)
            $result .= "<div id=\"". $this->sub_menu_container ."\"><ul>" . $submenu . "</ul></div>\n";
        
        return $result;
    }
    
    function getSubmenuElement($submenu){
        
        $result = '';
                
        foreach ($submenu as $subelement){
            
            if($this->getActionNameCurrentPath() == $this->getActionNameLinkPath($subelement['link'])){
                $result .= '<li class="'.$this->li_class_sub .'">';
                
            }else{
                $result .= '<li>';
            }

            if ($subelement['img'] != ''){
                $obj = $this->Html->image($subelement['img']) . '<br/>' . $subelement['name'];
            }else{
                $obj = $subelement['name'];
            }            

            $result .= $this->Html->link($obj ,$subelement['link'],array('title'=>trim($subelement['name'])),false,false). "</li>\n"; 
        }
        
        return $result;
    
    }

    function getMenuElement($melement, &$submenu, $sub){

        $result = '';
                
            if($this->getControllerNameCurrentPath() == $this->getControllerNameLinkPath($melement['link'])){
                $result .= '<li class="'.$this->li_class_main .'">';
                if ($sub){
                    $submenu =$this->getSubmenuElement($melement['Msubelement']);
                }
                
            }else{
                $result .= '<li>';
            }

            if ($melement['img'] != ''){
                $obj = $this->Html->image($melement['img']) . '<br/>' . $melement['name'];
            }else{
                $obj = $melement['name'];
            }
            
            $result .= $this->Html->link($obj ,$melement['link'],array('title'=>trim($melement['name'])),false,false). "</li>\n"; 
        
        return $result;
    }

    
    function getControllerNameCurrentPath(){
        return $this->params['controller'];
    }
    
    function getControllerNameLinkPath($link){
        $tmp = explode('/',$link);
        return $tmp[1];
    }
    
    function getActionNameCurrentPath(){
        return $this->param['action'];
    }
    
    function getActionNameLinkPath($link){
        $tmp = explode('/',$link);
        return !empty($tmp[2]) ? $tmp[2] : 'index';
    }        
}
?>

Kod sql dla Postgres'a

CREATE TABLE menus
(
  id serial NOT NULL,
  group_id integer,
  CONSTRAINT pk_menus PRIMARY KEY (id),
)


CREATE TABLE melements
(
  id serial NOT NULL,
  menu_id integer NOT NULL,
  name character varying(50),
  link character varying(255),
  img character varying(255),
  CONSTRAINT pk_column_id PRIMARY KEY (id),
) 


CREATE TABLE msubelements
(
  id serial NOT NULL,
  melement_id integer,
  name character varying(50),
  link character varying(255),
  img character varying,
  CONSTRAINT pk_msubelement_id PRIMARY KEY (id)
)

Dla stworzony tabel tworzymy modele a w nich dwie asocjacje:
* menu hasMany melement
* melement hasMany msubelement.

Dodajemy helper i komponent do kontrolera:

var $helpers = array('tabMenu');
var $components = array('tabMenu')

Po udanej akcji logowania, pobieramy id grupy użytkownika i odpalamy akcje komponentu.

$group_id = $this->User->field('group_id',array('username'=>$this->data['User']['username']));    
$this->tabMenu->init($group_id);

Potem w layoucie, lub gdziekolwiek w widoku uruchamiamy:

echo $tabMenu->showMenu($this->controller->tabMenu->getMenu(), false);

Ostatni parametr ustawiony jako false powoduje że nie pobierane będą elementy submenu.

21

(4 odpowiedzi, napisanych Model-Widok-Kontroler)

Witam.
Nie znam odpowiedzi na Twoje pytanie, ponieważ nie spotkałem się dotąd w żadnym komponencie z pobieraniem nazwy kontrolera w którym był wywoływany, może bardziej zaawansowani użytkownicy znają taki sposób.
Ja natomiast mogę natomiast podzielić się z Tobą, jak ja wyświetlam menu.

Napisałem sobie komponent, który przy logowaniu pobiera menu dla danej grupy użytkowników.
Do tego komponentu dołożyłem jeszcze helper, który wykorzystuję do wyświetlania elementów menu i jeśli istnieje - submenu. Można również dodawać grafiki dla elementów, a po przejściu do danej strony z menu, jego odpowiednia pozycja jest oznaczana.

Jeśli byłbyś zainteresowany kodem źródłowym, to daj znać.
Pozdrawiam.

22

(0 odpowiedzi, napisanych Ogólne)

Witam.
Troszkę tu wieje pustkami, ale mam nadzieję, że będzie lepiej.

Mam problem z transakcjami dla bazy postgresql.
Przy wykonywaniu $this->begin(); cake rozpoczyna transakcje. Problemem jest jednak to, co zwraca mi wywoływana funkcja.
Zamiast wartości bool'owskiej, zwracane jest takie dziwo (wynik var_dump) "array(0) { }"
Jeśli ktoś ma jakiś pomysł jak to ugryźć, to proszę o podpowiedź.