Write a comment
Wichtig Symfony Kommandos
Neues Projekt anlegen
php lib/vendor/symfony/data/bin/symfony generate:project projekt1
Frontend anlegen
php symfony generate:app frontend
Auflistung aller Kommandos
php symfony list
Cache Löschen
php symfony cache:clear
oder
php symfony cc
Alle Modelle erstellen und YAML Testdaten laden
php symfony doctrine:build --all --and-load
Neues Modul anlegen mit Tabellenzugriff an legen
php symfony doctrine:generate-module --with-show --non-verbose-templates frontend <ModulName> <TableName>
Sprachdatei erzeugen und werte speichern
php symfony i18n:extract frontend de --auto-save
Unit Tests starten
php symfony test:unit
oder
php symfony test:unit <TestClass>
In diesem Tutorial zeigen wir, wie man einen Blog mit Hilfe des Symfony Frameworks einrichtet.
Mit ein paar Handgriffen erhält man so schnell eine Möglichkeit flexibel und schlank seinen eigenen Blog zu pflegen.
Dank des modernen Architekturmusters MVC ist der Blog beliebig erweiterbar.
Weiterlesen
Moderne Web-Programmierung mit dem Symfony Framework
In diesem Tutorial wollen wir die grundlegenden Möglichkeiten des PHP Frameworks "symfony" erläutern.
Symfony ist ein in PHP 5 geschriebenes quelloffenes Web Application Framework welches dem Model View Controller (MVC) Architekturmuster folgt.
Für die Arbeit mit dem Symfony Framework verwenden wir ein Linux Betriebssystem inklusive Apache Webserver mit PHP Integration sowie eine MySQL Datenbank.
Weiterlesen
Write a comment
Achtung Neu!
Wir haben unsere Tutorials überarbeitet. Aktuell ist Symfony in der Version 3.4. Vielleicht möchtest Du lieber diese Tutorial lesen?
1. Neues Symfony2 Projekt anlegen
Wir befinden uns im Ordner workspace
Als erstes laden wir das Programm composer mit curl herunter
Siehe auch http://getcomposer.org/download/
curl -s https://getcomposer.org/installer | php
Jetzt legen wir ein neues Projekt an.
php composer.phar create-project symfony/framework-standard-edition webprojekt
Siehe auch
http://symfony.com/doc/current/book/installation.html
Die Fragen für die Datei "
parameters.yml" können mit drücken der Enter-Taste einfach bestätigt werden.
Anschließend verschieben wir die comphoser.phar Datei in das neu erstellte Projekt.
mv composer.phar webprojekt
Als Ergebnis haben wir folgende Projektstruktur
2. Composer anpassen
Damit symfony relative Symlinks erzeugen kann, tragen wir in der Section "extra"
"symfony-assets-install": "symlink" ein!
// file: composer.json
...
"extra": {
"symfony-app-dir": "app",
"symfony-web-dir": "web",
"incenteev-parameters": {
"file": "app/config/parameters.yml"
},
"symfony-assets-install": "symlink",
"branch-alias": {
"dev-master": "2.4-dev"
}
}
...
3. Apache Webserver einrichten
Wir legen einen neuen "Virtual Host" an, der auf den "web" Ordner des Symfony Projekts zeigt.
<VirtualHost *:80>
ServerName webprojekt.localhost
DocumentRoot "/workspace/webprojekt/web"
DirectoryIndex index.php
<Directory "/workspace/webprojekt/web">
AllowOverride All
Allow from All
Options Indexes FollowSymLinks
</Directory>
</VirtualHost>
Wichtig ist hier der "ServerName" dieser Name muss auflösbar sein.
Damit das funktioniert tragen wir den ServerName in der "hosts" Datei des Rechners ein.
// file: etc/hosts
127.0.0.1 webprojekt.localhost
Der Apache Webserver sollte nun einmal neu gestartet werden, damit die neue Konfiguration eingelesen wird.
Jetzt kann die Symfony Anwendung getestet werden. Dazu rufen wir die URL: http://webprojekt.localhost/config.php auf.
4. MySQL Datenbank
Die Verbindungsdaten zur MySQL Datenbank werden in der Datei app/config/parameters.yml hinterlegt
// file: app/config/parameters.yml
parameters:
database_driver: pdo_mysql
database_host: 127.0.0.1
database_port: ~
database_name: webprojekt
database_user: username
database_password: kennwort
mailer_transport: smtp
mailer_host: 127.0.0.1
mailer_user: ~
mailer_password: ~
locale: en
secret: ThisTokenIsNotSoSecretChangeIt
Nachdem die Verbindungsdaten eingetragen sind, kann die Datenbank mit folgendem Kommando erstellt werden:
Achtung: Dazu musst Du natürlich in dem Ordner sein, in dem sich das Framework befindet.
php app/console doctrine:database:create
Write a comment
1. Bundle anlegen
In Symfony2 werden nicht wie in der alten Framework-Version "applications" angelegt sondern sogenannte "bundles". Bundles sind Plugins die alle benötigten PHP Anweisungen sowie CSS-Dateien, JavaScript-Dateien und Bilder enthalten.
In der Datei
app/AppKernel.php werden die Bundles geladen.
An dieser Stelle sei erwähnt, dass die neuen (app/console) Kommandos interaktiv programmiert sind.
Das heisst es können zahlreiche Eigenschaften dem Framework über die Konsole hinzugefügt werden, wobei
dem Benutzer entsprechenden Fragen gestellt werden und es somit einfach ist schnell Controller, Models und vieles mehr zu erstellen.
Wir legen jetzt ein neues Bundle mit dem Namespace Efi/BlogBundle an. Der Suffix "Bundle" ist zwinged notwendig!
Das Kommando lautet hierzu:
php app/console generate:bundle --namespace=Efi/BlogBundle
$ php app/console generate:bundle --namespace=Efi/BlogBundle
Welcome to the Symfony2 bundle generator
In your code, a bundle is often referenced by its name. It can be the
concatenation of all namespace parts but it's really up to you to come
up with a unique name (a good practice is to start with the vendor name).
Based on the namespace, we suggest EfiBlogBundle.
Bundle name [EfiBlogBundle]:
The bundle can be generated anywhere. The suggested default directory uses
the standard conventions.
Target directory [/workspace/webprojekt/src]:
Determine the format to use for the generated configuration.
Configuration format (yml, xml, php, or annotation): annotation
To help you get started faster, the command can generate some
code snippets for you.
Do you want to generate the whole directory structure [no]?
Summary before generation
You are going to generate a "Efi\BlogBundle\EfiBlogBundle" bundle
in "/workspace/webprojekt/src/" using the "annotation" format.
Do you confirm generation [yes]?
Bundle generation
Generating the bundle code: OK
Checking that the bundle is autoloaded: OK
Confirm automatic update of your Kernel [yes]?
Enabling the bundle inside the Kernel: OK
Confirm automatic update of the Routing [yes]?
Importing the bundle routing resource: OK
You can now start using the generated code!
Die Frage in Zeile 22 "
Configuration format (yml, xml, php, or annotation)" beantworten wir mit "annotation".
Nachdem dieser Schritt erfolgreich durchgeführt wurde, erhalten wir folgende Dateistruktur:
2. Das Standard Twig Layout
Im Ordner
src/Efi/BlogBundle/Resources/views erstellen wir jetzt die Datei "
layout.html.twig". Diese Datei soll für alle Seiten das Standard-Layout vorgeben.
Für das CSS und JavaScript verwenden wir das
Bootstrap Framework welches uns auch "Responsive Design" für Smartphones und Tablets bietet.
2.1 Bootstrap Framework laden und im Ordner web/bundles platzieren
Für unser Bundle legen wir einen Unterordner mit dem Namen
efiblog an. Dort wird der geladene Ordner "
bootstrap" abgelegt.
2.2 Eigene CSS Anpassungen
Für unsere eigenen CSS Anpassungen legen wir die Datei
web/bundles/efiblog/css/main.css an.
Der Inhalt sieht wie folgt aus:
/* file: web/bundles/efiblog/css/main.css */
body {
padding-bottom: 30px;
padding-top: 70px;
}
2.3 Twig-Standardlayout einrichten
Die Datei layout.html.twig anpassen.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset={{ _charset }}"/>
<meta name="robots" content="noindex,nofollow" />
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href = "{{ asset('bundles/efiblog/bootstrap/css/bootstrap.min.css') }}" />
<link rel="stylesheet" href = "{{ asset('bundles/efiblog/css/main.css') }}" />
{% block head %}{% endblock %}
</head>
<body role="document">
<!-- Fixed navbar -->
<div class='navbar navbar-inverse navbar-fixed-top' role='navigation'>
<div class='container'>
<div class='navbar-header'>
<button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>
<span class='sr-only'>Toggle navigation</span>
<span class='icon-bar'></span>
<span class='icon-bar'></span>
<span class='icon-bar'></span>
</button>
<a class='navbar-brand' href='#'>efi Blog</a>
</div>
<div class='navbar-collapse collapse'>
<ul class='nav navbar-nav'>
<li><a href='#'>Home</a></li>
<li><a href='#'>Page 1</a></li>
<li><a href='#'>Page 2</a></li>
<li><a href='#'>Kontakt</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
<div class='container theme-showcase' role='main'>
<div class='jumbotron'>
<h1>Der efi Blog!</h1>
<p>Made with Symfony2 and Bootstrap Framework</p>
</div>
<div class='row'>
<div class='col-md-12'>
<!--Body content-->
{% block body %}{% endblock %}
</div>
</div>
</div>
{% block javascripts %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="/{{ asset('bundles/efiblog/bootstrap/js/bootstrap.min.js') }}" type="text/javascript"></script>
{% endblock %}
</body>
</html>
2.4 Die default View anpassen
Damit wir unsere Seite testen können passen wir zum Schluss noch die vom Bundle erstellte Default-View an.
{# file: src/Efi/BlogBundle/Resources/views/Default/index.html.twig #}
{% extends 'EfiBlogBundle::layout.html.twig' %}
{% block title 'Efi Blog' %}
{% block body %}
<h1>Hello {{ name }}! </h1>
{% endblock %}
ACHTUNG! Das Default-Twig Template erwartet einen Parameter in der URL!
Die URL zum Testen der Seite lautet:
http://webprojekt.localhost/app_dev.php/hello/worldwobei das letzte Wort, in unserem Fall
World ein beliebiger Parameter ist.
Write a comment
Vorwort
Es lohnt sich immer im Vorfeld einen Blick in den Befehlsumfang des Symfony-Frameworks zu werfen. Das erreicht man in dem man das Kommando
php app/console
aufruft. Es werden dann alle Befehle aufgelistet!
Jedes Kommando kann wiederum mit dem help Parameter zusätzlich inspiziert werden.
# php app/console help generate:controller
Usage:
generate:controller [--controller="..."] [--route-format="..."] [--template-format="..."] [--actions="..."]
Options:
--controller The name of the controller to create
--route-format The format that is used for the routing (yml, xml, php, annotation) (default: "annotation")
--template-format The format that is used for templating (twig, php) (default: "twig")
--actions The actions in the controller (multiple values allowed)
--help (-h) Display this help message.
--quiet (-q) Do not output any message.
--verbose (-v) Increase verbosity of messages.
--version (-V) Display this application version.
--ansi Force ANSI output.
--no-ansi Disable ANSI output.
--no-interaction (-n) Do not ask any interactive question.
--shell (-s) Launch the shell.
--process-isolation Launch commands from shell as a separate process.
--env (-e) The Environment name. (default: "dev")
--no-debug Switches off debug mode.
Help:
The generate:controller command helps you generates new controllers
inside bundles.
By default, the command interacts with the developer to tweak the generation.
Any passed option will be used as a default value for the interaction
(--bundle and --controller are the only
ones needed if you follow the conventions):
php app/console generate:controller --controller=AcmeBlogBundle:Post
If you want to disable any user interaction, use --no-interaction
but don't forget to pass all needed options:
php app/console generate:controller --controller=AcmeBlogBundle:Post --no-interaction
1. Controller anlegen
Für die statischen Seiten "Page1 und Page2" legen wir eine gemeinsame Controller-Klasse an.
Diese Controller-Klasse muss dem von uns erstellten Bundle zugeordnet werden!
# php app/console generate:controller --controller=EfiBlogBundle:Articles
Dank der interaktiven Symfony-Kommandos werden jetzt einige Fragen gestellt. Es reicht aber erst einmal
alles mit Enter zu bestätigen!
Es wurde jetzt eine neue Datei mit Namen "ArticlesController.php" im Ordner Efi/BlogBundle/Controller erstellt.
In diese Datei fügen wir jetzt die Action für unsere erste Page ein:
<?php
namespace Efi\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class ArticlesController extends Controller
{
public function page1Action() {
return array();
}
}
2. View anlegen
Analog zu der Action "page1Action" soll es jetzt eine View geben.
Hierzu erstellen wir im Verzeichnis "views" unseres Bundles einen Unterordner mit dem Namen "Articles".
Darin legen wir eine Twig-Template Datei mit dem Namen "page1.html.twig" an!
Der Inhalt der Page1 kann innerhalb des body Blocks beliebig hinzugefügt werden.
Wichtig ist hierbei die Angabe: {% extends "EfiBlogBundle::layout.html.twig" %} die dem Template sagt von welchem Layout sie erben soll!
{# page1.html.twig #}
{% extends "EfiBlogBundle::layout.html.twig" %}
{% block title %}Page 1{% endblock %}
{% block body %}
<h2>Page 1</h2>
<p>
Ein bisschen Blindtext kann nicht schaden ...
</p>
{% endblock %}
3. Route für die Page1 definieren
Die Verbindung von einem Controller zu der View wird über die sogenannten Routes im Symfony-Framework geregelt. Da wir "annotations" gewählt haben, können wir jetzt die Routes über der Action-Methode angeben!
/**
* @Route("/page1", name="page1")
* @Template()
*/
public function page1Action() {
return array();
}
Über die URL http://webprojekt.localhost/app_dev.php/page1 kann die neue Seite jetzt getestet werden.
Für die zweite Seite (Page2) kann man jetzt die Schritte wiederholen. Hierzu einfach eine weitere Action und ein Twig-Template analog anlegen!
Der gesamte Controller:
<?php
// File: src/Efi/BlogBundle/Controller/ArticlesController.php
namespace Efi\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class ArticlesController extends Controller
{
/**
* @Route("/page1", name="page1")
* @Template()
*/
public function page1Action() {
return array();
}
/**
* @Route("/page2", name="page2")
* @Template()
*/
public function page2Action() {
return array();
}
}
Die zweite Seite (page2)
{# page2.html.twig #}
{% extends "EfiBlogBundle::layout.html.twig" %}
{% block title %}Page 2{% endblock %}
{% block body %}
<h2>Page 2</h2>
<p>
Dies ist unsere zweite Seite ...
</p>
{% endblock %}
Die URL für die zweite Seite lautet dann: http://webprojekt.localhost/app_dev.php/page2
Write a comment
Das Ziel
Wir möchten eine einfache Telefonliste anlegen und auf unserer Page anzeigen!
An dieser Stelle empfehlen wir das SQLyog Tool, das man unter
http://code.google.com/p/sqlyog/wiki/Downloads herunterladen kann. Es können natürlich auch der phpMyAdmin oder andere MySQL Tools verwendet werden.
1. Tabellenstruktur (Entity Class)
In Symfony werden Tabellen über Entity Klassen erzeugt. Man kann natürlich auch Tabellen von Hand anlegen und diese dann über "reverse engineering" Technik einlesen.
Mit dem nachfolgenden Kommando wird ein neuer Ordner
Entity in unserem Bundle sowie die Datei
"Phonelist.php" erzeugt!
php app/console doctrine:generate:entity --entity=EfiBlogBundle:Phonelist
Wir legen auch gleich die 3 Felder "vorname, nachname und telefon" an. Das ist nicht zwingend erforderlich spart aber jede Menge Arbeit, wenn man im Vorfeld schon weiß welche Felder man in seiner Tabelle haben möchte. Später können neue Felder manuell in der Klasse hinzugefügt werden.
...
Instead of starting with a blank entity, you can add some fields now.
Note that the primary key will be added automatically (named id).
Available types: array, simple_array, json_array, object,
boolean, integer, smallint, bigint, string, text, datetime, datetimetz,
date, time, decimal, float, blob, guid.
New field name (press <return> to stop adding fields): vorname
Field type [string]:
Field length [255]:
New field name (press <return> to stop adding fields): nachname
Field type [string]:
Field length [255]:
New field name (press <return> to stop adding fields): telefon
Field type [string]:
Field length [255]:
...
2. Die Tabelle erzeugen
Jetzt erstellen wir die Tabelle in unserer MySQL Datenbank mit folgendem Kommando:
php app/console doctrine:schema:update --force
Das Resultat prüfen wir mit dem sqlYOG.
Bei dieser Gelegenheit kann man auch gleich ein paar Testdaten eingeben!
3. Die Tabelle anzeigen
Wir benötigen einen so genannten CRUD-Controller! CRUD ist die Abkürzung für
Create Read Update und Delete. Der Crud Controller stellt die Verbindung zu unserer Entität dar und gibt die Daten aus der Tabelle an die View weiter.
Mit dem Kommando
doctrine:generate:crud erzeugen wir also einen Controller und die entsprechenden Views.
php app/console doctrine:generate:crud --entity=EfiBlogBundle:Phonelist
Jetzt sollte die Telefonliste über die URL
http://webprojekt.localhost/app_dev.php/phonelist aufrufbar sein. Allerdings stellen wir fest, dass unser Layout noch nicht mit dem neuen Twig-Views verbunden ist. Das holen wir jetzt gleich nach, in dem wir die Dateien in /src/Efi/BlogBundle/Resources/views/Phonelist/ anpassen.
Write a comment
1. Default Route
Beim erstellen des Bundles wurde die Controller Klasse "DefaultController" mit einer index Action angelegt. Diesen Controller wollen wir jetzt für unsere Startseite verwenden!
Beim anlegen des Bundles hat Symfony die function indexAction($name) so angelegt, dass man
Ihr einen Parameter übergeben kann. Da wir für die Startseite keinen Parameter benötigen entfernen wir die $name Variable bei dem Funktionsparameter und auch bei dem Funktions-Rückgabewert (return).
Als Route verwenden wir "/" und vergeben noch den Namen "homepage". Der Name kann später verwendet werden um mit {{ path('homepage') }} im Twig-Template eine URL zu erzeugen.
namespace Efi\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DefaultController extends Controller
{
/**
* @Route("/", name="homepage")
* @Template
*/
public function indexAction()
{
return array();
}
}
2. Das Homepage Template
Zu der Action "index" gibt es im Ordner src/Efi/BlogBundle/Resources/views/Default/ die Datei index.html.twig welche wir jetzt auch anpassen.
Wichtig ist vor allem, das die Variable {{ name }} entfernt wird, da wir ja im Controller diese auch herausgelöscht haben!
{# file: src/Efi/BlogBundle/Resources/views/Default/index.html.twig #}
{% extends 'EfiBlogBundle::layout.html.twig' %}
{% block title 'Efi Blog' %}
{% block body %}
<h1>Homepage</h1>
{% endblock %}
3. Menüpunkt mit Twig
Jetzt wollen wir noch das die Hyperlinks in unserem Menü funktionieren. Dazu müssen wir die URLs in userer Layout Datei "layout.html.twig" einstellen. Twig hat hierzu den Befehl {{ path('routename') }} der uns die entsprechende URL, in unserem Beispiel mit Annotation in der Action angegeben, generiert!
<ul class="nav navbar-nav">
<li><a href = "{{ path('homepage') }}">Home</a></li>
<li><a href = "{{ path('page1') }}">Page 1</a></li>
<li><a href = "{{ path('page2') }}">Page 2</a></li>
<li><a href = "#contact">Kontakt</a></li>
</ul>
4. Der technische Hintergrund von app_dev.php und app.php
Die Entwickler-Ansicht wird immer über die Datei app_dev.php aufgerufen. So kann man jetzt schon die Seite über die Url
http://webprojekt.localhost/app_dev.php/ testen. Will man die Produktiv-Ansicht aufrufen, so wird das Apache Module "mod_rewrite" benötigt und muss geladen sein.
# file: httpd.conf
...
LoadModule rewrite_module modules/mod_rewrite.so
...
Die Datei .htaccess sorgt dafür, dass wenn die Frontpage(Startpage) aufgerufen wird, auf die Datei app.php weitergeleitet wird!
# file /web/.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
#<IfModule mod_vhost_alias.c>
# RewriteBase /
#</IfModule>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ app.php [QSA,L]
</IfModule>
Ob das Rewrite Module geladen ist, kann man mit der Ausgabe von phpinfo() kontrollieren!
Probleme mit WAMP in der Produktivansicht
Falls die URL http://webprojekt.localhost einen 404 Error ausgibt, so hilft es in der Datei /web/app.php den Parameter false auf true zu setzen!
...
$kernel = new AppKernel('prod', true);
...
Write a comment
In diesem Tutorial wollen wir zeigen, wie man mit dem Symfony-Framework bestimmte Bereiche mit einem Login schützen kann. Dazu benötigt man Benutzer, Gruppen und Zugriffsrollen (ROLES), sowie ein Anmeldeformular das angezeigt wird, wenn ein Benutzer versucht einen URL aufzurufen die einen Login benötigt.
1. Login Controller
Für den Login muss man als erstes einen neuen Controller in Symfony anlegen.
Diesen nennen wir "Security".
# php app/console generate:controller --controller=EfiBlogBundle:Security
2. Login Action anlegen
Als nächstes erstellen wir die loginAction für den Login.
Achtet darauf, dass ihr noch ein paar Klassen mit "use" laden müsst.
<?php
// src/Efi/BlogBundle/Controller/SecurityController.php
namespace Efi\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContext;
class SecurityController extends Controller {
/**
* @Route("/login", name="login")
* @Template()
*/
public function loginAction(Request $request)
{
$session = $request->getSession();
// get the login error if there is one
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(
SecurityContext::AUTHENTICATION_ERROR
);
} else {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
return array(
// last username entered by the user
'last_username' => $session->get(SecurityContext::LAST_USERNAME),
'error' => $error,
);
}
}
3. Die View für den Login anlegen
Als nächstes legen wir für diese Action eine View an. Die Datei heisst analog "login.html.twig".
In dieser View erstellen wir dann die Login Form.
{# src/Efi/BlogBundle/Resources/Views/Security/login.html.twig #}
{% extends 'EfiBlogBundle::layout.html.twig' %}
{% block title%}EfiBlogBundle:Security:login{% endblock %}
{% block body %}
{% if error %}
<div>{{ error.message }}</div>
{% endif %}
<div>
<div>
<form action="{{ path("login_check") }}" role="form" method="post">
<h2>Melde dich an</h2>
<input type="text" id="username" name="_username" placeholder="User" value="{{ last_username }}" required autofocus>
<input type="password" id="password" name="_password" placeholder="Password" required>
<label>
<input type="checkbox" value="remember-me"> Login merken
</label>
<button type="submit">Login</button>
</form>
</div>
</div>
{% endblock %}
4. Routing für login_check und logout
Nun müsst ihr noch die Routings eintragen in der routing.yml Datei.
# app/config/routing.yml
login_check:
path: /login_check
logout:
path: /logout
Diese sind wichtig für den Login und Logout. Ersteres checkt ob ihr eingeloggt seid. Letzteres ist für den späteren Logout.
5. Sicherheitseinstellungen (Firewall & Co.)
Benutzer, Gruppen und Rollen sowie generelle Einstellungen zur Sicherheit werden im Symfony-Framework in einer sogenannten Firewall geregelt. Damit alles auch funktioniert müsst ihr ein paar Sachen in eure security.yml eintragen.
# app/config/security.yml
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
dieter: { password: dieterspassword, roles: [ 'ROLE_ADMIN' ] }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/demo/secured/login$
security: false
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: login
check_path: login_check
use_referer: true
logout:
path: /logout
target: /
access_control:
6. Benutzer anlegen
In der Datei security.yml legen wir den Benutzer "john" mit Adminberechtiung an.
# app/config/security.yml
providers:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
john: { password: geheim, roles: [ 'ROLE_ADMIN' ] }
7. Action mit Login schützen
Nun könnt ihr eure Actions für bestimmte Zugriffsrollen regeln.
Das macht man, indem man der Action die @Security Annotation hinzufügt.
// src/bundlename/Controller/controllername.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
In dem nachfolgenden Beispiel schützen wir die Action "administration".
Durch die @Security Annotation stellen wir sicher, dass nur Mitglieder der Rolle "ROLE_ADMIN" hier zugriff haben werden!
/**
* @Route("/adminstration", name="adminstration")
* @Security("is_granted('ROLE_ADMIN')")
* @Template()
*/
public function adminstrationAction()
{
$user = $this->getUser();
return array();
}
Write a comment
1. Neues Symfony 3.4 Projekt anlegen
Wir befinden uns im Ordner workspace
Als erstes laden wir das Programm composer mit curl herunter
Siehe auch http://getcomposer.org/download/
curl -s https://getcomposer.org/installer | php
Jetzt legen wir ein neues Projekt an.
php composer.phar create-project symfony/framework-standard-edition testprojekt "3.4.*"
Siehe auch
http://symfony.com/doc/current/book/installation.html
Die Fragen für die Datei "
parameters.yml" können mit drücken der Enter-Taste einfach bestätigt werden.
Anschließend verschieben wir die comphoser.phar Datei in das neu erstellte Projekt.
mv composer.phar testprojekt
Als Ergebnis haben wir folgende Projektstruktur
2. Apache Webserver einrichten
Wir legen einen neuen "Virtual Host" an, der auf den "web" Ordner des Symfony Projekts zeigt.
<VirtualHost *:80>
ServerName testprojekt.localhost
DocumentRoot "/workspace/testprojekt/web"
DirectoryIndex index.php
<Directory "/workspace/testprojekt/web">
Require all granted
AllowOverride All
Allow from All
Options Indexes FollowSymLinks
</Directory>
</VirtualHost>
Wichtig ist hier der "ServerName" dieser Name muss auflösbar sein.
Damit das funktioniert tragen wir den ServerName in der "hosts" Datei des Rechners ein.
// file: etc/hosts
127.0.0.1 testprojekt.localhost
...
Der Apache Webserver sollte nun einmal neu gestartet werden, damit die neue Konfiguration eingelesen wird.
Jetzt kann die Symfony Anwendung getestet werden. Dazu rufen wir die URL: http://testprojekt.localhost/config.php auf.
3. MySQL Datenbank
Die Verbindungsdaten zur MySQL Datenbank werden in der Datei app/config/parameters.yml hinterlegt
// file: app/config/parameters.yml
parameters:
database_host: 127.0.0.1
database_port: null
database_name: testprojekt
database_user: username
database_password: kennwort
mailer_transport: smtp
mailer_host: 127.0.0.1
mailer_user: null
mailer_password: null
secret: ThisTokenIsNotSoSecretChangeIt
Nachdem die Verbindungsdaten eingetragen sind, kann die Datenbank mit folgendem Kommando erstellt werden:
Achtung: Dazu musst Du natürlich in dem Ordner sein, in dem sich das Framework befindet.
php bin/console doctrine:database:create
// file: app/config/parameters.yml
parameters:
database_driver: pdo_mysql
database_host: 127.0.0.1
database_port: ~
database_name: webprojekt
database_user: username
database_password: kennwort
mailer_transport: smtp
mailer_host: 127.0.0.1
mailer_user: ~
mailer_password: ~
locale: en
secret: ThisTokenIsNotSoSecretChangeIt
Write a comment
1. Default Bundle und DefaultController
Standardmäßig ist nun schon ein Bundle AppBundle im Ordner src vorhanden, welches einen DefaultController besitzt der sich in src/AppBundle/Controller/DefaultController.php befindet.
/**
* @Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
return $this->render('default/index.html.twig', [
'base_dir' => realpath($this->getParameter('kernel.project_dir')).DIRECTORY_SEPARATOR,
]);
}
Wir ändern die Action bzw. function indexAction nun wie folgt ab um für unser Beispiel einen Parameter mit einem beliebigen Text anzuzeigen:
/**
* @Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
return $this->render('default/index.html.twig',
[
'exampleParam1' => $request->get('example1'),
]
);
}
2. Das Standard Twig Layout
Im Ordner app/Resources/views/default befindet sich das Standard Twig Layout base.html.twig.
Für CSS und JavaScript verwenden wir das
Bootstrap Framework welches uns auch "Responsive Design" für Smartphones und Tablets bietet.
2.1 Bootstrap Framework laden und im Ordner web platzieren
Das heruntergeladene bootstrap wird nun in wie unten zu sehen als neuer Ordner im Ordner web eingefügt, sowie alle weiteren Komponenten, die zuvor heruntergeladen werden wurden.
2.2 Eigene CSS Anpassungen
Für unsere eigenen CSS Anpassungen legen wir die Datei
web/css/main.css an.
Der Inhalt sieht wie folgt aus:
/* file: web/css/main.css */
body {
padding-bottom: 30px;
padding-top: 70px;
}
2.3 Twig-Standardlayout einrichten
Die Datei base.html.twig anpassen.
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Welcome!{% endblock %}</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" type="image/x-icon" href="/{{ asset('favicon.ico') }}" />
<!-- Bootstrap CSS -->
<link rel="stylesheet" href='{{ asset('bootstrap/css/bootstrap.min.css') }}'>
<link rel="stylesheet" href='{{ asset('narrow-jumbotron/narrow-jumbotron.css') }}'>
<!-- main css -->
<link rel="stylesheet" href='{{ asset('css/main.css') }}'>
{% block stylesheets %}{% endblock %}
</head>
<body>
<div class="container">
<header class="header clearfix">
<nav>
<ul class="nav nav-pills float-right">
<li class="nav-item">
<a class="nav-link active" href="/{{ path('homepage') }}">
Home
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
Page 1
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
Page 1
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
Contact
</a>
</li>
</ul>
</nav>
<h3 class="text-muted">{% block projektName %}Project name{% endblock %}</h3>
</header>
{% block body %}{% endblock %}
</div>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src='{{ asset('jquery/jquery-3.3.1.min.js') }}'></script>
<script src='{{ asset('popper/popper.min.js') }}'></script>
<script src='{{ asset('bootstrap/js/bootstrap.min.js') }}'></script>
{% block javascripts %}{% endblock %}
</body>
</html>
2.4 Die default View anpassen
Damit wir unsere Seite testen können passen wir zum Schluss noch die vom Bundle erstellte Default-View an.
{# file: src/Resources/views/default/index.html.twig #}
{% extends 'base.html.twig' %}
{% block title 'Efi Blog' %}
{% block body %}
<h1>Hello {{ exampleParam1 }}! </h1>
{% endblock %}
ACHTUNG! Das Default-Twig Template erwartet einen Parameter
exampleParam1 deshalb haben wir diesen zuvor hinzugefügt!
Wenn man keine Parameter übergeben will bzw. keine erwartet werden, kann man in entsprechender Action den array( ... ) einfach weglassen oder lediglich [] schreiben.
return $this->render('default/index.html.twig');
oder
Write a comment
Vorwort
Es lohnt sich immer im Vorfeld einen Blick in den Befehlsumfang des Symfony-Frameworks zu werfen. Das erreicht man in dem man das Kommando
php bin/console
aufruft. Es werden dann alle Befehle aufgelistet!
Jedes Kommando kann wiederum mit dem help Parameter zusätzlich inspiziert werden.
# php bin/console help generate:controller
Usage:
generate:controller [options]
Options:
--controller=CONTROLLER The name of the controller to create
--route-format=ROUTE-FORMAT The format that is used for the routing (yml, xml, php, annotation) [default: "annotation"]
--template-format=TEMPLATE-FORMAT The format that is used for templating (twig, php) [default: "twig"]
--actions=ACTIONS The actions in the controller (multiple values allowed)
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
-e, --env=ENV The environment name [default: "dev"]
--no-debug Switches off debug mode
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Help:
The generate:controller command helps you generates new controllers
inside bundles.
By default, the command interacts with the developer to tweak the generation.
Any passed option will be used as a default value for the interaction
(--controller is the only one needed if you follow the conventions):
php bin/console generate:controller --controller=AcmeBlogBundle:Post
If you want to disable any user interaction, use --no-interaction
but don't forget to pass all needed options:
php bin/console generate:controller --controller=AcmeBlogBundle:Post --no-interaction
Every generated file is based on a template. There are default templates but they can
be overridden by placing custom templates in one of the following locations, by order of priority:
BUNDLE_PATH/Resources/SensioGeneratorBundle/skeleton/controller
APP_PATH/Resources/SensioGeneratorBundle/skeleton/controller
You can check https://github.com/sensio/SensioGeneratorBundle/tree/master/Resources/skeleton
in order to know the file structure of the skeleton
1. Controller anlegen
Für die statischen Seiten "Page1 und Page2" legen wir eine gemeinsame Controller-Klasse an.
Diese Controller-Klasse muss dem entsprechenden Bundle zugeordnet werden!
In unserem Fall ist dies lediglich das bereits erstellte Bundle AppBundle.
# php bin/console generate:controller --no-interaction --controller=AppBundle:Articles
Man kann das ganze auch interaktiv generieren lassen, indem man die Option --no-interaction weglässt.
Jedoch kann es hierbei möglicherweise zu falsch generierten Pfaden führen, da vermutlich nich alles angepasst wurde.
Da standardmäßig aber alles was wir benötigen, kann ruhig darauf verzichtet werden.
Es wurde jetzt eine neue Datei mit Namen "ArticlesController.php" im Ordner src/AppBundle/Controller erstellt.
In diese Datei fügen wir jetzt die Action für unsere erste Page ein:
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
class ArticlesController extends Controller
{
public function page1Action()
{
return $this->render('',
array(
// ...
)
);
}
}
2. View anlegen
Analog zu der Action "page1Action" soll es jetzt eine View geben.
Hierzu erstellen wir im Verzeichnis src/AppBundle einen Unterordner "Resources", darin einen Ordner "views" und zum Schluss darin einen Ordner mit dem Namen "Articles".
Darin legen wir eine Twig-Template Datei mit dem Namen "page1.html.twig" an!
Der Inhalt der Page1 kann innerhalb des body Blocks beliebig hinzugefügt werden.
Wichtig ist hierbei die Angabe: {% extends "base.html.twig" %} die dem Template sagt von welchem Layout sie erben soll!
{# page1.html.twig #}
{% extends "base.html.twig" %}
{% block title %}Page 1{% endblock %}
{% block body %}
<h2>Page 1</h2>
Ein bisschen Blindtext kann nicht schaden ...
{% endblock %}
3. Route und Template für die Page1 definieren
Die Verbindung von einem Controller zu der View wird über die sogenannten Routes im Symfony-Framework geregelt. Da wir "annotations" gewählt haben, können wir jetzt die Routes über der Action-Methode angeben!
/**
* @Route("/page1", name="page1")
* @return Response
*/
public function page1Action()
{
return $this->render('@App/Articles/page1.html.twig',
array(
// ...
)
);
}
Über die URL http://testprojekt.localhost/app_dev.php/page1 kann die neue Seite jetzt getestet werden.
Für die zweite Seite (Page2) kann man jetzt die Schritte wiederholen. Hierzu einfach eine weitere Action und ein Twig-Template analog anlegen!
Der gesamte Controller:
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
class ArticlesController extends Controller
{
/**
* @Route("/page1", name="page1")
* @return Response
*/
public function page1Action()
{
return $this->render('@App/Articles/page1.html.twig',
array(
// ...
)
);
}
/**
* @Route("/page2", name="page2")
* @return Response
*/
public function page2Action()
{
return $this->render('@App/Articles/page2.html.twig',
array(
// ...
)
);
}
}
Die zweite Seite (page2)
{# page2.html.twig #}
{% extends "base.html.twig" %}
{% block title %}Page 2{% endblock %}
{% block body %}
<h2>Page 2</h2>
Dies ist unsere zweite Seite ...
{% endblock %}
Die URL für die zweite Seite lautet dann: http://testprojekt.localhost/app_dev.php/page2
Write a comment
In diesem Tutorial wollen wir zeigen, wie man mit dem Symfony-Framework bestimmte Bereiche mit einem Login schützen kann. Dazu benötigt man Benutzer, Gruppen und Zugriffsrollen (ROLES), sowie ein Anmeldeformular das angezeigt wird, wenn ein Benutzer versucht einen URL aufzurufen die einen Login benötigt.
1. Login Controller
Für den Login muss man als erstes einen neuen Controller in Symfony anlegen.
Diesen nennen wir "Security".
# php bin/console generate:controller --controller=AppBundle:Security
2. Login Action anlegen
Als nächstes erstellen wir die loginAction für den Login.
Achtet darauf, dass ihr noch ein paar Klassen mit "use" laden müsst.
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class SecurityController extends Controller
{
const AUTHENTICATION_ERROR = \Symfony\Component\Security\Core\Security::AUTHENTICATION_ERROR;
const LAST_USERNAME = \Symfony\Component\Security\Core\Security::LAST_USERNAME;
/**
* @Route("/login", name="login")
* @param Request $request
* @return Response
*/
public function loginAction(Request $request)
{
$session = $request->getSession();
// get the login error if there is one
if ($request->attributes->has(self::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(
self::AUTHENTICATION_ERROR
);
} else {
$error = $session->get(self::AUTHENTICATION_ERROR);
$session->remove(self::AUTHENTICATION_ERROR);
}
return $this->render('@App/Security/login.html.twig',
array(
// last username entered by the user
'last_username' => $session->get(self::LAST_USERNAME),
'error' => $error,
// ...
)
);
}
}
3. Die View für den Login anlegen
Als nächstes legen wir für diese Action eine View an. Die Datei heisst analog "login.html.twig".
In dieser View erstellen wir dann die Login Form.
{# src/AppBundle/Resources/Views/Security/login.html.twig #}
{% extends 'base.html.twig' %}
{% block title%}AppBundle:Security:login{% endblock %}
{% block body %}
{% if error %}
<div>{{ error.message }}</div>
{% endif %}
<div>
<div>
<form action="{{ path("login_check") }}" role="form" method="post">
<h2>Melde dich an</h2>
<input type="text" id="username" name="_username" placeholder="User" value="{{ last_username }}" required autofocus>
<input type="password" id="password" name="_password" placeholder="Password" required>
<label>
<input type="checkbox" value="remember-me"> Login merken
</label>
<button type="submit">Login</button>
</form>
</div>
</div>
{% endblock %}
4. Routing für login_check und logout
Nun müsst ihr noch die Routings eintragen in der routing.yml Datei.
# app/config/routing.yml
login_check:
path: /secured_area/login_check
logout:
path: /secured_area/logout
Diese sind wichtig für den Login und Logout. Ersteres checkt ob ihr eingeloggt seid. Letzteres ist für den späteren Logout.
5. Sicherheitseinstellungen (Firewall & Co.)
Benutzer, Gruppen und Rollen sowie generelle Einstellungen zur Sicherheit werden im Symfony-Framework in einer sogenannten Firewall geregelt. Damit alles auch funktioniert müsst ihr ein paar Sachen in eure security.yml eintragen.
# app/config/security.yml
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/demo/secured/login$
security: false
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: login
check_path: login_check
use_referer: true
logout:
path: /logout
target: /
access_control:
6. Benutzer anlegen
In der Datei security.yml legen wir den Benutzer "john" mit Adminberechtiung an.
# app/config/security.yml
providers:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
john: { password: geheim, roles: [ 'ROLE_ADMIN' ] }
7. Action mit Login schützen
Nun könnt ihr eure Actions für bestimmte Zugriffsrollen regeln.
Das macht man, indem man der Action die @Security Annotation hinzufügt.
// src/bundlename/Controller/controllername.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
In dem nachfolgenden Beispiel schützen wir die Action "administration".
Durch die @Security Annotation stellen wir sicher, dass nur Mitglieder der Rolle "ROLE_ADMIN" hier zugriff haben werden!
/**
* @Route("/administration", name="administration")
* @Security("is_granted('ROLE_ADMIN')")
* @return Response
*/
public function administrationAction()
{
$user = $this->getUser();
return $this->render('@App/Security/administration.html.twig',
array(
'error' => null;
// ...
)
);
}
Write a comment
Das Ziel
Wir möchten eine einfache Telefonliste anlegen und auf unserer Page anzeigen!
An dieser Stelle empfehlen wir das SQLyog Tool, das man unter
http://code.google.com/p/sqlyog/wiki/Downloads herunterladen kann. Es können natürlich auch der phpMyAdmin oder andere MySQL Tools verwendet werden.
1. Tabellenstruktur (Entity Class)
In Symfony werden Tabellen über Entity Klassen erzeugt. Man kann natürlich auch Tabellen von Hand anlegen und diese dann über "reverse engineering" Technik einlesen.
Mit dem nachfolgenden Kommando wird ein neuer Ordner
Entity in unserem Bundle sowie die Datei
"Phonelist.php" erzeugt!
php bin/console doctrine:generate:entity --entity=AppBundle:Phonelist
Wir legen auch gleich die 3 Felder "vorname, nachname und telefon" an. Das ist nicht zwingend erforderlich spart aber jede Menge Arbeit, wenn man im Vorfeld schon weiß welche Felder man in seiner Tabelle haben möchte. Später können neue Felder manuell in der Klasse hinzugefügt werden.
...
Instead of starting with a blank entity, you can add some fields now.
Note that the primary key will be added automatically (named id).
Available types: array, simple_array, json_array, object,
boolean, integer, smallint, bigint, string, text, datetime, datetimetz,
date, time, decimal, float, binary, blob, guid.
New field name (press <return> to stop adding fields): vorname
Field type [string]:
Field length [255]:
Is nullable [false]:
Unique [false]:
New field name (press <return> to stop adding fields): nachname
Field type [string]:
Field length [255]:
Is nullable [false]:
Unique [false]:
New field name (press <return> to stop adding fields): telefon
Field type [string]:
Field length [255]:
Is nullable [false]:
Unique [false]:
...
2. Die Tabelle erzeugen
Jetzt erstellen wir die Tabelle in unserer MySQL Datenbank mit folgendem Kommando:
php bin/console doctrine:schema:update --force
Das Resultat prüfen wir mit dem sqlYOG.
Bei dieser Gelegenheit kann man auch gleich ein paar Testdaten eingeben!
3. Die Tabelle anzeigen
Wir benötigen einen so genannten CRUD-Controller! CRUD ist die Abkürzung für
Create Read Update und Delete. Der Crud Controller stellt die Verbindung zu unserer Entität dar und gibt die Daten aus der Tabelle an die View weiter.
Mit dem Kommando
doctrine:generate:crud erzeugen wir also einen Controller und die entsprechenden Views.
php bin/console doctrine:generate:crud --entity=AppBundle:Phonelist
Jetzt sollte die Telefonliste über die URL
http://testprojekt.localhost/app_dev.php/phonelist aufrufbar sein. Allerdings stellen wir fest, dass unser Layout noch nicht mit dem neuen Twig-Views verbunden ist. Das holen wir jetzt gleich nach, in dem wir die Dateien in /app/Resources/views/phonelist/ anpassen.
Write a comment
1. Default Route
Beim erstellen des Bundles wurde die Controller Klasse "DefaultController" mit einer index Action angelegt. Diesen Controller wollen wir jetzt für unsere Startseite verwenden!
Beim anlegen des Projekts hat Symfony die function indexAction(Requerst $request) so angelegt, dass man
Ihr Parameter übergeben kann. Da wir für die Startseite keinen Parameter benötigen entfernen wir die $request Variable bei dem Funktionsparameter und auch bei dem Funktions-Rückgabewert (return).
Als Route verwenden wir "/" und den Namen "homepage". Der Name kann später verwendet werden um mit {{ path('homepage') }} im Twig-Template eine URL zu erzeugen.
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
/**
* @Route("/", name="homepage")
* @return Response
*/
public function indexAction()
{
return $this->render('default/index.html.twig');
}
}
2. Das Homepage Template
Zu der Action "index" gibt es im Ordner app/Resources/views/default/ die Datei index.html.twig welche wir jetzt auch anpassen.
Wichtig ist vor allem, das die Variable {{ exampleParam1 }} entfernt wird, da wir ja im Controller diese auch herausgelöscht haben!
{# file: app/Resources/views/default/index.html.twig #}
{% extends 'base.html.twig' %}
{% block title 'Efi Blog' %}
{% block body %}
<h1>Homepage</h1>
{% endblock %}
3. Menüpunkt mit Twig
Jetzt wollen wir noch das die Hyperlinks in unserem Menü funktionieren. Dazu müssen wir die URLs in userer Layout Datei "base.html.twig" einstellen. Twig hat hierzu den Befehl {{ path('routename') }} bzw. {{ url('routenname') }} der uns die entsprechende URL, in unserem Beispiel mit Annotation in der Action angegeben, generiert!
<ul class="nav nav-pills float-right">
<li class="nav-item">
<a class="nav-link {% if (app.request.attributes.get('_route') == 'homepage') %}active{% endif %}"
href='{{ path('homepage') }}'>Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link {% if (app.request.attributes.get('_route') == 'page1') %}active{% endif %}"
href='{{ path('page1') }}'>Page 1</a>
</li>
<li class="nav-item">
<a class="nav-link {% if (app.request.attributes.get('_route') == 'page2') %}active{% endif %}"
href='{{ path('page2') }}'>Page 2</a>
</li>
<li class="nav-item">
<a class="nav-link {% if (app.request.attributes.get('_route') == 'contact') %}active{% endif %}"
href='#contact'>Contact</a>
</li>
</ul>
4. Der technische Hintergrund von app_dev.php und app.php
Die Entwickler-Ansicht wird immer über die Datei app_dev.php aufgerufen. So kann man jetzt schon die Seite über die Url
http://testprojekt.localhost/app_dev.php/ testen. Will man die Produktiv-Ansicht aufrufen, so wird das Apache Module "mod_rewrite" benötigt und muss geladen sein.
# file: httpd.conf
...
LoadModule rewrite_module modules/mod_rewrite.so
...
Die Datei .htaccess sorgt dafür, dass wenn die Frontpage(Startpage) aufgerufen wird, auf die Datei app.php weitergeleitet wird!
# file /web/.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
...
</IfModule>
Ob das Rewrite Module geladen ist, kann man mit der Ausgabe von phpinfo() kontrollieren!
Probleme mit WAMP in der Produktivansicht
Falls die URL http://testprojekt.localhost einen 404 Error ausgibt, so hilft es in der Datei /web/app.php den Parameter false auf true zu setzen und damit den debug mode zu aktivieren!
...
$kernel = new AppKernel('prod', true);
...
4 Comments
1. Neues Symfony 4.4 Projekt anlegen
Wir befinden uns im Ordner workspace
Als erstes laden wir das Programm composer mit curl herunter
Siehe auch http://getcomposer.org/download/
curl -s https://getcomposer.org/installer | php
Es wird mind. php7.1 oder höher benötigt.
2. Apache Webserver einrichten
Wir legen einen neuen "Virtual Host" an, der auf den "public" Ordner des Symfony Projekts zeigt.
<VirtualHost *:80>
ServerName testprojekt.localhost
DocumentRoot "/workspace/testprojekt/public"
DirectoryIndex index.php
<Directory "/workspace/testprojekt/public">
Require all granted
AllowOverride All
Allow from All
FallbackResource /index.php
</Directory>
<Directory /workspace/testprojekt/public/bundles>
FallbackResource disabled
</Directory>
</VirtualHost>
Wichtig ist hier der "ServerName" dieser Name muss auflösbar sein.
Damit das funktioniert tragen wir den ServerName in der "hosts" Datei des Rechners ein.
// file: etc/hosts
127.0.0.1 testprojekt.localhost
...
Der Apache Webserver sollte nun einmal neu gestartet werden, damit die neue Konfiguration eingelesen wird.
Jetzt kann die Symfony Anwendung getestet werden. Dazu rufen wir die URL: http://testprojekt.localhost/ auf.
3. MySQL Datenbank
Die Verbindungsdaten zur MySQL Datenbank werden in der Datei .env per DATABASE_URL hinterlegt.
Der db_user muss existieren.
// file: .env
###> doctrine/doctrine-bundle ###
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# Configure your db driver and server_version in config/packages/doctrine.yaml
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
###< doctrine/doctrine-bundle ###
Nachdem die Verbindungsdaten eingetragen sind, kann die Datenbank mit folgendem Kommando erstellt werden:
Achtung: Dazu musst Du natürlich in dem Ordner sein, in dem sich das Framework befindet.
php bin/console doctrine:database:create
Write a comment
1. Default Bundle und DefaultController
Da Symfony4.4 keinen Controller bei der erstellung eines Projektes erstellt, müssen wir ihn selbst per Command erstellen.
Dafür geben wir folgenden Befehl ein und ändern den ControllerName in default oder einen anderen beliebigen Namen.
php bin/console make:controller ControllerName
Nun ändern wir den Controller unter src/controller wie folgt ab.
/**
* @Route("/", name="homepage")
*/
public function index()
{
return $this->render('default/index.html.twig', [
'exampleParam1' => 'Hello John Doe',
]);
}
2. Das Standard Twig Layout
Im Ordner templates befindet sich das Standard Twig Layout base.html.twig.
Für CSS und JavaScript verwenden wir das
Bootstrap Framework welches uns auch "Responsive Design" für Smartphones und Tablets bietet.
2.1 Bootstrap Framework laden und im Ordner web platzieren
Das heruntergeladene bootstrap wird nun in wie unten zu sehen als neuer Ordner im Ordner public eingefügt, sowie alle weiteren Komponenten, die zuvor heruntergeladen werden wurden.
2.2 Eigene CSS Anpassungen
Für unsere eigenen CSS Anpassungen legen wir die Datei
public/css/cover.css an.
Der Inhalt sieht wie folgt aus:
/*
* Globals
*/
/* Custom default button */
.btn-secondary,
.btn-secondary:hover,
.btn-secondary:focus {
color: #333;
text-shadow: none; /* Prevent inheritance from `body` */
}
/*
* Base structure
*/
body {
text-shadow: 0 .05rem .1rem rgba(0, 0, 0, .5);
box-shadow: inset 0 0 5rem rgba(0, 0, 0, .5);
}
.cover-container {
max-width: 42em;
}
/*
* Header
*/
.nav-masthead .nav-link {
color: rgba(255, 255, 255, .5);
border-bottom: .25rem solid transparent;
}
.nav-masthead .nav-link:hover,
.nav-masthead .nav-link:focus {
border-bottom-color: rgba(255, 255, 255, .25);
}
.nav-masthead .nav-link + .nav-link {
margin-left: 1rem;
}
.nav-masthead .active {
color: #fff;
border-bottom-color: #fff;
}
2.3 Fav-Icons erstellen
2.4 Twig-Standardlayout einrichten
Die Datei base.html.twig anpassen.
<!doctype html>
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="die-efi.de">
<title>{% block title %}Welcome!{% endblock %}</title>
<link href="/{{ asset('bootstrap-5.2.0-dist/css/bootstrap.min.css') }}" rel="stylesheet" >
<!-- Favicons -->
<link rel="apple-touch-icon" href="/{{ asset('favicons/apple-touch-icon.png') }}" sizes="180x180">
<link rel="icon" href="/{{ asset('favicons/favicon-32x32.png') }}" sizes="32x32" type="image/png">
<link rel="icon" href="/{{ asset('favicons/favicon-16x16.png') }}" sizes="16x16" type="image/png">
<link rel="manifest" href="/{{ asset('favicons/site.webmanifest')}} ">
{# <link rel="mask-icon" href="/docs/5.2/assets/img/favicons/safari-pinned-tab.svg" color="#712cf9">#}
<link rel="icon" href="/{{ asset('favicons/favicon.ico') }}">
<meta name="theme-color" content="#712cf9">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.b-example-divider {
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.b-example-vr {
flex-shrink: 0;
width: 1.5rem;
height: 100vh;
}
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.nav-scroller {
position: relative;
z-index: 2;
height: 2.75rem;
overflow-y: hidden;
}
.nav-scroller .nav {
display: flex;
flex-wrap: nowrap;
padding-bottom: 1rem;
margin-top: -1px;
overflow-x: auto;
text-align: center;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
</style>
<link href="/{{ asset('css/cover.css') }}" rel="stylesheet">
{# Run `composer require symfony/webpack-encore-bundle`
and uncomment the following Encore helpers to start using Symfony UX #}
{% block stylesheets %}
{#{{ encore_entry_link_tags('app') }}#}
{% endblock %}
{% block javascripts %}
{#{{ encore_entry_script_tags('app') }}#}
{% endblock %}
</head>
<body class="d-flex h-100 text-center text-bg-dark">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
<header class="mb-auto">
<div>
<h3 class="float-md-start mb-0">dieefi</h3>
<nav class="nav nav-masthead justify-content-center float-md-end">
<a class="nav-link fw-bold py-1 px-0 active" aria-current="page" href="/{{ path('homepage') }}">Home</a>
<a class="nav-link fw-bold py-1 px-0" href="/{{ path('seite1') }}">Seite 1</a>
<a class="nav-link fw-bold py-1 px-0" href="/{{ path('seite2') }}">Seite 2</a>
</nav>
</div>
</header>
<main class="px-3">
{% block body %}{% endblock %}
</main>
<footer class="mt-auto text-white-50">
<p>wir sind die-efi</p>
</footer>
</div>
</body>
</html>
2.4 Die index html anpassen
Damit wir unsere Seite testen können passen wir zum Schluss noch die vom Bundle erstellte Default-View an.
{# file: templates/default/index.html.twig #}
{% extends 'base.html.twig' %}
{% block title 'Efi Blog' %}
{% block body %}
<h1>{{ exampleParam1 }}! </h1>
{% endblock %}
ACHTUNG! Das Default-Twig Template erwartet einen Parameter
exampleParam1 deshalb haben wir diesen zuvor hinzugefügt!
Wenn man keine Parameter übergeben will bzw. keine erwartet werden, kann man in entsprechender Funktion den array( ... ) einfach weglassen oder lediglich [] schreiben.
return $this->render('default/index.html.twig');
oder
Write a comment
Vorwort
Es lohnt sich immer im Vorfeld einen Blick in den Befehlsumfang des Symfony-Frameworks zu werfen. Das erreicht man in dem man das Kommando
php bin/console
aufruft. Es werden dann alle Befehle aufgelistet!
Jedes Kommando kann wiederum mit dem help Parameter zusätzlich inspiziert werden.
php bin/console help make:controller
1. Controller erstellen
Nun wollen wir Zwei neue Seiten erstellen. Dafür benutzen wir am besten einen neuen Controller.
php bin/console make:controller sites
Da wir aber zwei oder mehr Seiten haben wollen, müssen wir in dem Controller noch eine Funktion hinzufügen.
Um die Funktionen später besser zu erkennen, nennen wir sie seite1 und seite2.
Zudem ändern wir die Routen ab
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class SitesController extends AbstractController
{
/**
* @Route("/seite1", name="seite1")
*/
public function seite1()
{
return $this->render('sites/seite1.html.twig');
}
/**
* @Route("/seite2", name="seite2")
*/
public function seite2()
{
return $this->render('sites/seite2.html.twig');
}
}
2. View anlegen
Bei dem erstellen eines Controllers wird nur eine twig Datei angelegt, wir brauchen aber 2.
Dafür gehen wir in den Ordner templates/sites und ändern die bestehende index.html.twig in seite1.html.twig um.
Der Name bleibt jedem selbst überlassen, jedoch haben wir beim Controller bearbeiten die seite1.html.twig als zu aufrufende Datei festegelgt.
Zusätzlich erstellen wir eine seite2.html.twig Datei im gleichen Ordner.
Nun bearbeiten wir beide und machen sie etwas übersichtlicher:
{% extends 'base.html.twig' %}
{% block title %}Hello SitesController!{% endblock %}
{% block body %}
<div>
<h1>Ich bin Seite 1 !!!</h1>
</div>
{% endblock %}
Bei seite2 sollte natürlich auch Seite 2 stehen.
Jetzt können wir diese 2 Seiten über testprojekt.localhost/seite1 bzw. seite2 erreichen.
3. Hyperlinks einfügen
Zum schluss wollen wir noch unsere Seiten miteinander verbinden.
Dazu gehen wir in die base.html.twig Datei und ändern den Body wie folgt ab.
<ul class="nav nav-pills float-right">
<li class="nav-item">
<a class="nav-link" href='{{ path('homepage') }}'>Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href='{{ path('seite1') }}'>Seite 1</a>
</li>
<li class="nav-item">
<a class="nav-link" href='{{ path('seite2') }}'>Seite 2</a>
</li>
</ul>
4. prod, dev und test
Anders als in Symfony 3 können wir nun nicht mehr mit /app_dev auf unser dev environment zugreifen, sondern müssen dies in der .env Datei tun.
In der .env Datei gibt es folgenden Block.
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=***
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
#TRUSTED_HOSTS='^localhost|example\.com$'
###< symfony/framework-bundle ###
Wichtig ! APP_SECRET muss IMMER vor anderen versteckt sein, denn durch diese Zeichenkombination wird das Projekt zusätzlich verschlüsselt.
Nun können wir ganz einfach das dev hinter APP_ENV durch prod oder test austauschen, um das environment zu wechseln
Write a comment
Das Ziel
Wir möchten eine einfache Telefonliste anlegen und auf unserer Page anzeigen!
Bevor man anfängt, schaut man in die Composer.json Datei rein.
Und ändert es wie folgt ab:
"doctrine/doctrine-bundle": "~1.12",
"doctrine/orm": "~2.7",
1. Tabellenstruktur (Entity Class)
In Symfony werden Tabellen über Entity Klassen erzeugt. Man kann natürlich auch Tabellen von Hand anlegen und diese dann über "reverse engineering" Technik einlesen.
Mit dem nachfolgenden Kommando wird eine neue Datei
"PhoneList.php" sowie eine Datei "
PhoneListRepository.php" in unserem src Verzeichnis erzeugt!
php bin/console make:entity PhoneList
Wir legen auch gleich die 3 Felder "vorname, nachname und telefon" an. Das ist nicht zwingend erforderlich spart aber jede Menge Arbeit, wenn man im Vorfeld schon weiß welche Felder man in seiner Tabelle haben möchte. Später können neue Felder manuell in der Klasse hinzugefügt werden.
created: src/Entity/PhoneList.php
created: src/Repository/PhoneListRepository.php
Entity generated! Now let's add some fields!
You can always add more fields later manually or by re-running this command.
New field name (press <return> to stop adding fields): vorname
Field type [string]:
Field length [255]:
Is nullable [false]:
New field name (press <return> to stop adding fields): nachname
Field type [string]:
Field length [255]:
Is nullable [false]:
New field name (press <return> to stop adding fields): telefon
Field type [string]:
Field length [255]:
Is nullable [false]:
...
2. Die Tabelle erzeugen
Jetzt erstellen wir die Tabelle in unserer MySQL Datenbank mit folgendem Kommando:
php bin/console make:migration
Folgende Ausgabe sagt uns, dass eine Datei mit den benötigten SQL Befehlen erstellt wurde:
Next: Review the new migration "src/Migrations/Version20190425080023.php"
Then: Run the migration with php bin/console doctrine:migrations:migrate
In der Migrations Datei können wir nun auch änderungen vornehmen, welche wir später mit dem Befehl "
doctrine:migrations:migrate" einspielen. Mit dem oben genannten Befehl werden die verschiedenen php Dateien in dem
Migrations Ordner überprüft und ausgeführt. Es wird allerdings nur ausgeführt, was in der Datenbank in der "
migration_versions" Tabelle noch nicht hinterlegt ist.
Nachdem wir den obigen Befehl ausgeführt haben, können wir das Resultat in unserem jeweiligen Datenbank Tool einsehen und sollte wie folgt aussehen.
Bei dieser Gelegenheit können wir auch gleich ein paar Testdaten eingeben!
3. Die Tabelle anzeigen
Wir benötigen einen so genannten CRUD-Controller! CRUD ist die Abkürzung für Create Read Update und Delete. Der Crud Controller stellt die Verbindung zu unserer Entität dar und gibt die Daten aus der Tabelle an die View weiter.
Mit dem Kommando make:crud erzeugen wir also einen Controller und die entsprechenden Views.
php bin/console make:crud PhoneList
Ist dies nicht der Fall, gehen wir in den PhoneListController im src Ordner. Hier sehen wir überhalb der
class eine Route, diese muss aufgerufen werden. Hierbei ist wichtig, wird eine Entity mit Großbuchstaben erstellt, so wie wir es getan haben, wird die Rute automatisch mit "/" unterteilt.
Zudem stellen wir fest, dass unser Layout noch nicht mit dem neuen Twig-Views verbunden ist. Das holen wir jetzt gleich nach, indem wir die Dateien in /templates/phone_list/ anpassen.
3 Comments
1. Benutzertabelle erstellen
Nun möchten wir auf unserer Seite eine funktionsfähige Login-Seite hinzufügen, bei der sich Benutzer erst anmelden müssen, bevor Sie die Inhalte der Seite ansehen können.
Wir brauchen zunächst eine Tabelle in unserer Datenbank, in der wir unsere Benutzer speichern können. Dafür gibt es folgendes Kommando:
php bin/console make:user
Dort muss nun der Name der Klasse/Tabelle eingegeben werden. Hierfür eignet sich z.B. der Name User
Die weiteren Fragen können einfach mit Enter bestätigt werden.
Im Ordner src/Entity befindet sich nun die Datei User.php
Damit ist die Benutzer-Klasse vollständig für den Login vorbereitet!
Nun führen wir die folgenden beiden Commands aus, um in unserer Datenbank eine Tabelle zu erstellen, in der später die Benutzer gespeichert werden können.
php bin/console make:migration
php bin/console doctrine:migrations:migrate
Falls du mit einem Tool wie MySQL-Workbench oder Dbeaver nun deine Datenbank betrachtest, wirst du die Tabelle „user“ mit den Attributen „email“, „password“ und „roles“ entdecken.
2. Login-Maske erstellen
Nun fehlt uns nur noch eine Anmeldemaske und die Logik. Hier hilft uns Symfony. Dazu führen wir das folgende Kommando aus:
php bin/console make:auth
Es werden einige Fragen gestellt, mit denen wir unseren Login so generieren lassen können, wie es uns gefällt. Für einen Standard-Login können die Fragen wie unten stehend beantwortet werden.
What style of authentication do you want?:
[0] Empty authenticator
[1] Login form authenticator
> 1
The class name of the authenticator to create:
> LoginFormAuthenticator
Choose a name for the controller class:
> SecurityController
Enter the User class that you want to authenticate:
> App\Entity\User
Do you want to generate a '/logout' URL?:
> yes
Damit wurde nun ein Login-Template und sichere und funktionsfähige Login-Logik autogeneriert!
Final gehen wir nun in src/Security/LoginFormAuthenticator.php
In der Funktion onAuthenticationSuccess(…) muss die letzte Zeile
throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
ersetzt werden durch
return new RedirectResponse($this->urlGenerator->generate('homepage'));
Damit bestimmen wir auf welche URL ein Benutzer nach dem erfolgreichen Login weitergeleitet werden soll! In diesem Falle „homepage“.
3. Seite logingeschützt machen
Nun können wir noch einstellen, dass die Menüpunkte erst aufgerufen werden können, wenn man angemeldet ist.
Dazu öffnen wir die Datei config/packages/security.yml
Wir können selber konfigurieren, auf welche Route wir nach dem Logout weitergeleitet werden sollen. Dafür setzen wir unter „logout“, den Wert „target“ auf den Namen unserer Route, wie er im Controller steht.
logout:
path: app_logout
# Bei target können wir eintragen auf welche Seite wir beim Logout weitergeleitet werden.
target: homepage
Ganz unten gibt es „access_control“. Dies ändern wir wie folgt ab:
access_control:
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY } bedeutet, dass die URL /login von jedem aufgerufen werden kann. Dazu muss man nicht angemeldet sein
- { path: ^/, roles: ROLE_USER } bedeutet, dass alle anderen URLs (außer die explizit aufgeführten) einen Login benötigen.
Nun wird uns jeder Versuch Home, Seite1 und Seite2 aufzurufen, zum Login weiterleiten!
Unsere Seite ist nun login-geschützt! Wenn du nun versuchst eine der Seiten aufzurufen, wirst du zur Loginmaske weitergeleitet.
4. Angemeldeten Benutzer begrüßen & Logout-Button einfügen
Wir können außerdem eine Begrüßung für den angemeldeten Benutzer und Logout-Button hinzufügen.
In unserer templates/base.html.twig sind wir in der Lage unser Menü mit den Punkten „Home“, „Seite 1“ und „Seite 2“ um ein „Hallo, Benutzer!“ und einen Logout-Button zu erweitern!
Unsere Datei könnte dann zum Beispiel auszugsweise so aussehen:
<div class="container">
<header class="header clearfix">
<nav>
<ul class="nav nav-pills float-right">
<li class="nav-item">
<a class="nav-link" href='{{ path('homepage') }}'>Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href='{{ path('seite1') }}'>Seite 1</a>
</li>
<li class="nav-item">
<a class="nav-link" href='{{ path('seite2') }}'>Seite 2</a>
</li>
{# Logout Button nur anzeigen, wenn der Benutzer angemeldet ist!#}
{% if app.user %}
<li class="nav-item">
<a class="nav-link" href='{{ path('app_logout') }}'>Logout</a>
</li>
{% endif %}
</ul>
</nav>
<h3 class="text-muted">{% block projektName %}Project name{% endblock %}</h3>
{# Nur anzeigen, wenn der Benutzer angemeldet ist!#}
{% if app.user %}
<h4>Hallo, {{ app.user.username }}</h4>
{% endif %}
</header>
{% block body %}{% endblock %}
</div>
Mit {{ app.user }} können wir in unserem Template auf den angemeldeten Benutzer und seine Attribute zugreifen.
Wenn wir also {{ app.user.username }} ausführen, können wir den Benutzernamen, in unserem Fall die E-Mail, des angemeldeten Benutzer auslesen.
Nun haben wir aber noch kein Benutzerkonto mit dem wir uns anmelden können.