Alle Beiträge von Julian Billinger

Über Julian Billinger

Projektleiter Entwicklung

Automatische Generierung von API-Dokumentation in Laravel

Das erstellen von Schnittstellen Dokumentationen ist aufwendig, fehleranfällig und benötigt viel Zeit. Mit dem Composer Paket Scramble kann automatisch API-Dokumentationen erstellt werden und diese auf einer Unterseite präsentiert werden.

Die Dokumentation wird im OpenAPI 3.1.0 Format erstellt und mit Hilfe von Spotlight Elements präsentiert.

Auf der Zieldomain kann nach erfolgreicher Installation die Dokumentation unter domain.tld/docs/api aufgerufen werden. Die Dokumentation ist, solange nicht anders konfiguriert, ausschließlich im Entwicklungsmodus erreichbar. Sobald in der .env die APP_ENV angepasst wird ist sie nicht mehr erreichbar.

Installation

Das Paket scramble wird per Composer installiert:

composer require dedoc/scramble

Ebenfalls muss dbal installiert werden, damit Modell Attribute und Relations angezeigt werden:

composer require doctrine/dbal

Anschließend kann eine Konfigurationsdatei veröffentlicht werden, welche Einstellungen zur Sicherheit beinhaltet. Die Standardeinstellungen reichen allerdings vollkommen aus.

php artisan vendor:publish --provider="Dedoc\Scramble\ScrambleServiceProvider" --tag="scramble-config"

Verwendung

Damit Informationen automatisch angezeigt werden muss der Code sauber gepflegt sein. Vor die Funktion im Controller muss ein Block platziert werden, der die Funktion benennt und beschreibt:

Im Frontend wird uns diese Information dann so angezeigt:

Wird das Request mit validate(), bzw. Validator geprüft, werden die entsprechenden Felder auch gekennzeichnet. Welche Schreibweise der Methode verwendet wird ist egal:

Die Antwort wird ebenfalls automatisch gefüllt. Sollte es sich dabei um ein Modell handeln so wird dieses komplett ausgegeben. Aktuell funktioniert dies nur mit einer JSONResource, das wird sich allerdings im nächsten Release laut dem Entwickler ändern und Modelle sollen auch direkt ausgegeben werden können, ohne dass man neue Resourcen für alle Modelle erstellen muss.

Des Weiteren werden alle möglichen Responses und deren Antworten und deren möglicher Inhalt angezeigt. Im nächsten Release wird es außerdem möglich sein, die Responses individuell zu beschriften und zu beschreiben.

Das Projekt wurde erst vor wenigen Tagen veröffentlicht, aber der Entwickler ist schnell bei der Umsetzung von Feature Requests und freut sich über Feedback. Die Github Seite des Projektes können Sie hier finden, die offizielle Dokumentation hier.

Sollten Sie noch Fragen haben oder eine Beratung wünschen, können Sie gerne mit uns Kontakt aufnehmen oder unsere Webseite besuchen.

Gerne können Sie hier auch andere Artikel zum Thema Laravel anschauen.

LAMP Stack für Laravel auf WSL installieren

Für Windows existieren eine Vielzahl von LAMP Applikationen wie Laragon oder XAMPP. Allerdings sind einige nützliche Pakete, die man zu Laravel hinzufügen kann, nicht mit Windows kompatibel. Auch Funktionen wie der Scheduler oder Queue Workers können nur über Umwege getestet werden. Anstelle für jeden Entwickler bei jedem Projekt Server zu erstellen und echte Domains darauf umzuleiten, haben wir hier eine detaillierte Anleitung erstellt, mit der man auf dem Windows Subsystem for Linux eine vollwertige Entwicklungsumgebung erstellen kann.

Auch erstellt haben wir ein Shell Script, welches die komplette Verwaltung übernimmt:

  • Starten/Stoppen/Neustarten des LAMP Stacks
  • Anzeigen aller vHosts/Ordner
  • Erstellung neuer Projekte mit Option für Laravel
  • Erstellung einer neuen Datenbank mit Benutzer und Passwort und automatischem Ausfüllen der .env.
  • Erstellung von Self Signed Certificates

Updates

Vorbereitung in Windows

Damit wir innerhalb von Windows auf die im WSL gehosteten Seiten zugreifen können, müssen wir jedes Mal einen neuen Eintrag in der Host Datei hinterlegen. Damit das automatisch durch unser Script übernommen werden kann, verwenden wir gsudo. Um gsudo zu installieren, öffnen wir PowerShell als Administrator und verwenden diesen Befehl:

PowerShell -Command "Set-ExecutionPolicy RemoteSigned -scope Process; iwr -useb https://raw.githubusercontent.com/gerardog/gsudo/master/installgsudo.ps1 | iex"

