1

Temat: Tworzenie widoków

witam,

dopiero zaczynam zabawę z cakephp. mam utworzony model

class Product extends AppModel {
    var $name = "Product";
    var $hasOne = array(
                    "ProductsDescription"=>array("className"=>"ProductsDescription",
                                                "foreignKey"=>"products_id",
                                                "conditions"=>null,
                                                "fields"=>null)
                    );

oczywiscie generuje dobre zapytanie do MySQL, ale mam problem z edycja danych.

moja akcja edytujaca wyglada tak
(plik products_controller.php)

function edit($id = null) {

    $this->Product->id = $id;
    if (empty($this->data)) {
        $this->data = $this->Product->read();
    } else {
        if ($this->Product->save($this->data)) {
            $this->flash('Your product has been updated.','/products');
        }
        }
    }

natomiast widok

<h1>Edit Post</h1>
<?php
    echo $form->create('Product', array('action' => 'edit'));
    echo $form->input('products_name');
        echo $form->input('url');
    echo $form->input('products_description.products_description', array('rows' => '3'));
        echo $form->input('products_id', array('type'=>'hidden')); 
    echo $form->end('Save Post');
?>

wchodzac w Edycje tylko pole URL jest wypelnione i tylko pole url sie zapisuje do bazy.
Prosze o pomoc dla poczatkujacego.

Z gory dziekuje.

Pozdr.

2

Odp: Tworzenie widoków

W widoku, w metodzie $form->input(); musisz używać takich nazw, jakie są w tabeli products w bazie danych. Prawdopodobnie masz tam pole o nazwie 'name' i pole o nazwie 'description', wiec formularz powinien być zbliżony do:

<h1>Edit Post</h1>
<?php
    echo $form->create('Product', array('action' => 'edit'));
    echo $form->input('name');
        echo $form->input('url');
    echo $form->input('description', array('rows' => '3'));
        echo $form->input('id', array('type'=>'hidden')); 
    echo $form->end('Save Post');
?>

Ostatnio edytowany przez darek_dobron (2009-01-13 13:41:35)

3

Odp: Tworzenie widoków

mam dwie tabele.

CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL auto_increment,
  `url` varchar(255) NOT NULL,
  `symbol` varchar(255) NOT NULL,
  `status` int(11) NOT NULL default '1',
  PRIMARY KEY  (`id`)
)

oraz

CREATE TABLE IF NOT EXISTS `products_descriptions` (
  `id` int(11) NOT NULL auto_increment,
  `products_id` int(11) NOT NULL,
  `products_name` text NOT NULL,
  `products_description` text NOT NULL,
  `products_lang` varchar(10) NOT NULL,
  PRIMARY KEY  (`id`)
)

tabele sa polaczone.

Darek, dzieki za zainteresowanie tematem

4

Odp: Tworzenie widoków

[OFFTOP]
Ja w takich przypadkach odpalam w core.php debug=2 i w jakims queryBrowser kopiuje zapytanie jakie wysyla Cake i ogladam co jest nie tak.
[/OFFTOP]

5

Odp: Tworzenie widoków

mam oczywiscie debug caly czas wlaczony.
na stronie edycyjnej cake generuje mi zapytanie

SELECT `Product`.`id`, `Product`.`url`, `Product`.`symbol`, `Product`.`status`, `ProductsDescription`.`id`, `ProductsDescription`.`products_id`, `ProductsDescription`.`products_name`, `ProductsDescription`.`products_description`, `ProductsDescription`.`products_lang` FROM `products` AS `Product` LEFT JOIN `products_descriptions` AS `ProductsDescription` ON (`ProductsDescription`.`products_id` = `Product`.`id`) WHERE `Product`.`id` = 1 LIMIT 1

czyli wszystko to co potrzeba zeby edytowac wpis, a nawet wiecej :-)

pytanie tylko dlaczego nie wrzuca w inputy aktualnych wartosci z bazy i nie zapisuje.
generalnie to wyglada tak jakby w ogole nie korzystal z tabeli products_descriptions, ale tylko i wylacznie z tabeli products

