Development

Documentation/nl_NL/my_first_project

You must first sign up to be able to contribute.

Installeer symfony en initialiseer een nieuw project

We maken gebruik van de symfony sandbox. Het is een leeg symfony project waar al de benodigde libraries inzitten, en de standaard configuratie al gedaan is. Het grote voordeel van de sandbox installatie is dat dat je meteen kunt experimenteren met symfony.

Je kunt het hier downloaden: sf_sandbox.tgz, pak het uit naar de root web directory. In het bijgevoegde README bestand vind je meer informatie.

De bestand structuur zou er als volgt uit moeten zien:

www/
  sf_sandbox/
    apps/
      frontend/
    batch/
    cache/
    config/
    data/
      sql/
    doc/
    lib/
      model/
    log/
    plugins/
    test/
    web/
      css/
      images/
      js/

Dit zal een sf_sandbox project weergeven met een frontend applicatie. Test de sandbox door de volgende link op te vragen in je browser.

http://www.localhost/sf_sandbox/web/index.php/

Je ziet nu het volgende configuratie scherm:
http://www.symfony-project.com/images/tutorials/first_congrats.gif


Je kunt symfony ook installeren in een andere directory en dan gebruik maken van Virual hosts of een Allias. Het symfony boek bevat gedetaileerde hoofdstukken hierover namelijk Symfony installation en symfony directory structure.

Initialiseer het data model


In de weblog willen we artikels kunnen plaatsen en daar commentaar op kunnen geven. Maak in de directory sf_sandbox/config/ een bestand schema.yml met de volgende inhoud.

propel:
  weblog_post:
    _attributes: { phpName: Post }
    id:
    title:       varchar(255)
    excerpt:     longvarchar
    body:        longvarchar
    created_at:
  weblog_comment:
    _attributes: { phpName: Comment }
    id:
    post_id:
    author:      varchar(255)
    email:       varchar(255)
    body:        longvarchar
    created_at:


Dit configuratie bestand maakt gebruik van de YAML syntax. YAML is een makkelijke taal die het mogelijk maakt om een boom structuur te creeren. Het inspringen moet worden gedaan met spaties omdat YAML het anders niet begrijpt. Het is makkelijker leesbaar dan XML en sneller te maken. Meer informatie over YAML en de symfony configuratie kun je vinden in het hoofdstuk Configuration chapter.


Dit schema bevat de twee tabellen die we nodig hebben hebben voor onze weblog. Post en Comment worden de namen van de classes die gegenereerd worden. Sla het bestand op en open de command line. Ga naar de sf_Sandbox/ directory en type het volgende in.

$ php symfony propel-build-model 


Er zijn nu een aantal classes aangemaakt in de sf_sandbox/lib/model/ directory. Deze classes horen bij het "object-relational mapping" component die het mogelijk maken om de bijbehorende database aan te roepen vanuit de code zonder ook maar een SQL query te schrijven. Symfony maakt hiervoor gebruik van de Propel library. We noemen deze objecten "Het model". In het hoofdstuk Model Chapter kun je hier meer over lezen.

Type nu het volgende in je command line:

$ php symfony propel-build-sql

In de sf_sandbox/data/sql/ directory vind je nu een bestand lib.model.schema.sql. Deze SQL query kun je gebruiken om een database te initialiseren met dezelfde tabel struktuur. Je kan een database maken in MySQL met de command line of de web interface. Maar gelukkig kan symfony dit ook voor je doen. Standaard maakt het sf_sandbox project gebruik van een database genaamd sandbox.db die je kan terugvinden in sf_sandbox/data/ Om de database aan te maken type het volgende:

$ php symfony propel-insert-sql

Schrik niet als je op dit moment een waarschuwing te zien krijgt want dat is normaal. De insert-sql commando probeert bestaande tabellen te verwijderen voordat hij de tabellen uit de lib.model.schema.sql aanmaakt maar op dit moment zijn er nog geen tabellen.

Maak de applicatie scaffolding


De basis onderdelen van een weblog zijn het aanmaken, opvragen, updaten en verwijderen van artikelen en commentaren. Symfony kan aan de hand van het data model dit voor je genereren dit doe je op de volgende manier:

$ php symfony propel-generate-crud frontend post Post
$ php symfony propel-generate-crud frontend comment Comment
$ php symfony clear-cache