Als nächstes loggen wir uns im Windows Store ein und installieren Ubuntu. Wir verwenden die neueste Version (Ubuntu 22.04 LTS).

Grundinstallation

Nach erfolgreicher Installation von Ubuntu wechseln wir auf den root Benutzer.

sudo su

Damit wir ungestraft sudo verwenden können ohne ständig das Passwort eintippen zu müssen, fügen wir mit visudo am Ende der sudoers Datei eine Ausnahme für unseren Account hinzu (billinger mit dem eigenen Accountnamen austauschen).

billinger ALL=(ALL) NOPASSWD:ALL

PHP Repository hinzufügen:

add-apt-repository ppa:ondrej/php

Update, Upgrade und Installation von Apache, MySQL und PHP. Da bei älteren Laravel Versionen PHP 8 nicht funktioniert, installieren wir gleich PHP 7.4 und 8.1 gleichzeitig. Je nachdem welche Version später notwendig ist, kann diese einfach gewechselt werden.

apt-get update && apt-get upgrade -y 
apt install -y apache2 mysql-server unzip php8.1-{fpm,gd,mysql,curl,xml,zip,intl,mbstring,bz2,ldap,apcu,bcmath,gmp,imagick,igbinary,redis,smbclient,cli,common,opcache,readline,imagick,redis}  php7.4-{fpm,gd,mysql,curl,xml,zip,intl,mbstring,bz2,ldap,apcu,bcmath,gmp,imagick,igbinary,redis,smbclient,cli,common,opcache,readline,imagick,redis} 

Damit der mysql Benutzer auch ein Home Verzeichnis hat und nicht bei jedem Neustart einen Fehler ausgibt:

usermod -d /var/lib/mysql/ mysql

Apache Konfiguration

Diverse notwendige Apache Module werden aktiviert und anschließend PHP FPM 8.1 umgestellt. Auf dem gleichen Weg kann auch PHP 7.4 aktiviert werden.

a2enmod rewrite ssl vhost_alias authz_groupfile headers cache expires actions alias proxy_fcgi proxy proxy_html proxy_http xml2enc mpm_event http2
a2enconf php8.1-fpm
echo "Protocols h2 http/1.1" >> /etc/apache2/apache2.conf

PHP Konfiguration

Optimierung der Konfiguration:

sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/;env\[TMP\] = /env[TMP] = /" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/;env\[TEMP\] = /env[TEMP] = /" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/;env\[PATH\] = /env[PATH] = /" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/pm.max_children =.*/pm.max_children = 240/" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/pm.start_servers =.*/pm.start_servers = 30/" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/pm.min_spare_servers =.*/pm.min_spare_servers = 10/" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/pm.max_spare_servers =.*/pm.max_spare_servers = 200/" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/;pm.max_requests =.*/pm.max_requests = 1000/" /etc/php/8.1/fpm/pool.d/www.conf
sed -i "s/allow_url_fopen =.*/allow_url_fopen = 1/" /etc/php/8.1/fpm/php.ini
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/8.1/cli/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 3600/" /etc/php/8.1/cli/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/8.1/cli/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/8.1/cli/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/8.1/cli/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/8.1/cli/php.ini
sed -i "s/memory_limit = 128M/memory_limit = 1024M/" /etc/php/8.1/fpm/php.ini
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/8.1/fpm/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 3600/" /etc/php/8.1/fpm/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/8.1/fpm/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/8.1/fpm/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/8.1/fpm/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/8.1/fpm/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/8.1/fpm/php.ini
sed -i "s/;opcache.enable=.*/opcache.enable=1/" /etc/php/8.1/fpm/php.ini
sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" /etc/php/8.1/fpm/php.ini
sed -i "s/;opcache.memory_consumption=.*/opcache.memory_consumption=128/" /etc/php/8.1/fpm/php.ini
sed -i "s/;opcache.interned_strings_buffer=.*/opcache.interned_strings_buffer=16/" /etc/php/8.1/fpm/php.ini
sed -i "s/;opcache.max_accelerated_files=.*/opcache.max_accelerated_files=10000/" /etc/php/8.1/fpm/php.ini
sed -i "s/;opcache.revalidate_freq=.*/opcache.revalidate_freq=1/" /etc/php/8.1/fpm/php.ini
sed -i "s/;opcache.save_comments=.*/opcache.save_comments=1/" /etc/php/8.1/fpm/php.ini
sed -i "s|;emergency_restart_threshold.*|emergency_restart_threshold = 10|g" /etc/php/8.1/fpm/php-fpm.conf
sed -i "s|;emergency_restart_interval.*|emergency_restart_interval = 1m|g" /etc/php/8.1/fpm/php-fpm.conf
sed -i "s|;process_control_timeout.*|process_control_timeout = 10|g" /etc/php/8.1/fpm/php-fpm.conf
sed -i '$aapc.enable_cli=1' /etc/php/8.1/mods-available/apcu.ini
sed -i "s/rights=\"none\" pattern=\"PS\"/rights=\"read|write\" pattern=\"PS\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"EPS\"/rights=\"read|write\" pattern=\"EPS\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"PDF\"/rights=\"read|write\" pattern=\"PDF\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"XPS\"/rights=\"read|write\" pattern=\"XPS\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;env\[TMP\] = /env[TMP] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;env\[TEMP\] = /env[TEMP] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;env\[PATH\] = /env[PATH] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/pm.max_children =.*/pm.max_children = 240/" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/pm.start_servers =.*/pm.start_servers = 30/" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/pm.min_spare_servers =.*/pm.min_spare_servers = 10/" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/pm.max_spare_servers =.*/pm.max_spare_servers = 200/" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;pm.max_requests =.*/pm.max_requests = 1000/" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/allow_url_fopen =.*/allow_url_fopen = 1/" /etc/php/7.4/fpm/php.ini
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/7.4/cli/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 3600/" /etc/php/7.4/cli/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.4/cli/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.4/cli/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.4/cli/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.4/cli/php.ini
sed -i "s/memory_limit = 128M/memory_limit = 1024M/" /etc/php/7.4/fpm/php.ini
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/7.4/fpm/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 3600/" /etc/php/7.4/fpm/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.4/fpm/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.4/fpm/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.4/fpm/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.4/fpm/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.enable=.*/opcache.enable=1/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.memory_consumption=.*/opcache.memory_consumption=128/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.interned_strings_buffer=.*/opcache.interned_strings_buffer=16/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.max_accelerated_files=.*/opcache.max_accelerated_files=10000/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.revalidate_freq=.*/opcache.revalidate_freq=1/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.save_comments=.*/opcache.save_comments=1/" /etc/php/7.4/fpm/php.ini
sed -i "s|;emergency_restart_threshold.*|emergency_restart_threshold = 10|g" /etc/php/7.4/fpm/php-fpm.conf
sed -i "s|;emergency_restart_interval.*|emergency_restart_interval = 1m|g" /etc/php/7.4/fpm/php-fpm.conf
sed -i "s|;process_control_timeout.*|process_control_timeout = 10|g" /etc/php/7.4/fpm/php-fpm.conf
sed -i '$aapc.enable_cli=1' /etc/php/7.4/mods-available/apcu.ini
sed -i "s/rights=\"none\" pattern=\"PS\"/rights=\"read|write\" pattern=\"PS\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"EPS\"/rights=\"read|write\" pattern=\"EPS\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"PDF\"/rights=\"read|write\" pattern=\"PDF\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"XPS\"/rights=\"read|write\" pattern=\"XPS\"/" /etc/ImageMagick-6/policy.xml

Erweiterung der php.ini mit einer custom.ini und Erstellung von symbolischen Links:

#### /etc/php/custom.ini

max_execution_time = 2400
max_input_time = 900
post_max_size = 800M
memory_limit = 4048M
upload_max_filesize = 800M
max_input_vars = 100000
max_file_uploads = 5000
realpath_cache_size = 4M
date.timezone = 'Europe/Berlin'
display_errors = On
error_log = /var/log/php-error.log
error_reporting = E_ALL
phar.readonly = 0

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=512
opcache.interned_strings_buffer=64
opcache.max_accelerated_files=32531
opcache.save_comments=1
opcache.fast_shutdown=0
opcache.max_file_size=0
opcache.validate_timestamps=1
opcache.revalidate_freq=2
ln -s /etc/php/custom.ini /etc/php/7.4/fpm/conf.d/custom.ini
ln -s /etc/php/custom.ini /etc/php/8.1/fpm/conf.d/custom.ini
ln -s /etc/php/custom.ini /etc/php/7.4/cli/conf.d/custom.ini
ln -s /etc/php/custom.ini /etc/php/8.1/cli/conf.d/custom.ini

Composer Installation

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
mv composer.phar /usr/local/bin/composer
echo "export COMPOSER_ALLOW_SUPERUSER=1" >> ~/.bashrc

