Quickstart – potíže v počátcích

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

ahoj,
jsem u Nette teprve krátce a zkouším si dělat Quickstart.

Sekl jsem se ale a některé věci mi nejsou vůbec jasné.

V TaskPresenter se volá funkce find(), která není nikde definovaná. Při vytvoření menu a kliknutí na odkaz www/task/default/2 mi Laděnka háže chybu
Call to undefined method Todo\ListRepository::find()

<?php
    public function actionDefault($id){
        // TaskPresenter má za úkol zobrazit jeden konkrétní sezman úkolů
        // Identifikace se předá v adrese
        $this->list = $this->listRepository->find($id);
    }
?>

A dále mám problém s výpisem z databáze. Při výpisu úkolů mi hlásí chybu u řádku $task->list->title .
Cannot read an undeclared column „list“.

<?php
	        {foreach $tasks as $task}
                <tr>
                    <td>{$task->created|date:'j. n. Y'}</td>
                    <td>{$task->list->title}</td>
                    <td><b>{$task->text}</b></td>
                    <td>{$task->user->name}</td>
                </tr>
               {/foreach}
?>

Když ho odstraním, tak řádek $task->user->name zobrazí.
Při kontrole dotazů však lze vidět, že byl podát dotaz SELECT „id“, „title“ FROM „list“ ORDER BY „title“ ASC, takže moc dobře nechápu, v čem může být problém. Cizí klíče u tabulky task natavené mám.

Používám:
PHP 5.3.8 | Server Apache/2.2.21 (Win32) PHP/5.3.8 | Nette Framework 2.0.8
Postgresql 9.1

Jsem tady poprvé, tak nevím, jak moc detailně mám vše popisovat. předpokládám však, že Quickstart bude často diskutované téma.

Díky za jakoukoli pomoc!

Editoval Dismember (26. 2. 2013 23:01)

enumag
Člen | 2118
+
0
-

Všechna repository si musíš napsat sám, pro začátek bych ti doporučil CD collection, kde nějaké základní repository je k dispozici.

S tím undeclared column list si nejsem jistý, těch důvodů může být víc… Kdyžtak prosím strukturu těch dvou tabulek.

Dismember
Člen | 50
+
0
-

Díky za reakci!

S těmi repository návod pro začátečníka nepočítá? :-)

Hodil jsem cely můj quickstart do archivu na google drive a přiložil k tomu strukturu tabulek.

Pokud se mi na to někdo podívá, tak budu moc rád.

Přijímám facky za blbé chyby :-D

Re4DeR
Člen | 71
+
0
-

https://doc.nette.org/cs/quickstart vsak tady máš o repository

aby ti fungovalo to find tak pridej do ListRepository (nebo do hlavniho pokud od nej dedis) neco takoveho

public function find($by){
    return $this->getTable()->get($by);
}
Šaman
Člen | 2666
+
0
-

Podívám se na to – QS musí být kompletní a nenechávat nic na dodělání, protože kdo jede podle QS, ten ještě netuší, co je jeho chyba, co je speciálka Nette a co si prostě má dopsat.
Kdyžtak si zatím můžeš stáhnou z QS zdrojáky, tam abstraktní repository s touto funkcí určitě je (zdrojáky jsou funkční, až na hesla). Ale v textu by o tom mohla být zmínka.

Dismember
Člen | 50
+
0
-

nějakým způsobem jsem pokročil, ale menu jsem stále nerozjel.

V menu mam odkaz vytvořen správně: /quickstart-elias/www/task/default/1

Laděnka mi ale vyhodí vyjímku:
PDOException
No reference found for $list->

Mé zdrojáky:

<?php
class TaskPresenter extends BasePresenter {

    private $listRepository;

    /** @var Todo\TaskRepository */
    private $taskRepository;

    /** @var Todo\UserRepository */
    private $userRepository;

    /** @var Nette\Database\Table\ActiveRow */
    private $list;

    /**
     * V configu máme třídu Todo\ListRepository zaregistrovanou jako službu
     * se jménem listRepository, takže se bude volat pomocí
     *  $this->context->listRepository.
     */
    protected function startup() {
        parent::startup();
        // spojení s modelem listRepository
        $this->listRepository = $this->context->listRepository;
    }

    public function actionDefault($id) {
        // TaskPresenter má za úkol zobrazit jeden konkrétní sezman úkolů
        // Identifikace se předá v adrese
        $this->list = $this->listRepository->findBy(array('id' => $id))->fetch();
    }

