<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Exception\JsonException;
use App\Entity\Container;
use App\Entity\Box;
use App\Entity\Supply;
use App\Entity\Supplier;
use App\Entity\Provider;
/**
* @Route("/api", name="api_")
*/
class ApiController extends BaseController
{
/* todo: pozdeji do DB, prirazovat treba prava, atd... ted na to neni cas */
// API_KLIC => ID_KONTEJNERU
const API_KEYS = [
'123ABC123ABC123ABC' => 1,
];
const API_OPERATIONS = [
'test',
'report-container-state',
'report-ac',
'get-ac-setting',
'report-manipulator-states',
'check-incoming-supply-box',
'find-box-for-extraction',
'empty-box-extracted-by-supplier',
'full-box-inserted-by-supplier',
'check-incoming-provider',
'check-incoming-empty-box',
'full-box-extracted-by-provider',
'empty-box-inserted-by-provider',
];
protected Container $requestingContainer; // KONTEJNER, KTERY POSILA API REQUEST, naplnuje se v preProcessApiCall()
/*
* vrati bud chybovy Response, nebo pole dat
*/
private function preProcessApiCall(Request $request)
{
// header musi obsahovat platny apikey
if(!isset(self::API_KEYS[$request->headers->get('Api-Key', null)])) return $this->json(['status' => 0, 'msg' => 'Unauthorized'], 401);
// musi to byt json
if($request->getContentType() !== 'json') return $this->json(['status' => 0, 'msg' => 'Bad request - JSON only'], 400);
// kontejner podle api klice - musi byt pouzitelny
$this->requestingContainer = $this->containerModel->getUsableContainer(self::API_KEYS[$request->headers->get('Api-Key', null)]);
if(!$this->requestingContainer instanceof Container) return $this->json(['status' => 0, 'msg' => 'Error finding usable container'], 500); // nejaka haluz, kontejner ma spravny API klic ale je najaky problem u me
// zkusime konvertovat request na pole
try {
$payload = $request->toArray();
}
catch(JsonException $e) {
return $this->json(['status' => 0, 'msg' => 'Bad request - JSON only'], 400);
}
// musi obsahovat platny apikey -> header!
//if(!isset($payload['apiKey']) || !in_array($payload['apiKey'], self::API_KEYS)) return $this->json(['msg' => 'Unauthorized'], 401);
// musi obsahovat platnou operaci
if(!isset($payload['operation']) || !in_array($payload['operation'], self::API_OPERATIONS)) return $this->json(['status' => 0, 'msg' => 'Unknown operation'], 400);
// OK, to vypada dobre
return $payload;
}
/**
* @Route("/", name="root", methods={"GET", "POST"})
*/
public function index(Request $request): Response
{
$data = $this->preProcessApiCall($request);
if($data instanceof Response) return $data; // vratilo to chybovy response, posli ho ven
// jinak jsou data OK a je v nich rozparsovany JSON
switch($data['operation'])
{
//----------------------------------------------------------------------------------------------------------------------------------------
// test ze api funguje a API klic je v poradku
case 'test' :
return $this->json(['status' => 1, 'msg' => 'OK']);
//----------------------------------------------------------------------------------------------------------------------------------------
// kontejner hlasi stav bedynek - hmm co s tim... tady asi jen ulozit do databaze, ne?
case 'report-container-state' :
if(!isset($data['slotdata'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
// ok mam, jen ulozim json stavu do DB
if($this->containerModel->saveReportedContainerState($this->requestingContainer, $data['slotdata']) === true)
{
return $this->json(['status' => 1, 'msg' => 'Stav kontejneru uložen']);
}
else
{
return $this->json(['status' => 0, 'msg' => 'Chyba při ukládání stavu kontejneru']);
}
//----------------------------------------------------------------------------------------------------------------------------------------
// front na kontejneru precetl QR (zatim predpokladame Box) - pta se, co s tim
case 'check-incoming-supply-box' :
// v parametrech musim dostat qr boxu
if(!isset($data['qr'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
// OK mam vse co potrebuju, dalsi uz je 'application level' tj odezva uz bude vzdy 200
// nejprve najdeme box podle qr
$box = $this->boxModel->getBoxByQr($data['qr']);
if(!$box instanceof Box) return $this->json(['status' => 0, 'msg' => 'Neznámá přepravka']);
// ok box máme, je ve správném stavu (tj v držení Supplierem)?
$supplier = $box->getSupplier();
if($box->getState() != 100 || ! $supplier instanceof Supplier) return $this->json(['status' => 0, 'msg' => 'Přepravka není očekávána (špatný stav přepravky)']);
// ok Box je v držení nějakého Suppliera, má daný Supplier na dnešek nahlášený závoz do daného Continaeru?
$supply = $this->boxModel->getTodaysSupply($this->requestingContainer, $supplier);
if(!$supply instanceof Supply) return $this->json(['status' => 0, 'msg' => 'Vaše dodávka není nahlášena']);
// priznak zda se jedna o zasilku ktera je planovana cela jen do jedne zony
$singleZone = 'none';
if($supply->getExpectedColdBoxes() == 0)
{
$singleZone = 'W';
}
else
{
if($supply->getExpectedWarmBoxes() == 0)
{
$singleZone = 'C';
}
}
// OK máme hlášenou dodávku, hlásíme: kdo to je, jaká to je dodávka, kolik máme volna v kontejneru
// potřebujem nahlásit: počet prázdných přepravek (W / C) a počet prázdných slotů (W / C)
return $this->json([
'status' => 1,
'supplier' => $supplier->getName(),
'supplierId' => $supplier->getId(),
'slotStates' => $this->containerModel->getSlotStates($this->requestingContainer),
'singleZoneSupply' => $singleZone,
]);
//----------------------------------------------------------------------------------------------------------------------------------------
// hledam prazdnou bedynku v dane zone
case 'find-box-for-extraction' :
if(!isset($data['zone'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
$box = $this->containerModel->findEmptyBoxInZone($this->requestingContainer, $data['zone']);
if(!$box instanceof Box) return $this->json(['status' => 0, 'msg' => 'V zóně nebyla nalezena prázdná přepravka']);
return $this->json([
'status' => 1,
'boxQR' => $box->getQr(),
'boxX' => $box->getData('x'),
'boxY' => $box->getData('y'),
]);
//----------------------------------------------------------------------------------------------------------------------------------------
// doslo k extrakci prazdneho boxu (odebira ho supplier)
case 'empty-box-extracted-by-supplier' :
if(!isset($data['boxQr']) || !isset($data['supplierId'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
// hledam box, ten by mel byt v kontejneru v prazdnem stavu
$box = $this->boxModel->getBoxByQr($data['boxQr']);
if(!$box instanceof Box) return $this->json(['status' => 0, 'msg' => 'Z kontejneru byla vyjmuta neznámá přepravka']); // tohle se snad nemuze stat...
// todo: mozna jeste koukat zda je ve spravnem containeru?
// provest stavovy prechod
if($this->boxModel->changeBoxState($box, 100, $data['supplierId']))
{
return $this->json([
'status' => 1,
]);
}
else
{
return $this->json([
'status' => 0,
'msg' => 'Chyba při změně stavu přepravky',
]);
}
//----------------------------------------------------------------------------------------------------------------------------------------
// doslo k inserci plneho boxu (vklada ho supplier)
case 'full-box-inserted-by-supplier' :
if(!isset($data['boxQr']) || !isset($data['zone']) || !isset($data['weight'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
// hledam box, ten by mel byt u daneho suppliera
$box = $this->boxModel->getBoxByQr($data['boxQr']);
if(!$box instanceof Box) return $this->json(['status' => 0, 'msg' => 'Do kontejneru byla vložena neznámá přepravka']); // tohle se snad nemuze stat...
$box->setType($data['zone']); // TODO: tady??? asi by melo byt soucasti zmeny stavu nebo nevim...
$box->setData('weight', intval($data['weight']));
if($this->boxModel->changeBoxState($box, 400, $this->requestingContainer->getId()))
{
return $this->json([
'status' => 1,
]);
}
else
{
return $this->json([
'status' => 0,
'msg' => 'Chyba při změně stavu přepravky',
]);
}
//----------------------------------------------------------------------------------------------------------------------------------------
// autorizuje se nam provider
case 'check-incoming-provider' :
// v parametrech musim dostat qr providera
if(!isset($data['qr'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
$provider = $this->providerModel->getProviderByQr($data['qr']);
if(!$provider instanceof Provider) return $this->json(['status' => 0, 'msg' => 'Nerozpoznaný kód']);
// ok máme providera, jsou pro něj containeru nějaké bedýnky?
//$boxes = $this->boxModel->getBoxesInContainerForProvider($this->requestingContainer, $provider);
// TODO: !!! ve skutecnosti takhle: !!!
$boxesCounts = $this->boxModel->countBoxesInContainerForProvider($this->requestingContainer, $provider); // pocty bedynek s dodavkami ve W a C
$slotStates = $this->containerModel->getSlotStates($this->requestingContainer);
// simulace:
//$boxesCounts = array('W' => 2, 'C' => 2);
//$slotStates = array('empty_warm' => 0, 'empty_cold' => 0, 'warm_with_empty' => 46, 'cold_with_empty' => 70, 'warm_with_supply' => 2, 'cold_with_supply' => 2);
if($boxesCounts['W'] == 0 && $boxesCounts['C'] == 0 && $slotStates['empty_warm'] == 0 && $slotStates['empty_cold'] == 0)
{
return $this->json([
'status' => 0,
'provider' => $provider->getName(),
'providerId' => $provider->getId(),
'msg' => 'Není k dispozici žádná akce (v kontejneru pro vás není zásilka a nejsou žádné prázdné pozice)'
]);
}
return $this->json([
'status' => 1,
'provider' => $provider->getName(),
'providerId' => $provider->getId(),
'slotStates' => $slotStates,
'boxesCounts' => $boxesCounts,
]);
//----------------------------------------------------------------------------------------------------------------------------------------
// provider (dopravce) vklada prazdnou bedynku
case 'check-incoming-empty-box':
// v parametrech musim dostat qr bedynky a id jiz drive 'prihlaseneho' providera
if(!isset($data['qr']) || !isset($data['providerId'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
// overim, zda bedynka existuje a je v drzeni daneho providera
$box = $this->boxModel->getBoxByQr($data['qr']);
if(!$box instanceof Box) return $this->json(['status' => 0, 'msg' => 'Neznámá přepravka']);
// ok box máme, je ve správném stavu (tj. v držení toho správného Providera)?
$provider = $box->getProvider();
if($box->getState() != 200 || !$provider instanceof Provider || $provider->getId() != $data['providerId']) return $this->json(['status' => 0, 'msg' => 'Přepravka není očekávána (špatný stav přepravky)']);
// vse OK, empty box muzeme potencialne prijmout - BUD ho budeme vymenovat za plny box z dodavky, NEBO vkladat na prazdne misto
// prioritu bude mit vymena za box z dodavky
$supplyBox = $this->boxModel->getOneBoxInContainerForProvider($this->requestingContainer, $provider);
if($supplyBox instanceof Box)
{
// ok mame box s dodavkou v kontejneru, musime najit jeho pozici v kontejneru
$this->containerModel->findBoxInContainer($this->requestingContainer, $supplyBox); // nastavuje supplyBoxu X a Y
if( is_null($supplyBox->getData('x')) || is_null($supplyBox->getData('y')) )
{
return $this->json([
'status' => 0,
'msg' => 'Pozice boxu ' . $supplyBox->getQr() . ' nebyla v kontejneru nalezena!',
]);
}
// ok, mame vse k vymene prazdneho boxu za box s dodavkou
return $this->json([
'status' => 1,
'operation' => 'extract-insert',
'zone' => $supplyBox->getType(),
'boxQR' => $supplyBox->getQr(),
'boxX' => $supplyBox->getData('x'),
'boxY' => $supplyBox->getData('y'),
]);
}
// v kontejneru jsme nenalezli Box s dodavkou pro me, tak zkusime najit volne misto kam by se dala prepravka vlozit
$coords = $this->containerModel->findEmptySpaceForEmptyBox($this->requestingContainer);
if(!empty($coords))
{
return $this->json([
'status' => 1,
'operation' => 'insert',
'coords' => $coords,
]);
}
return $this->json([
'status' => 0,
'msg' => 'Kontejner nemá plné přepravky na výměnu, ani volná místa.'
]);
//----------------------------------------------------------------------------------------------------------------------------------------
// doslo k extrakci naplneneho boxu (odebira ho provider)
case 'full-box-extracted-by-provider' :
if(!isset($data['boxQr']) || !isset($data['providerId'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
// hledam box, ten by mel byt v kontejneru a soucasti dodavky pro daneho providera
$extractedBox = $this->boxModel->getBoxByQr($data['boxQr']);
if(!$extractedBox instanceof Box) return $this->json(['status' => 0, 'msg' => 'Z kontejneru byla vyjmuta neznámá přepravka']); // tohle se snad nemuze stat...
if($extractedBox->getState() != 400) return $this->json(['status' => 0, 'msg' => 'Z kontejneru byla vyjmuta přepravka v neodpovídajícím stavu (' . $extractedBox->getState() . ')']);
$boxSupply = $extractedBox->getSupply();
if(!$boxSupply instanceof Supply) return $this->json(['status' => 0, 'msg' => 'Z kontejneru byla vyjmuta přepravka která nepatří k žádné dodávce']);
$boxProvider = $boxSupply->getProvider();
if(!$boxProvider instanceof Provider) return $this->json(['status' => 0, 'msg' => 'Z kontejneru byla vyjmuta přepravka která nemá určeného přepravce']);
if($boxProvider->getId() != $data['providerId']) return $this->json(['status' => 0, 'msg' => 'Z kontejneru byla vyjmuta přepravka která patří jinému přepravci']);
// todo: mozna jeste koukat zda je ve spravnem containeru?
// provest stavovy prechod
if($this->boxModel->changeBoxState($extractedBox, 200, $data['providerId']))
{
return $this->json([
'status' => 1,
]);
}
else
{
return $this->json([
'status' => 0,
'msg' => 'Chyba při změně stavu přepravky',
]);
}
//----------------------------------------------------------------------------------------------------------------------------------------
// doslo k inserci prazdneho boxu (vklada ho provider)
case 'empty-box-inserted-by-provider' :
if(!isset($data['boxQr']) || !isset($data['zone']) || !isset($data['providerId'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
// hledam box, ten by mel byt u daneho providera
$box = $this->boxModel->getBoxByQr($data['boxQr']);
if(!$box instanceof Box) return $this->json(['status' => 0, 'msg' => 'Do kontejneru byla vložena neznámá přepravka']); // tohle se snad nemuze stat...
if($box->getState() != 200) return $this->json(['status' => 0, 'msg' => 'Do kontejneru byla vložena přepravka v neodpovídajícím stavu (' . $box->getState() . ')']);
if($box->getProvider()->getId() != $data['providerId']) return $this->json(['status' => 0, 'msg' => 'Do kontejneru byla vložena přepravka která patří jinému přepravci']);
$box->setType($data['zone']); // TODO: tady??? asi by melo byt soucasti zmeny stavu nebo nevim...
if($this->boxModel->changeBoxState($box, 300, $this->requestingContainer->getId()))
{
return $this->json([
'status' => 1,
'slotStates' => $this->containerModel->getSlotStates($this->requestingContainer),
'boxesCounts' => $this->boxModel->countBoxesInContainerForProvider($this->requestingContainer, $this->providerModel->getProvider($data['providerId'])),
]);
}
else
{
return $this->json([
'status' => 0,
'msg' => 'Chyba při změně stavu přepravky',
]);
}
//----------------------------------------------------------------------------------------------------------------------------------------
// kontejner hlasi stav klimatizace/topeni
case 'report-ac' :
if(!isset($data['acData'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
// ok mam, jen ulozim json stavu do DB
if($this->containerModel->saveReportedAC($this->requestingContainer, $data['acData']) === true)
{
return $this->json(['status' => 1, 'msg' => 'Stav AC uložen']);
}
else
{
return $this->json(['status' => 0, 'msg' => 'Chyba při ukládání stavu AC']);
}
//----------------------------------------------------------------------------------------------------------------------------------------
// kontejner chce vedet stav klimatizace/topeni
case 'get-ac-setting' :
$acs = $this->containerModel->getLastACSetting($this->requestingContainer);
if(is_null($acs)) return $this->json(['status' => 0, 'msg' => 'Nastavení AC není k dispozici']);
// poznamenat, ze bylo sliznuto kontejnerem
$this->containerModel->setACSettingDownloaded($acs['id']);
// a vratit
return $this->json(array_merge(['status' => 1 ], $acs));
case 'report-manipulator-states' :
if(!isset($data['manipulatorStates'])) return $this->json(['status' => 0, 'msg' => 'Chybějící parametr(y)']);
if($this->containerModel->saveReportedManipulatorsState($this->requestingContainer, $data['manipulatorStates']) === true)
{
return $this->json(['status' => 1, 'msg' => 'Stavy manipulátorů uloženy']);
}
else
{
return $this->json(['status' => 0, 'msg' => 'Chyba při ukládání stavu manipulátorů']);
}
}
}
}