NVM und NPM Installation

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
source ~/.bashrc
nvm install node
npm set unsafe-perm true
n=$(which node);n=${n%/bin/node}; chmod -R 755 $n/bin/*; sudo cp -r $n/{bin,lib,share} /usr/local

lamp Script hinterlegen

visudo ausführen und in der Zeile Details secure_path= /opt/lamp hinzufügen

mkdir /opt/lamp
cd /opt/lamp
wget https://admin-code.de/downloads/lamp
chmod +x lamp
echo "export PATH='$PATH:/opt/lamp'" >> ~/.bashrc
source ~/.bashrc

Rechte in /var/www anpassen

(billinger mit dem eigenen Accountnamen austauschen)

chown -R www-data:www-data /var/www
chmod 00755 /var
chmod 00755 /var/www
find /var/www -type d -exec chmod 00755 {} \;
find /var/www -type f -exec chmod 00644 {} \;
usermod -a -G www-data billinger

Mögliche Script Schalter

Ausführen kann man das Script mit dem Befehl „lamp“. Danach kommen die weiteren Keywords. Die Befehle „start“, „stop“, „restart“, „status“ beziehen sich auf die Services. Mit „list“ kann man kontrollieren, welche Konfigurationen in Apache vorhanden sind und welche Ordner in /var/www stehen. Mit „add Projektname“ und „remove Projektname“ können Projekte hinzugefügt und gelöscht werden (beim Löschen wird nur die Apache Konfiguration gelöscht. Die Daten bleiben weiterhin vorhanden).

Die Hilfe kann über „lamp help“ angezeigt werden.

Script ausführen

Da es ein paar Funktionen gibt die ohne https nicht funktionieren, erstellen wir für alle neuen Projekte automatisch Zertifikate. Da es sich hier allerdings um lokale Domainnamen handelt, können hier keine „echten“ Zertifikate wie von Let’s Encrypt verwendet werden. Eine Certificate Authority kann die Validität unserer Entwicklungsseiten nicht verifizieren. Deswegen werden wir unsere eigene Certificate Authority erstellen.

Wir verwenden hierfür dev-certificates von Ben Morel (https://github.com/BenMorel).

Unser lamp Script prüft automatisch, ob das Zertifikat schon existiert und erstellt es gegebenenfalls neu. Damit der Browser dieses auch verwendet, muss es hinterlegt werden.

Bei der Erstellung eines neuen Projektes kann zwischen Laravel und nicht Laravel entschieden werden. Ebenfalls ist es möglich, ein zuvor gepulltes Projekt in die vHosts mit einzufügen. Dabei sollte man die Frage ob Laravel installiert werden soll, ablehnen. Eine neue Datenbank kann trotzdem automatisch generiert und in die .env geschrieben werden.

Ebenfalls ist es möglich, „normale“ Projekte mit oder ohne Datenbank zu erstellen. Diese bekommen dann, um zu verifizieren dass die Installation funktioniert hat, eine Standard HTML Seite.

Unter den allgemeinen Informationen im Script kann die Variable TLD mit einer gewünschten TLD definiert werden. Moderne Browser werden beim aufrufen wie my-project.local direkt die Suchmaschine verwenden. Wer nicht jedes erste Mal https:// schreiben möchte, kann hier eine reguläre TLD wie .de oder .com verwenden. Besser wären allerdings die neuen TLDs wie .fun, .xyz, oder thematisch passend .test.

Autostart LAMP Stack

Da Apache und MySQL nicht Teil unseres Windows Betriebssystems sind, steht uns der LAMP Stack erst zur Verfügung, wenn Ubuntu gestartet wird und wir dort die Services entweder automatisch oder manuell über „lamp start“ ausführen. Damit dies automatisiert passiert, öffnen wir einmal regulär Ubuntu und notieren uns via Task Manager den genauen Pfad.

"C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu22.04LTS_2204.0.10.0_x64__79rhkp1fndgsc\ubuntu2204.exe"

Als nächstes öffnen wir mit WIN + R den Ausführen Dialog und öffnen den Autostart Ordner von Windows.

shell:startup

In diesem Ordner erstellen wir nun eine neue Batch Datei in der wir unsere WSL Befehle hinterlegen. Die Batch Datei wird bei jedem Systemstart automatisch ausgeführt.

@echo off 
wsl sudo bash /opt/lamp/lamp start

Visual Studio Code mit WSL Verbinden

Sobald WSL auf dem Gerät installiert ist, sollte sich Visual Studio Code automatisch beim Start melden und das Plugin „Remote – WSL“ vorschlagen, nun dieses installieren und in der .bashrc den Pfad für Visual Studio hinterlegen. Danach kann in WSL mit dem Befehl „code /path/to/open“ das gewünschte Verzeichnis geöffnet werden.

export PATH=$PATH:"/mnt/c/Users/BILLINGER/AppData/Local/Programs/Microsoft VS Code/bin"

Abschließend nochmal das .bashrc File mit source .bashrc laden.

Sollten Sie noch Fragen haben oder eine Beratung wünschen, können Sie gerne mit uns Kontakt aufnehmen oder unsere Webseite besuchen.

Gerne können Sie hier auch weitere Artikel zum Thema Laravel lesen. Andere Sysadmin Blogartikel finden Sie auf unserem Hauptblog.

Vue.JS mit Vue Router: Hash Zeichen in URL entfernen

SPA mit Vue Router können mithilfe des History Modes komplette URLs anzeigen – diese sind allerdings lediglich simuliert. Alles nach dem Hash ist nicht Teil der URL und wird nur vom Router verwendet, um dem Benutzer den richtigen Inhalt anzuzeigen. Dies hat negative Auswirkungen auf das SEO.

Wie wir den Hash entfernen und aus unseren simulierten URLs richtige URLs machen, erfahren sie in diesem Beitrag.

Vue Router.js

import Vue from 'vue';
import VueRouter from 'vue-router';

import Home from './pages/Home.vue';
import Contact from './pages/Contact.vue';
import NotFound from './pages/NotFound.vue';

Vue.use(VueRouter);

const routes = [
    {
        path: '/',
        redirect: '/home',
    },
    {
        path: '/home',
        component: Home,
        name: 'Home',
    },
    {
        path: '/contact',
        component: Contact,
        name: 'Contact',
    },
    {
        path: '*',
        component: NotFound,
        name: '404 Page not found',
    },

]

export default new VueRouter({ mode: 'history', routes });

Was davor https://example.com/#/contact war, ist nun https://example.com/contact. Der Server, der die Applikation hostet, weiß das allerdings noch nicht. Hier müssen wir ebenfalls Änderungen vornehmen:

Apache

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
</IfModule>

Nginx

location / {
    try_files $uri $uri/ /index.html;
}

Vue Laravel

Sollte unsere Vue.JS Applikation innerhalb einer Laravel Applikation gehostet werden, können wir hier direkt in der web.php Änderungen vornehmen.

<?php

use Illuminate\Support\Facades\Route;

Route::any('{all}', function () {
    return view('app');
})->where('all', '^(?!api).*$');

„app“ muss hier natürlich mit dem Namen unserer default Blade Ansicht ausgetauscht werden. Die where-clause erlaubt uns weiterhin, die APIs durchzulassen. URLs, die diesen String beinhalten, werden nicht automatisch weitergeleitet, sondern korrekt an die API Schnittstelle weitergeleitet.

Sollten Sie noch Fragen haben oder eine Beratung wünschen, können Sie gerne mit uns Kontakt aufnehmen oder unsere Webseite besuchen.

Gerne können Sie hier auch andere Artikel zum Thema Vue.JS anschauen.

Laravel mit InfluxDB Verbinden

Laravel kommt mit vielen Providern für Datenbank Verbindungen. Allerdings gibt es eine Vielzahl von Datenbanken, die nur über Umwegen von Laravel angesprochen werden können. Wie das Ganze mit InfluxDB funktioniert, erfahren Sie in diesem Beitrag.

Als erstes fügen wir das Paket mit Composer zu unserem Laravel Projekt hinzu:

composer require tray-labs/laravel-influxdb

In die .env müssen die Verbindungsinformationen hinterlegt werden:

INFLUXDB_HOST=localhost
INFLUXDB_PORT=8086
INFLUXDB_USER=some_user
INFLUXDB_PASSWORD=some_password
INFLUXDB_SSL=false
INFLUXDB_VERIFYSSL=false
INFLUXDB_TIMEOUT=0
INFLUXDB_DBNAME=some_database
INFLUXDB_UDP_ENABLED=false # Activate UDP
INFLUXDB_UDP_PORT=4444 # Port for UDP

Abschließend führen wir diesen Befehl im Terminal aus:

php artisan vendor:publish

Im Controller, in dem wir auf InfluxDB zugreifen möchten, können wir jetzt den Provider angeben und die Datenbankabfragen durchführen.

Wie das Ganze in der Influx Cloud DB aussieht, haben wir uns auch angeschaut und werden auf den nächsten Blog Beitrag verlinken, sobald dieser erscheint.

Sollten Sie noch Fragen haben oder eine Beratung wünschen, können Sie gerne mit uns Kontakt aufnehmen oder unsere Webseite besuchen.

Gerne können Sie hier auch andere Artikel zum Thema Laravel anschauen.

Laravel Notifications per Mail versenden

Mit Laravel kann man Benutzern direkt Notifications per E-Mail senden. Wie das funktioniert, erfahren Sie in diesem Artikel.

Zum Thema Laravel Notifications haben wir auch einen Artikel zu Notifications in Rocket.Chat versenden veröffentlicht, diesen können Sie hier finden.

Mailtrap & SMTP Konfiguration

Zum Testen verwenden wir mailtrap.io. Wie der Name es schon suggeriert werden alle Mails direkt abgefangen. Diese werden dann in einem Postfach gebündelt angezeigt.

Innerhalb des Postfaches gehen wir auf SMTP Settings und wählen im Dropdown direkt Laravel aus. Die richtigen Einstellungen werden angezeigt und können in die .env eingetragen werden.

Erstellung Notification & Controller

php artisan make:notification AlarmNotification
php artisan make:controller NotificationController

Im NotificationController erstellen wir eine Test Funktion und inkludieren die AlarmNotification, damit wir diese auch ansprechen können.

<?php

namespace App\Http\Controllers;

use App\Notifications\AlarmNotification;

class NotificationController extends Controller
{
    public function test()
    {
        // testing notification
    }
}

In der Test Funktion erstellen wir uns die NotificationData, die wir versenden möchten.

$notificationData = [
    'message' => 'Test Notification',
    'actionLink' => 'https://admin-code.de'
    'actionText' => 'Click here'
];

Damit wir die Notification versenden können, benötigen wir noch einen Zielbenutzer. Über „notify“ können wir ihm dann die Notification mit notificationData schicken.

$user = User::first();

$user->notify(new AlarmNotification($notificationData));

Damit das auch funktioniert, müssen innerhalb des User Models Notifications erlaubt sein.
Dies sollte standartmäßig bereits der Fall sein – trotzdem sollte folgendes kontrolliert werden:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
use Illuminate\Database\Eloquent\SoftDeletes;



class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

An diesem Punkt können wir die Notification bereits testen.

// api.php

use App\Http\Controllers\NotificationController;

Route::get('notification-test', [NotificationController::class, 'test']);

Über Postman können wir nun die API aufrufen und etwaige Fehler analysieren.

Möglicher Fehler beim Versenden der Mail:

stream_socket_client(): php_network_getaddresses: getaddrinfo for mailhog failed: No such host is known.

Lösung:

php artisan cache:clear
php artisan config:clear

Konfiguration der Notification

Am Anfang der Notification Class deklarieren wir die notificationData als private.

class AlarmNotification extends Notification
{
    use Queueable;
    private $notificationData;

Und schreiben diese mit in den Constructor

public function __construct($notificationData)
    {
        $this->notificationData = $notificationData;
    }

Nun können wir die Informationen, die wir im Controller an die Notification weitergegeben haben hier auch verwenden. In der toMail Funktion wird der Text der Mail definiert.

public function toMail($notifiable)
    {
        return (new MailMessage)
	    ->line($this->notificationData['message'])
	    ->action(
	        $this->notificationData['actionText'],
	        $this->notificationData['actionLink']
	    )
    }

Aussehen der Laravel Notification ändern

Die Templates, die von Laravel verwendet werden, um Notifications zu versenden, können mit diesen beiden Commands in den resources Ordner verschoben und anschließen bearbeitet werden:

php artisan vendor:publish --tag=laravel-mail
php artisan vendor:publish --tag=laravel-notifications

Nun können wir zum Beispiel das Logo im Header der Notification verändern:

Dazu einfach in der resources/views/vendor/mail/html/header.blade.php den Link austauschen. Dabei nicht vergessen, in der CSS Datei die Breiten- und Höhenangaben zu bearbeiten.

Weitere Informationen und Meta Daten in Laravel Notification

Neben Linien und einem Action Button kann man noch weitere Infos and die Notification weitergeben.

->level()

Verändert Farben des Action Buttons und Anrede wenn keine gesetzt ist

->subject()

Betreff der E-Mail

->from()

Absender der E-Mail

->replyTo()

E-Mail Adresse für Antworten

->priority()

Priorität der E-Mail, 1-5, 1 ist das höchste

->greeting()

Anrede

->line()

Text in der Mail, kann auch mehrmals per For-Loop verwendet werden

->salutation()

Gruß zum Abschied

Mehr Methoden können Sie in der offiziellen Dokumentation nachschlagen.

Sollten Sie noch Fragen haben oder eine Beratung wünschen, können Sie gerne mit uns Kontakt aufnehmen oder unsere Webseite besuchen.

Gerne können Sie hier auch andere Artikel zum Thema Laravel anschauen.

Back Funktion in Vue mit Vue-Router abfangen

Bei der Entwicklung von Vue Webanwendungen hat man in der Regel mehrere Ansichten oder Dialoge innerhalb einer Unterseite. Bei dem Betätigen der Zurücktaste im Browser oder direkt an der Maus wird allerdings die letzte Seite in der History geöffnet. Etwaige Fortschritte gehen somit verloren.

Eine einfache Möglichkeit dieses Verhalten abzufangen sind Router Guards. Wir können hier den Seitenwechsel abfangen, abfragen ob gerade etwas aktiv ist und den Seitenwechsel erlauben oder abbrechen.

Im ersten Schritt muss in der Komponente die wir bearbeiten möchten innerhalb des created Events der Router Guard hinterlegt werden.

const unregisterRouterGuard = this.$router.beforeEach((to, from, next) => {

});

this.$once('hook:destroyed', () => {
    unregisterRouterGuard();
});

Innerhalb der Funktion können wird jetzt angeben welche v-models welches Verhalten auslösen sollten.

if (this.showData) {
    this.backFunction();
    next(false);
} else {
   next();
}

In diesem Beispiel haben wir einen modalen Dialog mit dem v-model showData. Wenn dieser auf true steht, dann ist der Dialog gerade offen. Der User möchte allerdings nicht sofort auf die vorherige Seite, sondern den Dialog schließen.

Wir führen die Funktion backFunction() aus um den Dialog zu schließen und verhindern mit next(false) die Weiterleitung.

Problematik: Der User hat einen modalen Dialog, Karte oder ähnliches geöffnet, möchte allerdings über die Navigation auf eine andere Unterseite. Bei Betätigen des router-links wird das Verlassen der Seite abgebrochen und der Dialog wird geschlossen.

Um dieses Verhalten zu Verhindern fügen wir dem mounted Event einen Event-Listener hinzu:

this.$root.$on(override, () => {
    this.routerGuardOverwrite = true;
});

Der Router Link in der Navigation bekommt ein @click, welches den Override ausführt.

<router-link to="/nextcloud" v-if="roleAttributes.includes('nextcloud')">
    <v-list-item link @click="handleLinkClick()">
        <v-list-item-action>
            <v-icon>mdi-cloud</v-icon>
        </v-list-item-action>
        <v-list-item-content>
            <v-list-item-title>
                Nextcloud
            </v-list-item-title>
        </v-list-item-content>
    </v-list-item>
</router-link>
handleLinkClick: function () {
    this.$root.$emit(override);
},

Abschließend können wir am Anfang des Router Guards das Verlassen der Seite erlauben.

if (this.routerGuardOverride) {
    next();
    return;
}

Sollten Sie noch Fragen haben oder eine Beratung wünschen, können Sie gerne mit uns Kontakt aufnehmen oder unsere Webseite besuchen.

Laravel Scheduler

Mit Hilfe des Schedulers können Tasks gezielt geplant und unabhängig von Benutzeraktivitäten innerhalb von Laravel ausgeführt werden. Wie der Scheduler verwendet wird, erfahren Sie in diesem Artikel.

Grundsätzlich werden bei Laravel Funktionen nur ausgeführt, wenn Benutzer diese auslösen. Wenn wir allerdings Tasks haben, die regelmäßig zu bestimmten Zeiten ausgeführt werden, müssen wir den Scheduler verwenden.

Die Grundfunktion hinter dem Scheduler ist ein Cronjob, der jede einzelne Minute ausgeführt wird. Der Cronjob ruf dann wiederum über Artisan den Scheduler auf.

Editierung des Crontabs

sudo su
crontab -e

Der Crontab wird standartmäßig mit dem Endgegner vi geöffnet. Mit der Bild-runter Taste gehen wir hier zur letzten Zeile, drücken i für insert und fügen die folgende Zeile ein.

* * * * * /usr/bin/php7.4 /var/www/insight/artisan schedule:run > /dev/null 2>&1

(Die Pfade für die PHP-Executeable und Artisan müssen natürlich angepasst werden)

Erstellung der Commands

Zum ausführen der Einzelnen Tasks werden Commands verwendet. Diese können wie gewohnt mit Artisan erstellt werden.

php artisan make:command <command:name>

Der neue Command kann im Ordner /app/Console/Commands gefunden werden.

Wichtig hierbei ist die Signatur des Commands (im Bild Zeile 24). Diese wird verwendet, um den Command über den Scheduler oder die Konsole aufzurufen.

Was genau der Command ausführen soll, wird in der handle() Funktion definiert. Kleinere Funktionen können direkt innerhalb des Commandos definiert werden. Dazu kann man wie im Screenshot regulär Models und Helpers importieren und verwenden. Bei umfangreicheren Abläufen oder benötigten Hilfsfunktionen sollte man die Funktionalität direkt in den dazugehörigen Controller auslagern:

Auch für das Debuggen ist es hilfreich, die Funktionen im Controller zu haben, um diese dann per API via Postman zu testen. Der direkte Aufruf der Commands führt zu keinen Fehlermeldungen in der Console.

Konfiguration Scheduler

Die Konfigurationsdatei des Schedulers ist unter app/Console/Kernel.php zu finden. Hier müssen die Commands hinterlegt werden, um sie dann auszuführen:

In der Funktion schedule können wir anschließen unsere Commands mit Häufigkeit der Aufrufe hinterlegen:

Schedules können in den Unterschiedlichsten Konstellationen getriggert werden, eine Umfangreiche Liste der Modifiers kann in der offiziellen Dokumentation gefunden werden.

Sollten Sie noch Fragen haben oder eine Beratung wünschen, können Sie gerne mit uns Kontakt aufnehmen oder unsere Webseite besuchen.

Gerne können Sie hier auch andere Artikel zum Thema Laravel anschauen.

Laravel Notifications an Rocket.Chat versenden

Laravel Notifications können standardmäßig per E-Mail, SMS (über Drittanbieter) und Slack versendet werden. Mit Hilfe des Community Projektes Laravel Notification Channels lassen sich Notifications auch an andere Dienste schicken.

In diesem Artikel zeigen wir Ihnen, wie Rocket.Chat angesprochen werden kann.

Setup

Der Rocket.Chat Notification Channel wird mit Composer installiert:

composer require laravel-notification-channels/rocket-chat

Vorab müssen wir innerhalb von Rocket.Chat einen neuen Channel und eine Integration erstellen:

Wichtig: Der Rocket.Chat Token wird erst nach dem ersten Speichern generiert.

In die .env werden die URL des Rocket.Chat Servers, das Token aus dem letzten Screenshot, und der Name des Zielchannels hinterlegt:

ROCKETCHAT_URL="https://chat.admin-box.de/"
ROCKETCHAT_TOKEN="*******"
ROCKETCHAT_CHANNEL="insight"

In der Datei config/services.php wird der neue Rocket.Chat Service hinterlegt:

'rocketchat' => [
    'url' => env('ROCKETCHAT_URL'),
    'token' => env('ROCKETCHAT_TOKEN'),
    'channel' => env('ROCKETCHAT_CHANNEL'),
],

Eine neue Notification wird erstellt:

php artisan make:notification TestNotification

Zum Steuern der Notification wird ein neuer Controller erstellt (optional):

php artisan make:controller NotificationController

Controller Konfiguration

Im Controller, den wir verwenden möchten, um die Notification auszuführen, fügen wir die Notification hinzu

use App\Notifications\TestNotification;

und können sie danach auch schon in einer Beispielfunktion verwenden

public function testNotification()
{
    $user = Auth::user();
    $notificationData = [
        'body' => 'Testbenachrichtigung von ' . $user->name,
        'url' => 'https://portal.admin-insight.de'
    ];>

    Notification::route('', '')
        ->notify(newTestNotification($notificationData));
}

Da wir hier keine Nachrichten direkt an einzelne Benutzer versenden, die in unserer Laravel Installation hinterlegt sind, sondern hart auf einen Rocket.Chat Server und einen Channel gehen, können wir mit Notification::route(“, “) die Notification triggern. Bei anderen Formen der Notification, wie E-Mail, wird die Notification mit Hilfe des User Models aufgerufen, und die verknüpfte E-Mail-Adresse wird automatisch zur Zieladresse.

$user->notify(new TestNotification($notificationData)));

Notification Konfiguration

Innerhalb der Notification werden die folgenden Klassen hinzugefügt

use NotificationChannels\RocketChat\RocketChatMessage;
use NotificationChannels\RocketChat\RocketChatAttachment;
use NotificationChannels\RocketChat\RocketChatWebhookChannel;

Auf RocketChatAttachment kann verzichtet werden, sollte man grundsätzlich keine Anhänge versenden.

class TestNotification extends Notification
{
    use Queueable;
    private $notificationData; // 

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($notificationData)
    {
        $this->notificationData = $notificationData;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return [ 
            RocketChatWebhookChannel::class
        ];
    }

Die Variable $notificationData wird im Constructor bespielt und kann dann später in der Nachricht verwendet werden

    public function toRocketChat($notifiable): RocketChatMessage
    {

        return RocketChatMessage::create()
          ->content($this->notificationData['body'] . ' [Hier klicken](' . $this->notificationData['url'] . ')' );
    }

In der toRocketChat Funktion wird nun die Nachricht erstellt und losgeschickt

Neben content() gibt es noch weitere nützliche Methoden:

->alias('')

Ändert den Namen des Absenders (der originale Name wird dahinter noch gezeigt)

->emoji('')

Tauscht das Profilbild des Absenders mit einem der Rocket.Chat Emojis (Bspw. :radioactive:)

->avatar('')

Tauscht das Profilbild des Absenders mit einem im Internet gespeichertem Bild

->attachment() und attachments()

Hier können Bilder/Videos/Sounds als Anhang der Nachricht hinzugefügt werden

Beispielhaftes Attachment:

->attachment(
    RocketChatAttachment::create()
        ->imageUrl('https://domain.tld/image.jpg')
        ->color('blue') 
        ->text('attachmentText'
);

Anhänge haben ebenfalls eine Vielzahl von möglichen Methoden. Zeitstempel, Farben, Thumbnails, und vieles mehr. Mehr Methoden können Sie in der offiziellen Dokumentation nachschlagen.

Sollten Sie noch Fragen haben oder eine Beratung wünschen, können Sie gerne mit uns Kontakt aufnehmen oder unsere Webseite besuchen.

Gerne können Sie hier auch andere Artikel zum Thema Laravel anschauen.