On *nix systems, you will have to change some rights:
$ chmod 777 data
$ chmod 777 data/sandbox.db


Nu heb je twee modules namelijk post en Comment. Met deze modules kun je de objecten beheren van de post en comment classes. Een module staat voor een pagina of groep van pagina`s met het zelfde doel. De nieuwe modules vind je terug via de volgende URLs:


Je kunt nu data invoeren zodat de weblog wat meer opvulling krijgt.
http://www.symfony-project.com/images/tutorials/first_crud.gif
Hier vind je meer informatie over Scaffolding en hier vind je meer informatie over de struktuur van symfony.

In de bovenstaande URLs zal je opvallen dat index.php veranderd is in frontend_dev.php de twee URLs gebruiken dezelfde applicatie (frontend),maar in verschillende omgevingen. Bij frontend_dev.php, maak je gebruik van de applicatie in development omgeving, Waar je beschikking hebt over verscheidene development tools bijvoorbeeld de debug toolbar rechts boven in het scherm en de "live configuration engine". Hierdoor is het laden van een pagina ook langzamer dan dat hij geladen word via index.php. De produktie omgeving controller is index.php deze is geoptimaliseerd voor snelheid. Als je gebruik wilt blijven maken van de produktie omgeving, verplaats dan de frontend_dev.php voor index.php/ in de volgende URLs maar vergeet niet eerst even de cache te legen, dit doe je op de volgende manier:

$ php symfony clear-cache

http://localhost/sf_sandbox/web/index.php/


Lees meer over de verschillende omgevingen in environments

Verander de layout


Om te kunnen navigeren tussen de verschillende modules heeft de weblog een standaard navigatie nodig.

Pas de global template aan die je kunt vinden op de volgende locatie sf_sandbox/apps/frontend/templates/layout.php vervang de code tussen de <body> tags voor de volgende code:

<div id="container" style="width:600px;margin:0 auto;border:1px solid grey;padding:10px">
  <div id="navigation" style="display:inline;float:right">
    <ul>
      <li><?php echo link_to('List of posts', 'post/list') ?></li>
      <li><?php echo link_to('List of comments', 'comment/list') ?></li>
    </ul>
  </div>
  <div id="title">
    <h1><?php echo link_to('My first symfony project', '@homepage') ?></h1>
  </div>
 
  <div id="content" style="clear:right">
    <?php echo $sf_data->getRaw('sf_content') ?>
  </div>
</div>

Je kunt je pagina titel aanpassen door de view configuration file te wijzigen. Deze kun je vinden op de volgende locatie sf_sandbox/apps/frontend/config/view.yml Zoek de regel op met de titel en verander deze naar: default: http_metas: content-type: text/html

metas:
  title:        The best weblog ever
  robots:       index, follow
  description:  symfony project
  keywords:     symfony, project
  language:     en


De gehele website moet ook aangepast worden want hij maakt nu gebruik van een standaard template van de standaard module deze bevind zich in het framework en niet in je applicatie. Om dit te overschrijven moet je een eigen main module maken dit doe je door het volgende in te typen:

$ php symfony init-module frontend main


Standaard laat de index action een "Congratulations" scherm zien. Om dit te veranderen moet je het volgende bestand aanpassen. sf_sandbox/apps/frontend/modules/main/actions/actions.class.php Vervang de executeIndex() voor het volgende:

<?php
public function executeIndex()
{
}

Wijzig nu sf_sandbox/apps/frontend/modules/main/templates/indexSuccess.php om er een welkom text in te zetten bijvoorbeeld.

<h1>Welcome to my swell weblog</h1>
<p>You are the <?php echo rand(1000,5000) ?>th visitor today.</p>


Nu moeten we symfony nog vertellen welke actie we willen uitvoeren als de pagina aangeroepen word. Om dit te doen moeten we het volgende bestand sf_sandbox/apps/frontend/config/routing.yml als volgt aanpassen.

homepage:
  url:   /
  param: { module: main, action: index }


Bekijk het resultaat op http://localhost/sf_sandbox/web/frontend_dev.php/
http://www.symfony-project.com/images/tutorials/first_welcome.gif


Hier vind je meer informatie over Views en templates.

Informatie doorgeven vanuit de action naar de template

Dat was snel, of niet? Nu is het tijd om de comment module en de post module door elkaar te gooien om het commentaar onder de berichten te tonen.

Allereerst moet je het commentaar bij een bericht beschikbaar maken in de post weergave template. In symfony wordt dit soort logica in de actions gezet. Wijzig het actions bestand sf_sandbox/apps/frontend/modules/post/actions/actions.class.php en verander de executeShow() methode door de volgende 4 regels toe te voegen:

<?php 
public function executeShow()
{
  $this->post = PostPeer::retrieveByPk($this->getRequestParameter('id'));
  $this->forward404Unless($this->post);
 
  $c = new Criteria();
  $c->add(CommentPeer::POST_ID, $this->getRequestParameter('id'));
  $c->addAscendingOrderByColumn(CommentPeer::CREATED_AT);
  $this->comments = CommentPeer::doSelect($c);
}

De Criteria en -Peer objecten zijn onderdeel van Propel's object-relational mapping. Feitelijk zullen deze vier regels een SQL query op de Comment tabel afhandelen om het commentaar op te halen die gerelateerd zijn aan het huidige bericht (degene die geselecteerd wordt door de URL parameter id). De $this->comments regel in de action zal toegang verlenen tot de $comments variabele in de bijbehorende template. Pas nu de post weergave template sf_sandbox/apps/frontend/modules/post/templates/showSuccess.php aan door het volgende aan het einde toe te voegen:

<?php use_helper('Text', 'Date') ?>
 
<hr />
<?php if ($comments) : ?>
  <p><?php echo count($comments) ?> comment<?php if (count($comments) > 1) : ?>s<?php endif; ?> to this post.</p>
  <?php foreach ($comments as $comment): ?>
    <p><em>posted by <?php echo $comment->getAuthor() ?> on <?php echo format_date($comment->getCreatedAt()) ?></em></p>
    <div class="comment" style="margin-bottom:10px;">
      <?php echo simple_format_text($comment->getBody()) ?>
    </div>
  <?php endforeach; ?>
<?php endif; ?>

Deze pagina gebruikt nieuwe PHP functies (format_date() en simple_format_text()) die worden geboden door symfony. Ze worden 'helpers' genoemd omdat ze een aantal taken voor je doen die normaal gesproken meer tijd en code kosten. Maak een nieuw commentaar aan voor je eerste bericht, en check vervolgens het eerste bericht, door bijvoorbeeld op het nummer in de lijst te klikken of direct in the typen:

http://localhost/sf_sandbox/web/frontend_dev.php/post/show?id=1

http://www.symfony-project.com/images/tutorials/first_comments_under_post.gif

Dit begint goed te worden.

Hier vind je meer informatie over benamingsconventies van een action met een template

Voeg een nieuwe record to relatief aan een andere tabel

Bij het toevoegen van commentaar kan je de id van het gerelateerde bericht kiezen. Dat is niet erg gebruikersvriendelijk. Laten we dit veranderen, en zeker stellen dat de gebruiker terugkomt bij het bericht waar hij commentaar op levert.

Allereerst, in de nog verse modules/post/templates/showSuccess.php template, voeg de volgende regel toe aan het einde:

<?php echo link_to('Add a comment', 'comment/create?post_id='.$post->getId()) ?>

De link_to() helper maakt een hyperlink aan die wijst naar de create action van de comment module, zodat je direct commentaar kan toevoegen vanaf de bericht detail pagina. Vervolgens, open modules/comment/templates/editSuccess.php en vervang de volgende regels:

<tr>
  <th>Post:</th>
  <td><?php echo object_select_tag($comment, 'getPostId', array (
  'related_class' => 'Post',
)) ?></td>
</tr>

door:

<?php if ($sf_params->has('post_id')): ?>
  <?php echo input_hidden_tag('post_id',$sf_params->get('post_id')) ?> 
<?php else: ?>
  <tr>
    <th>Post*:</th>
    <td><?php echo object_select_tag($comment, 'getPostId', array('related_class' => 'Post')) ?></td>
  </tr>
<?php endif; ?>

Het formulier in de comment/create pagina wijst nu naar de comment/update action, die de gebruiker doorstuurt naar comment/show wanneer het formulier wordt verstuurd (dit is het standaard gedrag van een gegenereerde CRUD). Voor de weblog betekent dit dat na het toevoegen van commentaar, de detailpagina van het commentaar wordt getoond. het is beter om het originele bericht te tonen met al het bijbehorende commentaar tot dan toe. Dus open modules/comment/actions/actions.class.php en zoek de executeUpdate() methode. Merk up dat het created_at veld niet door de action wordt gedefinieerd: symfony weer dat een veld met de naam created_at naar de systeemtijd moet worden gezet wanneer een nieuwe record wordt aangemaakt. De uiteindelijke redirect van de action moet nu worden aangepast om naar de correcte action te worden gestuurd. Verander het naar:

<?php
public function executeUpdate ()
{
  if (!$this->getRequestParameter('id', 0))
  {
    $comment = new Comment();
  }
  else
  {
    $comment = CommentPeer::retrieveByPk($this->getRequestParameter('id'));
    $this->forward404Unless($comment);
  }
 
  $comment->setId($this->getRequestParameter('id'));
  $comment->setPostId($this->getRequestParameter('post_id'));
  $comment->setAuthor($this->getRequestParameter('author'));
  $comment->setEmail($this->getRequestParameter('email'));
  $comment->setBody($this->getRequestParameter('body'));
 
  $comment->save();
 
  return $this->redirect('post/show?id='.$comment->getPostId());
}

Gebruikers kunnen nu commentaar aan berichten toevoegen en zullen worden teruggestuurd naar het bericht. Je wou een weblog? Je hebt een weblog.

Hier vind je meer over actions

Formulier Validatie

Bezoekers kunnen commentaar toevoegen, maar wat als ze het formulier verzenden zonder enige data erin? Dan krijg je een vervuilde database. Om dat tegen te gaan, maak een bestand aan genaamd update.yml in de sf_sandbox/apps/frontend/modules/comment/validate/ directory (je moet die directory ook aanmaken) en schrijf hierin:

methods:
  post:           [author, email, body]
  get:            [author, email, body]

fillin:
  enabled:       on

names:
  author:
    required:     Yes
    required_msg: Het naam veld kan niet leeg gelaten worden

  email:
    required:     No
    validators:   emailValidator

  body:
    required:     Yes
    required_msg: Het tekst veld kan niet leeg gelaten worden

emailValidator:
  class:          sfEmailValidator
  param:
    email_error:  Dit is geen geldig e-mailadres

Let op dat je de 4 extra spaties aan het begin van iedere regel niet mee kopieert, aangezien de YAML parser in dat geval zou breken. De eerste letter in dit bestand moet zijn de 'm' van 'methods'.

Het activeren van de fillin zorgt ervoor dat het formulier opnieuw wordt gevuld met de waarde die eerder door de gebruiker werd ingevoerd in het geval van een mislukte validatie. De naam declaraties zetten de validatie regels voor ieder inputveld van het formulier.

Uit zichzelf zal de controller de gebruiker doorsturen naar de updateError.php template wanneer een fout wordt gevonden. Het zou beter zijn het formulier nogmaals te tonen, met een foutmelding. Om dat te doen, voeg de handleErrorUpdate methode toe aan de action class van modules/comment/actions/actions.class.php:

<?php
public function handleErrorUpdate()
{
  $this->forward('comment', 'create');
}

Om het nu af te maken, open wederom de modules/comment/templates/editSuccess.php template en voeg dit bovenaan toe:

<?php if ($sf_request->hasErrors()): ?>  
  <div id="errors" style="padding:10px;">
    Please correct the following errors and resubmit:
    <ul>
    <?php foreach ($sf_request->getErrors() as $error): ?>
      <li><?php echo $error ?></li>
    <?php endforeach; ?>
    </ul>
  </div>
<?php endif; ?>

Nu heb je een robuust formulier.

http://www.symfony-project.com/images/tutorials/first_form_validation.gif

Hier vind je meer over Formulier validatie

Verander de URL

Is je al opgevallen hoe de URLs worden getoond? Je kan ze meer gebruikers- en zoekmachine-vriendelijk maken. Laten we de titel van het bericht gebruiken als een URL voor berichten.

Het probleem is dat titels speciale karakters kunnen bevatten zoals spaties. Als je ze gewoon escaped, zal de URL lelijke dingen bevatten als %20, dus je kan beter het model uitbreiden om een nieuwe methode aan het Post object toe te voegen om een schone, gestripte titel te krijgen. Om dat te doen, wijzig het Post.php bestand dat je vind in de sf_sandbox/lib/model/ directory, en voeg de volgende methode toe:

<?php
public function getStrippedTitle()
{
  $result = strtolower($this->getTitle());
 
  // strip all non word chars
  $result = preg_replace('/\W/', ' ', $result);
 
  // replace all white space sections with a dash
  $result = preg_replace('/\ +/', '-', $result);
 
  // trim dashes
  $result = preg_replace('/\-$/', '', $result);
  $result = preg_replace('/^\-/', '', $result);
 
  return $result;
}

Nu kan je een permalink actie maken voor de post module. Voeg de volgende methode toe aan modules/post/actions/actions.class.php:

<?php
public function executePermalink()
{
  $posts = PostPeer::doSelect(new Criteria());
  $title = $this->getRequestParameter('title');
  foreach ($posts as $post)
  {
    if ($post->getStrippedTitle() == $title)
    {
      break;
    }
  }
  $this->forward404Unless($post);
 
  $this->getRequest()->setParameter('id', $post->getId());
 
  $this->forward('post', 'show');
}

De lijst met berichten kna deze permalink action aanroepen in plaats van de show action voor ieder bericht. In modules/post/templates/listSuccess.php, verwijder de id tabel header en cel, en verander de titel cel van:

<td><?php echo $post->getTitle() ?></td>

Naar:

<td><?php echo link_to($post->getTitle(), 'post/permalink?title='.$post->getStrippedTitle()) ?></td>

Nog een stap: Het wijzigen van de routing.yml die je vind in sf_sandbox/apps/frontend/config/. Voeg deze regels toe aan de bovenkant:

list_of_posts:
  url:   /latest_posts
  param: { module: post, action: list }

post:
  url:   /weblog/:title
  param: { module: post, action: permalink }

Navigeer nu nog eens naar je applicatie en let op de URLs.

http://www.symfony-project.com/images/tutorials/first_routing.gif

Hier vind je meer over mooie URLs.

Opschonen van de voorkant

Goed, als dit een weblog is, dan heeft iedereen het recht om berichten te plaatsen. Dat is niet precies waar je aan dacht, of wel? OK, laten we de templates wat opschonen.

In de template modules/post/templates/showSuccess.php, haal de 'edit' link weg door de volgende regel te verwijderen:

<?php echo link_to('edit', 'post/edit?id='.$post->getId()) ?>

Doe hetzelfde voor de modules/post/templates/listSuccess.php template en verwijder:

<?php echo link_to('create', 'post/create') ?>

Je moet ook de volgende methodes verwijderen uit modules/post/actions/actions.class.php:

  • executeCreate
  • executeEdit
  • executeUpdate
  • executeDelete

OK, lezers kunnen geen berichten meer plaatsen.

Generatie van de backend

Laten we een backend applicatie maken zodat je berichten kan plaatsen. Typ in de command line (nog steeds binnen de sf_sandbox project directory):

$ php symfony init-app backend
$ php symfony propel-init-admin backend post Post
$ php symfony propel-init-admin backend comment Comment

Deze keer gebruiken we de admin generator. Het bied veel meer features en aanpassingsmogelijkheden dan de basis CRUD generator.

Zoals je ook deed voor de frontend applicatie, wijzig de layout (apps/backend/templates/layout.php) om de globale navigatie toe te voegen:

<div id="navigation">
  <ul style="list-style:none;">
    <li><?php echo link_to('Manage posts', 'post/list') ?></li>
    <li><?php echo link_to('Manage comments', 'comment/list') ?></li>
  </ul>
</div>
<div id="content">
  <?php echo $sf_data->getRaw('sf_content') ?>
</div>

Je kan je nieuwe back-office applicatie in de ontwikkelomgeving zien door naar het volgende adres te gaan:

http://localhost/sf_sandbox/web/backend_dev.php/post

http://www.symfony-project.com/images/tutorials/first_basic_admin.gif

Het grote voordeel van het gegenereerde beheer is dat je het makkelijk kan aanpassen door het wijzigen van een configuratiebestand.

Verander de backend/modules/post/config/generator.yml naar:

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Post
    theme:            default
    fields:
      title:          { name: Title }
      excerpt:        { name: Exerpt }
      body:           { name: Body }
      nb_comments:    { name: Comments }
      created_at:     { name: Creation date }
    list:
      title:          Post list
      layout:         tabular
      display:        [=title, excerpt, nb_comments, created_at]
      object_actions:
        _edit:        ~
        _delete:      ~
      max_per_page:   5
      filters:        [title, created_at]
    edit:
      title:          Post detail
      fields:
        title:        { type: input_tag, params: size=53 }
        excerpt:      { type: textarea_tag, params: size=50x2 }
        body:         { type: textarea_tag, params: size=50x10 }
        created_at:   { type: input_date_tag, params: rich=on }

Merk op dat tussen de bestaande kolommen van de Post tabel, de admin zal zoeken naar een nb_comments. Er is nog geen getter hiervoor, maar het is simpel om die toe te voegen aan sf_sandbox/lib/model/Post.php:

<?php
public function getNbComments()
{
  return count($this->getComments());
}

Ververs nu het Post beheer en zie de veranderingen:

http://www.symfony-project.com/images/tutorials/first_custom_admin.gif

Beveilig de toegang tot de backend

De backend kan momenteel door iedereen worden bezocht. Je moet hier toegangs restricties op zetten.

In apps/backend/modules/post/config/, voeg een bestand genaamd security.yml toe met de volgende inhoud:

all:
  is_secure: on

Herhaal dit voor de comment module. Nu kan je deze modules niet meer bezoeken tenzij je ingelogd bent.

Maar er bestaat nog geen action om in te loggen! OK, die kan je makkelijk toevoegen. Allereerst, maak een security module skelet:

$ php symfony init-module backend security

Deze nieuwe module zal worden gebruikt om het login formulier af te handelen. Wijzig de apps/backend/modules/security/templates/indexSuccess.php om het login formuler te maken:

<h2>Authentication</h2>
 
<?php if ($sf_request->hasErrors()): ?>
  Identification failed - please try again
<?php endif; ?>
 
<?php echo form_tag('security/login') ?>
  <label for="login">login:</label>
  <?php echo input_tag('login', $sf_params->get('login')) ?>
 
  <label for="password">password:</label>
  <?php echo input_password_tag('password') ?>
 
  <?php echo submit_tag('submit', 'class=default') ?>
</form>

Voeg de login action toe die wordt aangeroepen door het formulier in de security module (in apps/backend/modules/security/actions/actions.class.php):

<?php
public function executeLogin()
{
  if ($this->getRequestParameter('login') == 'admin' && $this->getRequestParameter('password') == 'password')
  {
    $this->getUser()->setAuthenticated(true);
 
    return $this->redirect('main/index');
  }
  else
  {
    $this->getRequest()->setError('login', 'incorrect entry');
 
    return $this->forward('security', 'index');
  }
}

En voor de hoofd module, verwijder de standaard code in de index action:

<?php
public function executeIndex()
{
}

Het laatste wat je moet doen is om de security module in te stellen als de standaard module voor het afhandelen van inlog actions. Om dat te doen, open het apps/backend/config/settings.yml configuratie bestand en voeg toe:

all:
  .actions:
    login_module:           security
    login_action:           index    

Op dit punt, als je het berichtenbeheer probeert te openen, moet je een gebruikersnaam en wachtwoord invoeren:

http://www.symfony-project.com/images/tutorials/first_login.gif

Hier vind je meer over beveiliging.

Conclusie

OK, het uur is voorbij. Je hebt het gered. Nu kan je beide applicaties gebruiken in een productie omgeving en ermee spelen:

frontend:   http://localhost/sf_sandbox/web/index.php/
backend:    http://localhost/sf_sandbox/web/backend.php/

Als je op dit punt een foutmelding tegenkomt, kan het misschien zijn omdat je het model hebt aangepast nadat een aantal actions in de cache zijn toegevoegd (cache staat niet aan voor de ontwikkelomgeving). Om de cache te legen, typ:

$ php symfony cc

Zie, de applicatie is snel en draait prima. Best wel cool, of niet? Kijk vooral even door de code heen, voeg nieuwe modules toe, en verander het design van de pagina's.

En vergeet niet je werkende symfony applicaties in de symfony Wiki te vermelden!