V tomto receptu si ukážeme praktické využití real-time databáze Firebase od Google. Vytvoříme velmi rychle sexy android aplikaci pro monitoring vytížení VOIP ústředny.
Ingredience
- účet na google (pro zřízení databáze Firebase)
- IONIC2 dev stack
- projekt na Symfony 3.x
- data z VOIP ústředny (aktuální hovory, zmeškané hovory, stav jednotlivých VOIP zařízení apod.)
Postup přípravy
- nejprve si připravíme Firebase databázi pro náš nový projekt (do 100 konkurenčních spojení je zdarma) na firebase.google.com a https://console.firebase.google.com
- upravíme zabezpečení tak, aby bylo možné se připojit a zapisovat bez autorizace uživatelem (v této aplikaci nehrají uživatelé roli, postačí základní JSON klíč):
- tím máme prostor pro výměnu dat hotovou
- připravíme si tedy cron na kmení dat, v SF klasický command + klienta na připojení k Firebase
- použijeme tedy například „composer require kreait/firebase-php“
- a vytvoříme si vlastní service:
<?php namespace FirebaseBundle\Service; use Kreait\Firebase; class Client { private $firebase; private $database; public function __construct() { $this->firebase = (new Firebase\Factory()) ->withCredentials(__DIR__.'/../../../app/config/firebase/APP_KEY.json') ->withDatabaseUri('https://APP_PREFIX.firebaseio.com/') ->create(); $this->database = $this->firebase->getDatabase(); } public function getReference(string $path) { return $this->database->getReference($path); } }
- nyní nakrmíme novou databázi z dat ústředny, v našem případě například:
public function saveStats(TPStats $TPStats) { $data = [ 'actualCalls' => ['count' => $TPStats->getActualCalls()->getCount()], 'freeOperators' => ['count' => $TPStats->getFreeOperators()->getCount()], 'missedCalls' => [ 'count' => $TPStats->getMissedCalls()->getCount(), 'oldestDelta' => $TPStats->getMissedCalls()->getDelta(), ], 'recordedCalls' => [ 'count' => $TPStats->getRecordedCalls()->getCount(), 'oldestDelta' => $TPStats->getRecordedCalls()->getDelta(), ], 'waitingCalls' => [ 'count' => $TPStats->getWaitingCalls()->getCount(), 'oldestDelta' => $TPStats->getWaitingCalls()->getDelta(), ], 'busyCalls' => [ 'count' => $TPStats->getBusyCalls()->getCount(), 'oldestDelta' => $TPStats->getBusyCalls()->getDelta(), ], 'operatorActualLog' => [ 'log' => $TPStats->getOperatorsActualLog(), ], ]; $this->client->getReference('/actualData')->set($data); }
- výsledkem je potom JSON struktura ve Firebase:
Použití stringu v proměnných delta je záměrné, usnadňujeme si tak práci pro výpis přímo v IONIC app a díky tomu, že je celá aplikace real-time, nevzniká žádné zpoždění.
Ty žluté vyznačené části není chyba ani warning, ale ukázka reálné aktualizace dat, které se zrovna změnili. Mimochodem geniální věc pro debug, kdy okamžitě vidíme, zda-li nám plnění databáze funguje, jak má.
- nyní už zbývá jen IONIC2 app pro Android (případně OS X pro fajnšmekry)
- vytvoříme si tedy novou blank aplikaci
ionic start af2-lists blank –v2 - nainstalujeme angularfire:
npm
install
angularfire2 --save
- v app.module.ts si zavedeme config:
// AF2 Settings
export
const firebaseConfig = {
apiKey:
"AIzaSyDnAX0CQbbsMYuOTJ66ox_F0GwzPM4XPXY"
,
authDomain:
"angularfire2-list-example.firebaseapp.com"
,
storageBucket:
""
,
messagingSenderId:
"609067141823"
};
- no a tím pádem můžeme pracovat s firebase databází, například takto:
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import {AngularFire, FirebaseObjectObservable} from 'angularfire2'; @Component({ selector: 'page-home', templateUrl: 'home.html', }) export class HomePage { data: FirebaseObjectObservable<any>; actualOperatorsList: FirebaseObjectObservable<any>; constructor(public navCtrl: NavController, af: AngularFire) { this.data = af.database.object('/actualData'); af.database.list('/actualData/operatorActualLog/log') //Convert array into Observable and flatten it //Transform the value .map((x) => x) //Subscribe to the stream .subscribe(x => this.actualOperatorsList = x); } }
- vypíšeme data:
<ion-header> <ion-navbar> <ion-title> CALL MONITOR </ion-title> </ion-navbar> </ion-header> <ion-content> <ion-grid> <ion-row> <ion-col col-6> <actualOperatorsLog [actualOperatorsLog]="actualOperatorsList"></actualOperatorsLog> </ion-col> <ion-col col-6> <ion-item> <button ion-button icon-left> <ion-icon name="call"></ion-icon> Aktuální hovory </button> <ion-badge color="dark" class="value" item-right>{{ (data | async)?.actualCalls?.count }}</ion-badge> </ion-item> <ion-item> <button ion-button icon-left> <ion-icon name="cafe"></ion-icon> Volní operátoři </button> <ion-badge color="dark" class="value" item-right>{{ (data | async)?.freeOperators?.count }}</ion-badge> </ion-item> <ion-item> <button ion-button icon-left> <ion-icon name="bonfire"></ion-icon> Zmeškané hovory za 30 min </button> <ion-badge color="dark" class="value" item-right>{{ (data | async)?.busyCalls?.count }} <span>/ {{ (data | async)?.busyCalls?.oldestDelta }}</span></ion-badge> </ion-item> <ion-item> <button ion-button icon-left> <ion-icon name="bus"></ion-icon> Čekající hovory </button> <ion-badge color="dark" class="value" item-right>{{ (data | async)?.waitingCalls?.count }} <span>/ {{ (data | async)?.waitingCalls?.oldestDelta }}</span></ion-badge> </ion-item> <ion-item> <button ion-button icon-left> <ion-icon name="contacts"></ion-icon> Změškané hovory ve frontě </button> <ion-badge color="dark" class="value" item-right>{{ (data | async)?.missedCalls?.count }} <span>/ {{ (data | async)?.missedCalls?.oldestDelta }}</span></ion-badge> </ion-item> <ion-item> <button ion-button icon-left> <ion-icon name="cash"></ion-icon> Záznamník </button> <ion-badge color="dark" class="value" item-right>{{ (data | async)?.recordedCalls?.count }} <span>/ {{ (data | async)?.recordedCalls?.oldestDelta }}</span></ion-badge> </ion-item> </ion-col> </ion-row> </ion-grid> <p> </p> <p> </p> </ion-content>
- ještě jedna komponenta pro výpis aktuálního stavu:
import {Component, Input} from '@angular/core'; import 'rxjs/add/operator/map'; import {OperatorLog} from "../entity/OperatorLog"; @Component({ selector: 'actualOperatorsLog', template: ` <ion-item *ngFor="let item of actualOperatorsLog" class="operatorsLog"> <ion-icon name="person"></ion-icon> {{ item.voipid }} {{ item.action }} <span>{{ item.age }}</span> </ion-item> ` }) export class ActualOperatorsLogComponent { @Input() actualOperatorsLog: OperatorLog[]; constructor() { } }
- a aplikaci zbuildíme pro android či iphone
Aplikaci podáváme na FULL HD (aby nedošlo ke střižení jako na screenu níže) monitoru připojeném k jakémukoliv androidímu zařízení. No není pěkná?
Chcete pomoci s tvorbou aplikace? Kontaktujte nás!