    public function renderDefault() {
        $this->template->list = $this->list;
        $this->template->tasks = $this->listRepository->tasksOf($this->list);
    }

}
?>
<?php
class ListRepository extends Repository {

    /**
     * Ve třídě Todo\ListRepository si vytvoříme metodu, která nám z
     * objektu ActiveRow, obsahujícího řádek z tabulky list, vrátí
     *  všechny související úkoly.
     */
    public function tasksOf(Nette\Database\Table\ActiveRow $list) {
        return $list->related('task')->order('created');
    }
}
?>

Databáze:

<?php
CREATE TABLE list
(
  id integer NOT NULL DEFAULT nextval('list_id'::regclass),
  title character varying(50),
  CONSTRAINT pk_tlid PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE list
  OWNER TO postgres;

?>
<?php
CREATE TABLE task
(
  id integer NOT NULL,
  text character varying(200),
  done boolean,
  user_id integer,
  list_id integer,
  created date,
  CONSTRAINT pk_tid PRIMARY KEY (id),
  CONSTRAINT task_list_id_fkey FOREIGN KEY (list_id)
      REFERENCES list (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT task_user_id_fkey FOREIGN KEY (user_id)
      REFERENCES "user" (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);
ALTER TABLE task
  OWNER TO postgres;
?>
<?php
CREATE TABLE "user"
(
  id integer NOT NULL DEFAULT nextval('user_id'::regclass),
  username character varying(50),
  password character varying(50),
  name character varying,
  role character varying(20),
  CONSTRAINT pk_userid PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE "user"
  OWNER TO postgres;

?>
Dismember
Člen | 50
+
0
-

Tak jo, vyřešeno. Nainstaloval jsem si databázi MySQL, vytvořil tabulky a už to valí :-)

Takže chyba byla na mé straně a to v mých tabulkách v PostgreSQL…

Dismember
Člen | 50
+
0
-

Nedaří se mi dokončit část s výpisem úkolů uživatele

Laděnka hází chybu: Argument 1 passed to Todo\TaskListControl::__construct() must be an instance of Nette\Database\Table\Selection, null given, called in C:\www\app\Apache\htdocs\quickstart-elias\app\presenters\HomepagePresenter.php on line 42 and defined

zdrojáky se shodují s návodem:

HomepagePresenter:

<?php
    public function createComponentUserTasks() {
        $incomplete = $this->taskRepository->findIncompleteByUser($this->getUser()->getId());
        $control = new Todo\TaskListControl($incomplete, $this->taskRepository);
        $control->displayList = TRUE;
        $control->displayUser = FALSE;
        return $control;
    }
?>

Tasklist.php:

<?php
<?php

namespace Todo;

use Nette;

class TaskListControl extends Nette\Application\UI\Control {

    /** @var \Nette\Database\Table\Selection */
    private $selected;

    /** @var TaskRepository */
    private $taskRepository;

    /** @var boolean */
    public $displayUser = TRUE;

    /** @var boolean */
    public $displayList = FALSE;

    public function __construct(Nette\Database\Table\Selection $selected, TaskRepository $taskRepository) {
        parent::__construct(); // vždy je potřeba volat rodičovský konstruktor
        $this->selected = $selected;
        $this->taskRepository = $taskRepository;
    }

    public function render() {
        $this->template->setFile(__DIR__ . '/TaskList.latte');
        $this->template->tasks = $this->selected;
        $this->template->displayUser = $this->displayUser;
        $this->template->displayList = $this->displayList;
        $this->template->render();
    }

    public function handleMarkDone($taskId) {
        $this->taskRepository->markDone($taskId);
        $this->presenter->redirect('this');
    }

    public function handleDelete($id) {
        $this->taskRepository->delete($id);
        $this->flashMessage('Nic', 'success');
        $this->redirect('this');
    }

}
?>

Chybovou hlášku chápu tak, že se do konstruktu nepředal argument, ačkoli by se předat měl:

<?php
$control = new Todo\TaskListControl($incomplete, $this->taskRepository);
?>

Kde může být chyba?

Tak jsem tuto věc zkusil vyřešit jinak. Vytvořil jsem si stránku, kde vypsal seznam uživatelů a kliknutím na jméno se předalo ID a měl by se zobrazit seznam úkolů pro daného uživatele.

UserPresenter:

<?php
    public function renderTasks($userId) {
        //$this->template->user = $this->userRepository->findByName($user);
        $this->template->tasks = $this->taskRepository->findIncompleteByUser($userId);
    }
?>

TaskPresenter:

<?php
    public function findIncompleteByUser($userId){
        $this->findIncomplete()->where(array('user_id' => $userId));
    }
?>

Při výpisu mi to hlásí chybu Invalid argument supplied for foreach()

**Můžete mi prosím někdo s tímto pomoci? Děkuji **

vvoody
Člen | 910
+
0
-
public function findIncompleteByUser($userId){
	return $this->findIncomplete()->where(array('user_id' => $userId));
}

ten return

Dismember
Člen | 50
+
0
-

díky :-) už to valí :-)

Dismember
Člen | 50
+
0
-

zdravím po nějaké době ;-) začal jsem tvořit aplikaci a využívám postupy, které jsou představeny ve quickstartu.