wrzucilem sobie w plik edit.ctp formulke <?php print_r($this->data); ?> czyli to co dostaje.
efekt:

Array
(
    [Product] => Array
        (
            [id] => 1
            [url]=> khhjkh
            [symbol] => jhjh
            [status] => 1
        )

    [ProductsDescription] => Array
        (
            [id] => 1
            [products_id] => 1
            [products_name] => nazwa
            [products_description] => opis
            [products_lang] => pl
        )

)

wiec moim zdaniem cos jest walniete przy zapisie formularza - cos trzeba zmienic w pliku edit.ctp

6

Odp: Tworzenie widoków

A może :

echo $form->input('ProductsDescription.products_description', array('rows' => '3'));

Niestety nie mam możliwości sprawdzenia.

BTW. Tak z ciekawości - po co rozbicie na Product i ProductsDescription skoro są połączone relacją 1 do 1? Gdybyś wszystkie pola z ProductsDescription umieścił w Products problem sam by się rozwiązał.

7

Odp: Tworzenie widoków

A czemu nie uzywasz wartosci value do wypelnienia formularza?

<?=     $form->input('Article.id',    array(
                        type'        => 'hidden',
                        value'        => $this->data['Article']['id']
                        ));   ?>

ja robie cos takiego i wszystko jest ok hmm

Ostatnio edytowany przez duke_piotr (2009-01-13 15:33:10)

8

Odp: Tworzenie widoków

Darek - drugi dzien bawie sie z Cake. w innej relacji to juz mi nic nie dzialalo.
p.s. Twoj sposob zadzialal.
Rozbilem na dwie tabele bo beda 3 wersje jezykowe, dlatego opis i nazwa produktu sa w innej tabeli.

...ale teraz mam inny problem - nie umiem tego zapisac do bazy.
kod z kontrollera

function edit($id = null) {

    $this->Product->id = $id;
    if (empty($this->data)) {
        $this->data = $this->Product->read();
    } else {
        if ($this->Product->save($this->data)) {
            $this->flash('Your product has been updated.','/products');
        }
        }
    }

save robi mi update tylko jednej tabeli - products
saveall nie robi mi update tylko wstawia nowe wiersze do obu tabel.
updateall - wywala mi blad

generalnie metoda prob i bledow proboje http://book.cakephp.org/view/75/Saving-Your-Data

pozdr.

9

Odp: Tworzenie widoków

gaw napisał/a:

wrzucilem sobie w plik edit.ctp formulke <?php print_r($this->data); ?> czyli to co dostaje.
efekt:

Array
(
    [Product] => Array
        (
            [id] => 1
            [url]=> khhjkh
            [symbol] => jhjh
            [status] => 1
        )

    [ProductsDescription] => Array
        (
            [id] => 1
            [products_id] => 1
            [products_name] => nazwa
            [products_description] => opis
            [products_lang] => pl
        )

)

do takiego updata twoja tabela powinna wygladac tak:

Array
(
    [Product] => Array
        (
            [id] => 1
            [url]=> khhjkh
            [symbol] => jhjh
            [status] => 1
        )

    [ProductsDescription] => Array
        (
           [0] => Array (
              [id] => 1
              [products_id] => 1
              [products_name] => nazwa
              [products_description] => opis
              [products_lang] => pl
            )
        )

)

A zaleznosc z opisem na moje oko to hasmany a polecenie to saveAll hmm

Ostatnio edytowany przez duke_piotr (2009-01-13 17:28:32)

10

Odp: Tworzenie widoków

ok, dziekuje wszystkim zainteresowanym za pomoc.
Drugi dzień z CakePHP zakończony sukces i problemy rozwiązane!
Jeśli chodzi o wstawianie inputów skorzystałem z rady duke_piotr - dzięki temu mam większą kontrolę.
Zapisuje dane przez saveAll - jak sie okazało muszę wstawiać 2x pole ukryte z numerami ID rekordów które chce zmieniać - tzn. jedno pole z jednej tabeli i jedno z drugiej. Głupi błąd, a kilka godzin szukałem rozwiązania.

