{"id":508,"date":"2019-12-13T15:57:22","date_gmt":"2019-12-13T14:57:22","guid":{"rendered":"https:\/\/wiki.ad-libitum.info\/?page_id=508"},"modified":"2020-09-22T11:57:03","modified_gmt":"2020-09-22T09:57:03","slug":"symfony-projekt","status":"publish","type":"page","link":"https:\/\/wiki.ad-libitum.info\/?page_id=508","title":{"rendered":"Symfony-Projekt"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Mit dem composer das Projekt erstellen. Dazu auf DOS-Ebene ins htdocs-Verzeichnis gehen und den Befehl <code>composer create-project symfony\/skeleton zielpfad<\/code> eingeben. Zielpfad ist das Verzeichnis innerhalb von htdocs, in dem das Projekt erstellt werden soll.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Im Verzeichnis public muss eine .htaccess erstellt werden. Die bekommt folgenden Inhalt:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;IfModule mod_rewrite.c&gt;\n    RewriteEngine On\n\n    # Determine the _RewriteBase automatically and set is \n    # as environment variable\n    RewriteCond %{REQUEST_URI}::$1 ^(\/.+)\/(.*)::\\2$\n    RewriteRule ^(.*) - [E=BASE:%1]\n\n    # If the requested filename existes, simply serve it.\n    # We only want to let Apache serve files and not directories.\n    RewriteCond %{REQUEST_FILENAME} -f\n    RewriteRule .? - [L]\n\n    # Rewrite all other queries to the front controller.\n    RewriteRule .? %{ENV:BASE}\/index.php [L]\n&lt;\/IfModule&gt;<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Subversion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Damit die Versionierung klappt, muss Subversion eingerichtet werden. Dazu in PHPStorm unter VCS \/ Import into Version Control aufrufen und in das gew\u00fcnschte Repository exportieren. Anschlie\u00dfend gleich wieder mit VCS \/ Get from Version Control importieren, damit \u00c4nderungen erkannt werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dann noch im Dateiexplorer \u00fcber das Kontextmen\u00fc die nicht erforderlichen Verzeichnisse von Subversion ausnehmen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zugriff auf die neue Site<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr den Zugriff auf die Site sind zwei Anpassungen erforderlich:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In der <code>httpd-vhosts.conf<\/code> m\u00fcssen die folgenden Zeilen eingef\u00fcgt werden, wobei die Parameter hinter DocumentRoot und ServerName nat\u00fcrlich <b>angepasst<\/b> werden m\u00fcssen.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;virtualhost *:80=\"\"&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;DocumentRoot \"C:\\xampp\\htdocs\\symfony\\public\"\n&nbsp;&nbsp;&nbsp;&nbsp;ServerName symphony.test\n&lt;\/virtualhost&gt;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Anschlie\u00dfend muss XAMPP neu gestartet werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die zweite \u00c4nderung muss auf denjenigen PCs innerhalb des lokalen Netzes durchgef\u00fchrt werden, auf denen die Seite angezeigt werden soll. Und zwar in der Datei <code>C:\\Windows\\System32\\drivers\\etc\\hosts<\/code>. Dort muss f\u00fcr die neue Site eine neue Zeile eingef\u00fcgt werden: <code>192.168.0.12        adlibitum.test<\/code>. Die IP ist dabei die IP des XAMPP-Servers und der zweite Parameter derjenige, der in der <code>httpd-vhosts.conf<\/code> als ServerName eingetragen worden ist.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Profiler<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Der Profiler liefert viele interessante Informationen zum Programm im aktuellen Status zur\u00fcck. Das ist die Statuszeile am unteren Bildschirmrand.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">composer require profiler --dev<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Logger<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Der Logger liefert viele zus\u00e4tzliche Informationen zum Programm im aktuellen Status zur\u00fcck.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">composer require logger<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Debugger installieren<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In das Verzeichnis mit der neuen Internetsite wechseln.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">composer require debug --dev\ncomposer unpack debug<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Der zweite Befehl dient dazu, das Paket in die einzelnen Komponenten  aufzul\u00f6sen. Damit k\u00f6nnen diese gezielt an die ben\u00f6tigte Version angepasst oder entfernt werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Router installieren<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">composer require annotations<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Das sorgt auch daf\u00fcr, dass die Use-Statements automatisch erg\u00e4nzt werden, falls erforderlich.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Security Checker installieren<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Um die Packages auf Sicherheitslecks pr\u00fcfen zu k\u00f6nnen, kann der sec-checker verwendet werden.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">composer require sec-checker --dev<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Damit wird auch erreicht, dass nach jeder Installation eines Pakets ein Sicherheitscheck durchgef\u00fchrt wird. Um eine Pr\u00fcfung ohne Installation durchzuf\u00fchren: <code>composer install<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Twig installieren<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn HTML-Templates verwendet werden sollen, wird Twig ben\u00f6tigt:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">composer require twig<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Damit das dann auch genutzt werden kann, muss der Controller den AbstractController extenden: <code>class XxxController extends AbstractController<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Maker-Bundle<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Dieses Bundle wird f\u00fcr zahlreiche Funktionen ben\u00f6tigt.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">composer require symfony\/maker-bundle --dev<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Datenbanktreiber<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mit Doctrine sind Datenbankfunktionen m\u00f6glich.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">composer require doctrine<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Konfiguriert wird in der .env: <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">DATABASE_URL=mysql:\/\/db_user:db_password@127.0.0.1:3306\/db_name?serverVersion=mariadb-10.4.14<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Die mariadb ist wichtig, sonst kommt der Fehler sync-metadata-storage soll gestartet werden. Unter Umst\u00e4nden sind auch in der <code>config\\packages\\doctrine.yaml<\/code> Einstellungen erforderlich.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Anschlie\u00dfend kann auf DOS-Ebene die Datenbank mit <code>php bin\/console doctrine:database:create<\/code> erstellt werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tabellen werden mit <code>php bin\/console make:entity<\/code> erstellt. Anschlie\u00dfend mit <code>php bin\/console make:migration<\/code> eine Migration erstellen. Diese im Verzeichnis migrations pr\u00fcfen, bevor sie mit <code>php bin\/console doctrine:migrations:migrate<\/code> ausgef\u00fchrt wird.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Debug-Infos<\/h2>\n\n\n\n<p>Um an beliebiger Stelle im Code Debugginginfos zu bekommen, kann <code>dump($var);<\/code> eingebaut werden. Das erzeugt in der Debugging-Statuszeile ein neues Symbol: ein Fadenkreuz. \u00dcber dieses k\u00f6nnen die Inhalte der Variablen betrachtet werden. Die Verwendung ist auch in twig-Dateien m\u00f6glich. Dort einfach <code>{{ dump() }}<\/code> einf\u00fcgen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unter Windows erfolgt der Aufruf der Konsole mit <code>php bin\/console<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Routing<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Um das Routing in den Kommentarblock zu schreiben, m\u00fcssen Annotations installiert sein: <code>composer require annotations<\/code>. Im Docbloc \u00fcber der Funktion dann <code>@Route(\"\/\")<\/code> einf\u00fcgen, wobei zwischen den Anf\u00fchrungszeichen die Route steht. Im Beispiel die Route f\u00fcr index.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dar\u00fcber hinaus ist es sinnvoll, den Namen f\u00fcr die Route selbst festzulegen. Dadurch kann der Controller \u00fcber ein und denselben Namen referenziert werden, auch wenn der Name der Funktion ge\u00e4ndert wird. Um den Namen von Hand festzulegen, einfach einen zweiten Parameter mit angeben:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/**<br><\/em><em> * <\/em><strong><em>@Route<\/em><\/strong><em>(\"\/\", name=\"app_homepage\")<br><\/em><em> *\/<br><\/em>public function homepage()<br>{<br>    return new Response(\"Hallo Homepage!\");<br>}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Zum Aufrufen dieser Router dient dann <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">href=\"{{ path('app_homepage') }}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Erwartet der Controller Parameter, so sind diese in Form eines Array zus\u00e4tzlich einzutragen: <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">href=\"{{ path('article_show',{slug:'nur-ein-test'}) }}\"<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">HTML-Vorlagen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">HTML-Vorlagen k\u00f6nnen dank Twig verwendet werden: <code>composer require twig<\/code>. Die Templates daf\u00fcr kommen in das Verzeichnis templates.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Damit Twig genutzt werden kann, muss die Controllerklasse erweitert werden: <code>extends AbstractController<\/code>. Eingebunden wird dann mit dem Befehl <code>return $this-&gt;render()<\/code>. Der Aufruf erwartet zwei Parameter: der erste ist die zu verwendende Vorlage, der zweite sind zu \u00fcbergebenden Parameter in Form eines Arrays.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/**\n * <\/em><strong><em>@Route<\/em><\/strong><em>(\"\/fahrten\/{slug}\")\n *\/\n<\/em>public function fahrten($slug)\n{\nreturn $this-&gt;render('homepage\/base.html.twig',[\n\"title\" =&gt; ucwords(str_replace(\"-\", \" \", $slug)),\n]);\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Assets<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mit Assets kann man im Code automatische Referenzen einbauen. Zur Nutzung mit dem Befehl <code>composer require asset<\/code> installieren. Damit kann man dann in Twigdateien folgendes verwenden: <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;link rel=\"stylesheet\" href=\"{{ asset('css\/styles.css') }}\"&gt;<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Markdown<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Um per Twig auszugebenden Text zu formatieren, muss ein Markdownbundle installiert werden: <code>composer require knplabs\/knp-markdown-bundle<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u00dcbersetzungen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Installieren mit <code>composer require symfony\/translation<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Im YAML-Format werden die Strings OHNE &#8220; eingegeben. Das Leerzeichen nach dem Doppelpunkt zwischen den Sprachen ist wichtig!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Formulare<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Installieren mit <code>composer require form<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Zun\u00e4chst eine Klasse f\u00fcr das Formular erstellen. Diese muss Bedingungen erf\u00fcllen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>NAMExFormType extends AbstractType<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Der Name muss mit FormType beendet werden und die Klasse muss die oben genannte Klasse erweitern. Darin dann eine Funktion erstellen (Strg+O):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>public function buildForm() {<br>    $builder<br>        -&gt;add('NameDBFeld') \/\/so oft wie erforderlich<br>     ;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Im Kontroller wird dann das Formular gerendert:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>$form = $this-&gt; createForm(NAMExFormType::class);<br>return $this-&gt; render('Verzeichnis\/NAMEz.htlm.twig', [<br>    'NAMEy' =&gt; $form-&gt;createView(),<br>])<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Im Template, wird schnell erstellt, indem man im Kontroller den Cursor auf den Templatenamen setzt und Alt+Enter dr\u00fcckt, dann folgendes einf\u00fcgen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>{{ form_start (NAMEy) }}<br>    {{form_widget(NAMEy) }}<br>{{ form_end (NAMEy) }}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Um die Formulardaten zu verarbeiten, den Kontroller wie folgt erweitern:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public function new(EntityManagerInterface $em, Request $request) \/\/httpFoundation\n...\n{\n    $form = $this-&gt;createForm(ArticleFormType::class);\n\n    $form-&gt;handleRequest($request);\n    if ($form-&gt;isSubmitted() &amp;&amp; $form-&gt;isValid()) {\n        $data = $form-&gt;getData();\n        $article = new Article();\n        $article-&gt;setTitle($data['title']);\n        $article-&gt;setContent($data['content']);\n        $article-&gt;setAuthor($this-&gt;getUser());\n\n        $em-&gt;persist($article);\n        $em-&gt;flush();\n\n        $this-&gt;addFlash('erfolg', \"Hat geklappt!\");\n\n        return $this-&gt;redirectToRoute('admin_article_list');\n    }\n\n    return $this-&gt;render('article_admin\/new.html.twig', [\n        'articleForm' =&gt; $form-&gt;createView(),\n    ]);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Damit der Anwender wei\u00df, dass es geklappt hat, soll eine entsprechende Meldung angezeigt werden. Dazu die DB-Klasse erweitern:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$this-&gt;addFlash('erfolg', \"Meldung\");<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Sowohl erfolg als auch Meldung sind beliebige Texte. Gespeichert wird in der Session und die Inhalte k\u00f6nnen nur <strong>1x<\/strong> gelesen werden, weil sie beim Lesen gleich gel\u00f6scht werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Zur Anzeige der Meldung im Twig-Template einfach einbauen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{% for message in app.flashes('erfolg') %}\n    {{ message }}\n{% endfor %}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Um eine solche Variable zu pr\u00fcfen, <strong>ohne<\/strong> sie zu l\u00f6schen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{{ app.session.flashBag.peek('erfolg')|length &gt; 0 ? '' : 'mb-5' }}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Man kann sich das Leben auch vereinfachen, indem man das Formular an die DB-Klasse bindet. Dann wird nicht nur der Feldtype automatisch erkannt, auch die manuelle Zuweisung der Formularfelder zu den DB-Feldern kann entfallen. Dazu in der Formularklasse eine neue Funktion einbauen &#8211; Strg+O \/ Configure Options:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public function configureOptions(OptionsResolver $resolver)<br>{<br>    $resolver-&gt;setDefaults([<br>        'data_class' =&gt; Article::class<br>    ]);<br>}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Im Kontroller zur DB-Klasse k\u00f6nnen dann die manuellen Zuweisungen entfallen. Statt dessen wird eine Variable f\u00fcr die DB-Klasse verwendet:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/** <\/em><strong><em>@var <\/em><\/strong><em>Article <\/em><em>$article <\/em><em>*\/<br><\/em>$article = $form-&gt;getData();<br>$article-&gt;setAuthor($this-&gt;getUser());<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Das Article muss dabei vom Typ App\\Entity sein.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Formulare k\u00f6nnen auch automatisch mit Formatvorlagen verkn\u00fcpft werden. Dazu muss in config\\packages die twig.yaml angepasst werden:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">form-themes:<br>    - 'bootstrap_4_layout.html.twig'<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Welche Themes es gibt, kann man bei <a rel=\"noreferrer noopener\" href=\"https:\/\/symfony.com\/doc\/current\/form\/form_themes.html\" target=\"_blank\">Symfony<\/a> nachschauen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Feldtypen k\u00f6nnen auch von Hand angepasst werden. Infos gibt es bei <a rel=\"noreferrer noopener\" href=\"https:\/\/symfony.com\/doc\/current\/forms.html\" target=\"_blank\">Symfony<\/a>. Infos zu den Formattypen gibt es <a rel=\"noreferrer noopener\" href=\"https:\/\/symfony.com\/doc\/current\/reference\/forms\/types.html\" target=\"_blank\">hier<\/a>. Der hinzugef\u00fcgte Feldtyp muss vom Typ Symfony\\Component\\Form\\Extension\\Core\\Type sein. \u00dcbrigens, um den zweiten Parameter zu \u00fcberspringen, null eintragen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Auswahllisten anhand von DB-Feldern werden ebenfalls mit -&gt;add bef\u00fcllt. Als dritter Parameter wird die gew\u00fcnschte DB angegeben.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-&gt; add('author', EntityType::class, [<br>    'class' =&gt; User::class<br>])<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In dieser Klasse braucht es dann aber eine spezielle Funktion:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public function __toString()<br>{<br>    return $this-&gt;getFirstName();<br>}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Hier wird dasjenige Feld aus der zuvor definierten Tabelle \u00fcbergeben, das hier genannt wird.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Soll ein definiertes Feld angesprochen werden, wird so gearbeitet:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-&gt; add('author', EntityType::class, [\n    'class' =&gt; User::class,\n    'choice_label' =&gt; function(User $user) {\n        return sprintf('(%d) %s', $user-&gt;getId(), $user-&gt;getFirstName());\n    },\n])<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn keine der Optionen aus der Liste vorausgew\u00e4hlt sein soll:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">'placeholder' =&gt; 'Bitte ausw\u00e4hlen',<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr individuelle Abfragen muss zun\u00e4chst das Repository deklariert werden &#8211; in der Formklasse:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public function __construct(UserRepository $userRepository)<br>{<br>    $this-&gt;userRepository = $userRepository;<br>}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Um die Variablen automatisch zu initialisieren, den Cursor auf die Variable setzen, Alt-Enter dr\u00fccken und den Code erzeugen lassen. Dann im Formularbereich eine neue Variable einf\u00fcgen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">'choices' =&gt; $this-&gt;userRepository<br>    -&gt;findAllEmailAlphabetical(),<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Diese Funktion findAllEmailAlphabetical muss dann im Repository\\userRepository.php erzeugt werden:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public function findAllEmailAlphabetical()<br>{<br>    return $this-&gt;createQueryBuilder('u')<br>        -&gt;orderBy('u.email', 'ASC')<br>        -&gt;getQuery()<br>        -&gt;execute();<br>}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a rel=\"noreferrer noopener\" aria-label=\" (\u00f6ffnet in neuem Tab)\" href=\"https:\/\/www.youtube.com\/watch?v=t5ZedKnWX9E\" target=\"_blank\">Auch ansehen<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mit dem composer das Projekt erstellen. Dazu auf DOS-Ebene ins htdocs-Verzeichnis gehen und den Befehl composer create-project symfony\/skeleton zielpfad eingeben. Zielpfad ist das Verzeichnis innerhalb von htdocs, in dem das Projekt erstellt werden soll. Im Verzeichnis public muss eine .htaccess erstellt werden. Die bekommt folgenden Inhalt: &lt;IfModule mod_rewrite.c&gt; RewriteEngine On # Determine the _RewriteBase automatically [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-508","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/wiki.ad-libitum.info\/index.php?rest_route=\/wp\/v2\/pages\/508","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wiki.ad-libitum.info\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/wiki.ad-libitum.info\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/wiki.ad-libitum.info\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/wiki.ad-libitum.info\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=508"}],"version-history":[{"count":0,"href":"https:\/\/wiki.ad-libitum.info\/index.php?rest_route=\/wp\/v2\/pages\/508\/revisions"}],"wp:attachment":[{"href":"https:\/\/wiki.ad-libitum.info\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=508"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}