Chtěl jsem si vytvořit menu z položek v databázi. Stejně jako ve quickstartu jsem proto připojil jednotlivé repozitáře do BasePresenteru a ve funkci beforeRender volám položky z databáze.

<?php

use Nette\Application\UI;
use Nette\Application\UI\Form;

/**
 * Base presenter for all application presenters.
 */
abstract class BasePresenter extends Nette\Application\UI\Presenter {

    private $itemRepository;
    private $sourceRepository;
    private $topicRepository;
    private $regionRepository;

    function inject(Osint\ItemRepository $itemRepository, Osint\SourceRepository $sourceRepository, Osint\TopicRepository $topicRepository, Osint\RegionRepository $regionRepository) {
        $this->itemRepository = $itemRepository;
        $this->sourceRepository = $sourceRepository;
        $this->topicRepository = $topicRepository;
        $this->regionRepository = $regionRepository;
    }

    public function beforeRender() {
        // provede vždy nezávisle na view
        $this->template->topics = $this->topicRepository->getTopics();
    }

    public function handleSignOut() {
        $this->getUser()->logout();
        $this->redirect('Sign:in');
    }

}
?>

Toto ale skončí fatal errorem Call to a member function getTopics() on a non-object

Podobně v jiném presenteru (viz níže) volám položky a vše funguje jak má

Můžete mi poradit prosím, jak upravit výše uvedený kód, abych získal položky z databáze, které použiju na každou stránku do menu?

<?php

use Nette\Application\UI;
use Nette\Application\UI\Form;

class TopicPresenter extends BasePresenter {

    private $itemRepository;
    private $sourceRepository;
    private $topicRepository;
    private $regionRepository;

    function inject(Osint\ItemRepository $itemRepository, Osint\SourceRepository $sourceRepository, Osint\TopicRepository $topicRepository, Osint\RegionRepository $regionRepository) {
        $this->itemRepository = $itemRepository;
        $this->sourceRepository = $sourceRepository;
        $this->topicRepository = $topicRepository;
        $this->regionRepository = $regionRepository;
    }

    public function renderDefault() {
        $this->template->topics = $this->topicRepository->getTopics();
    }

}
?>

Editoval Dismember (18. 6. 2013 8:56)

andrej2005
Člen | 2
+
0
-

Dobry den. Taky mam potize s quickstartem. Precetl jsem snad vsechna thready na tohle tema, a dospel jsem k nazoru, ze provozovatel stranek bys mel dat to do poradku. Zacatecnik nevidi do hloubky vsech chyb, problemu a souvislosti, proto nedokaze dat to dohromady.

Timto zadam o opravu zdrojaku pro quickstart.

Glottis
Člen | 129
+
0
-

myslim si ze v basepresenteru se ti nezavola beforeRender, protoze to nevolas v tom podedenem

public function beforeRender() {
	parent::beforeRender();
}

ale mozna ze placam :)

Glottis
Člen | 129
+
0
-

a jeste si nejsem jisty tim, jak mas zadeklarovane ty privatni promene. mas je jak v base tak tom podedenem. a v obou do nich priradis pres inject (pokud vubec projdou oba injecty) a cekal bych, ze kdyz priradis v podedenem, tak v parentovy tam ty data mit nebudes :) protoze to je privat

Dismember
Člen | 50
+
0
-

díky za impuls!

Samozřejmě to bylo špatně :-)) v BasePresenteru jsem ty privatní proměnné nastavil na Public a v ostatních poděděných presenterech je zrušil a už to valí…začínám mít v tom OOP větší pořádek :-)

enumag
Člen | 2118
+
0
-

@Dismember: Public rozhodně NE, použij protected.

jiri.pudil
Nette Blogger | 1032
+
0
-

andrej2005 napsal(a):