Po dwóch dniach nauki jestem zaskoczony możliwościami tego frameworka(to mój 1. framework). Kilka linijek kodu załatwia za mnie większą część pracy.

Dobrze by było w przyszłości rozwinąć to forum, bo brakuje polskiego źródła informacji.

pozdr.

11

Odp: Tworzenie widoków

Forum zaczyna żyć smile Ostatnio zrobiło się bardzo ruchliwie.

W wolnej chwili postaram się napisać jakiś kawałek tutoriala dla początkujących. Dobrze by też było żeby uaktualnić główną stronę, bo już od dawna jest dostępna stabilna wersja 1.2, a ostatni post jest z 1 stycznia 2008 hmm

Co do możliwości Cake'a - są ogromne. W wypadku większości projektów wersję beta można "wypiec" w przeciągu dnia smile

12

Odp: Tworzenie widoków

Darek, mam jeszcze pytanie - pewnie banalne.
Mogę tworzyć kontrolery, modele, widoki dla poszczególnych podstron - w tym wypadku przedstawiałem products, ale jak mam zrobic strone główną?
widok to na pewno w app/views/pages/home.ctp, ale skad on ma wziac dane?
Pytanie na pewno oczywiste i banalne. Czy home.ctp korzysta z głównego kontrollera. Bo robiąc inne kontrolery dziedzicze po nim...
hmmm sam nie wiem.

13

Odp: Tworzenie widoków

Twoją stroną główną może być dowolna podstrona.

Zerknij w app/config/routes.php - będzie tam cośprzypominającego:

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

Oznacza to, że cały ruch trafiający na stronę główną jest przekierowany na kontroler 'pages' i akcję 'display'  z parametrem 'home'.

Jeśli chciałbyś mień na stronie głównej powiedzmy listę produktów, to w/w linia miałaby pewnie postać:

Router::connect('/', array('controller' => 'products', 'action' => 'index'));

Oczywiście można tworzyć wiele takich przekierowań.

np.

Router::connect('/', array('controller' => 'products', 'action' => 'index'));
Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));
Router::connect('/produkt/*', array('controller' => 'products', 'action' => 'view'));

Wszystko jasne?

14

Odp: Tworzenie widoków

ale bajer!!!!!! :-)
działa to świetnie
Darek, a masz moze jakis szybki tutek jak robic linki w postaci www.adres.pl/url-z-bazy

probowalem, tak
Router::connect('/*', array('controller' => 'products', 'action' => 'view'));

ale to oczywiscie nie dziala.

Z gory dzieki.

pozdr.

15

Odp: Tworzenie widoków

Rozumiem że chodzi Ci o użycie "google friendly url's". Jeśli tak, to rozwiązanie mam, ale nie przytoczę z pamięci całości. Jutro będę miał dostęp do mojego drugiego komputera i wrzucę Ci gotowe rozwiązanie. Jeśli nie o to chodzi, to powiedz jaki efekt dokładnie chcesz osiągnąć.

16

Odp: Tworzenie widoków

tak, chodziło o przyjazne linki.

Z góry dziękuje.

pozdr.

17

Odp: Tworzenie widoków

Ciekawe ci Ci odpisze:) Ja robie baze newsow z kluczem glownym tworzonym przez PHP. Cos na ksztalt strrtolower(str_replace())..
czyli w wolnym tlumaczeniu wszystko male i pozamieniaj znaki spacji i inne na jakies inne np '_' czy '.'. Nie jest to piekne rozwiazanie gdyz art powinien sie tworzyc w bazie na moje oko jako autoincrement no ale coz ;]

18

Odp: Tworzenie widoków

Co do przyjaznych linków:

kod w routes.php:

Router::connect('/', array('controller' => 'pages', 'action' => 'index'));
Router::connect('/*', array('controller' => 'pages', 'action' => 'page'));

W pages_controller.php

<?php
class PagesController extends AppController {

    var $name = 'Pages';
    var $helpers = array('Html', 'Form','Javascript','Session','Ajax');
    var $uses = array('Config','Page','MenuElement','News');
    var $components = array('Conf');

    function beforeFilter(){
        $menu_elements=$this->MenuElement->findAllThreaded(array('MenuElement.menu_type'=>'main_menu'),array('MenuElement.id','MenuElement.name','MenuElement.page_id','MenuElement.external_link','MenuElement.parent_id','MenuElement.binded_element','MenuElement.menu_type','Page.slug'),'MenuElement.order_no');
        $this->set('menu_elements',$menu_elements);
        $this->Page->recursive=-1;
        $footer_links=$this->Page->find(array('slug'=>'linki_do_stopki'),array('Page.slug','Page.content'));
        $this->set('footer_links',$footer_links['Page']['content']);
    }

    function index() {
        $this->layout="mainpage";
        $page=$this->Page->find(array('slug'=>'strona_glowna'));
        $this->set('page',$page);
        $this->set('page_title',$page['Page']['title']);
        $this->set('page_desc',$page['Page']['meta_desc']);
        $this->set('page_key',$page['Page']['meta_key']);
        $news=$this->News->findAll(array('News.published'=>1,'News.page_id'=>0),null,'News.add_date DESC',6);
        $this->set('news',$news);
    }
    
    function page($slug=null) {
        if($slug!=null){
            if($slug=='strona_glowna'){
                $this->redirect('/');
            }
            $this->Page->recursive=-1;
            $page=$this->Page->find(array('slug'=>$slug));
            $page_menu=$this->MenuElement->findAll(array('MenuElement.menu_type'=>'page_menu','MenuElement.parent_id'=>$page['Page']['id']),array('MenuElement.id','MenuElement.name','MenuElement.page_id','MenuElement.external_link','MenuElement.parent_id','MenuElement.binded_element','MenuElement.menu_type','Page.slug'),'MenuElement.order_no');
            $this->set('page_menu',$page_menu);
            $page_news=$this->News->findAll(array('News.page_id'=>$page['Page']['id'],'News.published'=>1),null,'News.add_date  DESC');
            $this->set('page_news',$page_news);
            $this->set('page_title',$page['Page']['title']);
            $this->set('page_desc',$page['Page']['meta_desc']);
            $this->set('page_key',$page['Page']['meta_key']);
            $this->set('page',$page);
        }else{
            $this->redirect('/');
        }
    }

}
?>

W widoku strony tworzysz linki używając:

<?php echo $html->link('Nazwa linka','/url'); ?>

Wrzuciłem cały kod kontrolera, łącznie z funkcją wyciągająca menu dla każdej strony. Coś wyjaśnić?

19

Odp: Tworzenie widoków

skoro ten twoj $slug ma byc unikalny to chyba nie potrzeba juz id. Wystarczy ze slug bedzie kluczem glownym. No chyba ze nie skapowalem kodu big_smile

20

Odp: Tworzenie widoków

Unikalność slug'a to jedno, a index oparty na liczbie to drugie smile. Poza tym , jeśli kiedyś będziesz musiał zmienić powiązania, dużo łatwiej odwołać się do numeru niż do stringa. Np. zmienia ci się slug jakiejś strony, i co wtedy? Jeśli slug jest kluczem, to musisz zmienić każdy link prowadzący do tej strony, a jeśli używasz sluga, tylko jako 'aliasu' to masz dużo mniej roboty smile

21

Odp: Tworzenie widoków

hi,

mam jeszcze pytanie zwiazane z linkami - tworze linki na podstawie tytulu/nazwy produktu. Beda 3 wersje jezykowe wiec pomyslalem ze dobrze by bylo dac url tez w 3 wersjach. co myslicie? przerzucilbym pole url z tabeli products do products_descriptions.

pozdr.

22

Odp: Tworzenie widoków