Dobry den. Taky mam potize s quickstartem. Precetl jsem snad vsechna thready na tohle tema, a dospel jsem k nazoru, ze provozovatel stranek bys mel dat to do poradku. Zacatecnik nevidi do hloubky vsech chyb, problemu a souvislosti, proto nedokaze dat to dohromady.

Jenže pro člověka, který ten quickstart píše, není vůbec jednoduché se oprostit od toho, co už o Nette ví a kam až do hloubky vidí. Takový člověk prostě neví, co všechno začátečník neví. (Nehledě na to, že to, co začátečník neví, často zahrnuje i elementární věci, které se spíše než Nette týkají samotného PHP a OOP v něm.)

Timto zadam o opravu zdrojaku pro quickstart.

Jakým směrem? Na co se zaměřit? Která místa jsou problematická? Co kde zjednodušit? Co kde vysvětlit víc do hloubky? Když pošleš konkrétní připomínky, určitě s tím půjde něco udělat. Jinak je to jen výkřik do tmy.

Dismember
Člen | 50
+
0
-

@enumag Roger that! Thanks ;-)

lukaha
Člen | 2
+
0
-

jiri.pudil napsal(a):


Timto zadam o opravu zdrojaku pro quickstart.

Jakým směrem? Na co se zaměřit? Která místa jsou problematická? Co kde zjednodušit? Co kde vysvětlit víc do hloubky? Když pošleš konkrétní připomínky, určitě s tím půjde něco udělat. Jinak je to jen výkřik do tmy.

Zdravim, tak ja se pokusim shrnout sve poznatky ze studia quickstartu:

  • verze na github.com je diametralne odlisna od textu v quickstartu, protoze se v quickstartu pouziva dle slov hlavnich vyvojaru Nette BAD PRACTICE (lekce se stejným principem Prezentery, Formuláře:
$this->taskRepository = $this->context->taskRepository;

) Chapu,ze se Nette vyviji, ale dle meho nazoru by to mohlo byt aspon trochu sjednocenne at jiz s githubem nebo github s quickstartem (pomerne dost dlouho mi trvalo, nez jsem prisel, kde je chyba a v cem se lisi muj kod od Githubu, kdyz jsem psal podle navodu… metoda injectNeco mi pripomina metodu set)

  • dale v kapitole Prezentery je chyba v metode actiondefault, ktera se da objevit celkem snadno, protoze hlasi, ze metoda find ($id) neexistuje, a na Githubu je to opravene, ale jiz se nikdo neotravoval to dat i do textu:
$this->list = $this->listRepository->find($id);
  • clovek v quickstartu snadno ztrati orientaci: nadpis TaskPrezenter, kousek pod tim BasePresenter (ac je to v jinem kontextu, muze to par novacku zmast).

V poslednich 3 kapitolach jsem nic nenasel. Zdaji se mi, ze jsou jiz psany novym zpusobem. Je mozne aspon zrevidovat ceskou verzi a upravit ji dle anglicke verze?

andrej2005
Člen | 2
+
0
-

>

Timto zadam o opravu zdrojaku pro quickstart.

Jakým směrem? Na co se zaměřit? Která místa jsou problematická? Co kde zjednodušit? Co kde vysvětlit víc do hloubky? Když pošleš konkrétní připomínky, určitě s tím půjde něco udělat. Jinak je to jen výkřik do tmy.

Jakym smerem? Navod je celkem pekny, snazeji se vysvetlit koncepci frameworku! Ale bohuzel kdyz jedes podle nej, tak ten projekt se nespusti. Ladenka vyhodi spoustu chyb, a nevis kam s tim. Jestli stahnes z githubu, pak Composer to neumi sestavit – prej neumi stahnout nejaky tester.git. Rucne taky nejde. Ja osobne uz nevim kam pichnout. Zkusil vsechno (behem druheho tydne praci na tom podle moznosti). Je mi zajmave jestli autor to vyzkousel u sebe? Opravdu mu to bezi? Nebo trochu jinak, je tady nekdo, komu funguje quickstart? Aspon bezi example CD-collection. Celkem podobny priklad. Podle nej snazim se prokousat. V PHP jsem opravdu zacatecnik, pro mne je bliz asp.net, ale okolnosti jsou takove, ze musim to zvladnout.
Proste chtelo by to, pokud je to opravdu quickstart, podle navodu sestavit projekt a spustit ho, i kdyz clovek nechape vsech souvisloti v PHP. A na githubu musi byt funkcni zdrojak pro overeni postupu. Bylo by to mozni?