Z drugiej strony powstaja problemy z unikalnoscia adresu i zeby tego unikac robi sie oszukane tagi jak:

pudelek.pl/news/1/doda_robi_loda

no bo kto ci zagwarantuje ze nie zrobi go kilka razy i trzeba sie bedzie bawic w sprawdzanie adresu.

W powyzszym przypadku nic sie nikomu nie pomyli ale nie jest to juz friendly tag hmm

23

Odp: Tworzenie widoków

duke_piotr - Twoja odpowiedz jest do mojego pytania? juz mam funkcje do sprawdzania unikalnosci urla.

pozdr.

24

Odp: Tworzenie widoków

duke_piotr napisał/a:

Z drugiej strony powstaja problemy z unikalnoscia adresu i zeby tego unikac robi sie oszukane tagi jak:

pudelek.pl/news/1/doda_robi_loda

no bo kto ci zagwarantuje ze nie zrobi go kilka razy i trzeba sie bedzie bawic w sprawdzanie adresu.

W powyzszym przypadku nic sie nikomu nie pomyli ale nie jest to juz friendly tag hmm

Może taki adres nie wygląda najlepiej, ale dla google'a nadal jest friendly smile

Sprawdzanie unikalności sluga to drobnostka:

$this->data['Page']['slug']=$this->generateSlug($this->data['Page']['slug']);
$exists=$this->Page->findCount(array('Page.slug'=>$this->data['Page']['slug']));
if($exists>0)$this->Page->invalidate('slug_exists');

Wykorzystana funkcja generateSlug to

function generateSlug($string) {
          $low=array(
            'ś' => 's',
            'ż' => 'z',
            'ź' => 'z',
            'ó' => 'o',
            'ą' => 'a',
            'ę' => 'e',
            'ł' => 'l',
            'ć' => 'c',
            'ń' => 'n',
            'Ś' => 's',
            'Ż' => 'z',
            'Ź' => 'z',
            'Ó' => 'o',
            'Ą' => 'a',
            'Ę' => 'e',
            'Ł' => 'l',
            'Ć' => 'c',
            'Ń' => 'n'
          );
          $string = strtolower(strtr($string,$low));

          $settings = array('separator' => '_', 'overwrite' => true,'length' => 50);

          $string = preg_replace('/[^a-z0-9_]/i', $settings['separator'], $string);
          $string = preg_replace('/\\' . $settings['separator'] . '[\\' . $settings['separator'] . ']*/', $settings['separator'], $string);

          if (strlen($string) > $settings['length']) {
              $string = substr($string, 0, $settings['length']);
          }

          $string = preg_replace('/\\' . $settings['separator'] . '$/', '', $string);
          $string = preg_replace('/^\\' . $settings['separator'] . '/', '', $string);
          return $string;
    }

25

Odp: Tworzenie widoków

Mały oftopic, ale może kiedyś  komuś się przyda.

gaw napisał/a:
<h1>Edit Post</h1>
<?php
    echo $form->create('Product', array('action' => 'edit'));
    echo $form->input('products_name');
        echo $form->input('url');
    echo $form->input('products_description.products_description', array('rows' => '3'));
        echo $form->input('products_id', array('type'=>'hidden')); 
    echo $form->end('Save Post');
?>

Nie powinno się uzywać "action" => "edit" dla formularzy tylko "url" => "edit"
czyli powinno to być tak  :

    e(form->create("Product", array("url" => "edit")));

W 90% przypadków zadziała "action" natomiast przy custom routingach zaczynaja się problemy (np gdy wyniki paginacje są filtrowane jakimś formularzem) , mam na myśli routingi takie jak :

    Router::connect('/user/:controller/:action/*', array('prefix' => 'user'));
    Router::connect('/player/:controller/:action/*', array('prefix' => 'player'));

czyli takie które pozwalają użyć np takich urli :
/user/games/index - dla akcji user_index ctrl GamesController
/player/games/index -  dla akcji player_index ctrl GamesController