Added some models and worked on API-class

templating-wip
Eirik Th S 2022-08-29 22:02:36 +02:00
parent e4f224cde7
commit 370055e3cc
17 changed files with 438 additions and 62 deletions

View File

@ -15,6 +15,10 @@ spl_autoload_register(function ($class_name) {
elseif(file_exists(__DIR__ . "/models/" . $class_name . ".php")) {
include_once __DIR__."/models/Model.php";
include_once __DIR__ . "/models/" . $class_name . ".php";
// echo "Load class ".__DIR__."/models/".$class_name.'.php'."<br>\n";
}elseif(file_exists(__DIR__ . "/models/Plan/" . $class_name . ".php")) {
include_once __DIR__."/models/Model.php";
include_once __DIR__ . "/models/Plan/" . $class_name . ".php";
// echo "Load class ".__DIR__."/models/".$class_name.'.php'."<br>\n";
}
});

View File

@ -227,6 +227,7 @@ class Auth {
}
public static function currentUserId(){
$a = Auth::getInstance();
return $_SESSION['user_id'];
}
}

View File

@ -14,6 +14,7 @@ class WebPage {
public $pr = ""; // project root
public $err = array();
public $msg = array();
public $data = array();
public function __construct(){

View File

@ -9,8 +9,11 @@ abstract class Model {
protected static $table;
protected static $tableExtends = null;
protected static $fields;
protected $isLoaded = false;
protected $initialValues = [];
protected $errors = [];
public function __construct(){
public function __construct($id = 0){
foreach (static::$fields as $field => $type){
switch ($type){
case "INT":
@ -23,6 +26,29 @@ abstract class Model {
break;
}
}
if($id > 0){
try {
$firstField = array_keys(static::$fields)[0];
$result = DB::query("SELECT `".implode("`, `", array_keys(static::$fields))."` FROM ".static::$database.".".static::$table . " t1 WHERE `$firstField` = ?", $id )->fetch_assoc();
$values = [];
foreach (static::$fields as $field => $type){
$this->{ $field } = $result[$field];
// cache initial value
$values[$field] = $this->{$field};
}
$this->isLoaded = true;
} catch (DatabaseException $e) {
$this->errors[] = $e;
}
}
$this->initialValues = $this->asArray();
}
/**
@ -95,6 +121,7 @@ abstract class Model {
$result = array();
while($row = $q->fetch_assoc()){
$res = new static();
$res->isLoaded = true;
/* Alternative for non-joined queries:
foreach (static::$fields as $key => $ignore){
@ -118,9 +145,67 @@ abstract class Model {
return false;
}
public function isLoaded() : bool {
return $this->isLoaded;
}
// public function set($value, )
/**
* @throws DatabaseException
*/
public function save(){
$newFields = [];
$newValues = [];
$allExceptFirstFields = [];
$allExceptFirstValues = [];
$fieldCount = 0;
foreach(static::$fields as $field => $type){
$currValue = $this->{ $field };
if(!empty($this->initialValues) && $currValue != $this->initialValues[$field]){
$newFields[] = $field;
$newValues[] = $currValue;
}
if($fieldCount > 0){
$allExceptFirstFields[] = $field;
$allExceptFirstValues[] = $currValue;
}
$fieldCount++;
}
if(!empty($this->initialValues) && empty($newValues)){
return false;
}
if($this->isLoaded()){
$updateSets = [];
foreach($newFields as $field){
$updateSets[] = "`$field` = ?";
}
DB::query(sprintf('UPDATE %s.%s SET %s WHERE %s LIMIT 1', static::$database, static::$table, implode(', ', $updateSets), "`" . array_keys(static::$fields)[0] . "` = ?"), array_merge($newValues, [$this->{array_keys(static::$fields)[0]}]));
}
else {
$sql = sprintf('INSERT INTO %s.%s (%s) VALUE (%s)', static::$database, static::$table, implode(', ', $newFields), implode(', ', array_fill(0, count($newFields), '?')));
DB::query($sql, $newValues);
$insertid = DB::insert_id();
$this->{ array_keys(static::$fields)[0] } = $insertid;
$this->isLoaded = true;
return $insertid;
}
return true;
}
public function asArray(): array {
$arr = [];
foreach ($this as $key => $val){
$arr[$key] = $val;
}
return $arr;
}
}

30
models/Plan/PlanStore.php Normal file
View File

@ -0,0 +1,30 @@
<?php
//namespace models;
class PlanStore extends Model {
protected static $table = "plan_store";
protected static $fields = [
"plan_store_id" => "INT",
"space_id" => "INT",
"name" => "VARCHAR",
"created" => "DATETIME",
"state" => [ 'planning', 'shopping', 'closed' ]
];
public static function getUserSpaces(){
$spaces = array_merge(
static::get([ 'owner_id' => Auth::currentUserId() ]),
PlanSpaceMember::get([ 'member_id' => Auth::currentUserId() ])
);
foreach ($spaces as $s){
if($s->space_name == ""){
$spaceOwner = User::get(['user_id' => $s->owner_id])[0];
$s->space_name = $spaceOwner->full_name != "" ? sprintf('%ss space', $spaceOwner->full_name ) : "A users space";;
}
}
return $spaces;
}
}

View File

@ -0,0 +1,29 @@
<?php
//namespace models;
class PlanSpace extends Model {
protected static $table = "plan_space";
protected static $fields = [
"space_id" => "INT",
"space_name" => "VARCHAR",
"owner_id" => "INT",
"space_type" => [ 'STORE', 'CHECK', 'CALORIES' ]
];
public static function getUserSpaces(){
$spaces = array_merge(
static::get([ 'owner_id' => Auth::currentUserId() ]),
PlanSpaceMember::get([ 'member_id' => Auth::currentUserId() ])
);
foreach ($spaces as $s){
if($s->space_name == ""){
$spaceOwner = User::get(['user_id' => $s->owner_id])[0];
$s->space_name = $spaceOwner->full_name != "" ? sprintf('%ss space', $spaceOwner->full_name ) : "A users space";;
}
}
return $spaces;
}
}

View File

@ -7,14 +7,23 @@ class PlanSpace extends Model {
protected static $fields = [
"space_id" => "INT",
"space_name" => "VARCHAR",
"owner_id" => "VARCHAR",
"owner_id" => "INT",
"space_type" => [ 'STORE', 'CHECK', 'CALORIES' ]
];
public static function getUserSpaces(){
return array_merge(
$spaces = array_merge(
static::get([ 'owner_id' => Auth::currentUserId() ]),
PlanSpaceMember::get([ 'member_id' => Auth::currentUserId() ])
);
foreach ($spaces as $s){
if($s->space_name == ""){
$spaceOwner = User::get(['user_id' => $s->owner_id])[0];
$s->space_name = $spaceOwner->full_name != "" ? sprintf('%ss space', $spaceOwner->full_name ) : "A users space";;
}
}
return $spaces;
}
}

15
models/User.php Normal file
View File

@ -0,0 +1,15 @@
<?php
//namespace models;
class User extends Model {
protected static $table = "user";
protected static $fields = [
"user_id" => "INT",
"md5_id" => "VARCHAR",
"full_name" => "VARCHAR",
"user_email" => "VARCHAR",
"user_level" => "INT",
"date" => "DATE"
];
}

View File

@ -15,7 +15,7 @@
<label class="input-group-text" for="spaceSelect">Space:</label>
<select class="form-select" id='spaceSelect' aria-label="Select space">
{% for space in spaces %}
<option>...</option>
<option value="{{ space.space_id }}">{{ space.space_name }}</option>
{% endfor %}
</select>
</div>

View File

@ -33,7 +33,13 @@ abstract class Api {
}
if($this->success){
$this->execute();
try {
$this->execute();
}
catch (Exception | DatabaseException $e){
$this->success = false;
$this->message = $e;
}
}
$this->printResult();
@ -52,6 +58,9 @@ abstract class Api {
echo json_encode( $returns );
}
/**
* @throws DatabaseException
*/
protected function execute(){ }
/**

View File

@ -1,5 +1,13 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
include_once '../../../Router.php';
include_once 'api.php';
$dirs = [];
$file = "";
$args = [];
@ -22,9 +30,15 @@ foreach($_GET as $arg){
if(!empty($filePath)){
$_GET['args'] = $args;
echo $filePath;
// echo __dir__ . '/' . $filePath;
// include $filePath;
if(file_exists( __dir__ . '/' . $filePath )){
include_once __dir__ . '/' . $filePath;
return;
}
}
http_send_status(500);
header('Content-Type: application/json');
echo json_encode([ 'error' => "API not found." ]);

View File

@ -0,0 +1,42 @@
<?php
class CreateStoreApi extends Api {
protected $methods = [
"POST" => [
[
"name" => "space_id",
"keyword" => "space_id",
"type" => VERIFY_STRING
],
[
"name" => "name",
"keyword" => "name",
"type" => VERIFY_STRING
]
]
];
/**
* @throws DatabaseException
*/
function execute(){
try {
$store = new PlanStore();
$store->space_id = $this->data['space_id'];
$store->name = $this->data['name'];
$this->result = $store->save();
$this->success = true;
$this->message = "OK";
}
catch (DatabaseException $e){
$this->success = false;
$this->message = "Error: " . $e;
}
}
}
$request = new CreateStoreApi();

View File

@ -0,0 +1,46 @@
<?php
class ModifyStoreApi extends Api {
protected $methods = [
"POST" => [
[
"name" => "store_id",
"keyword" => "store_id",
"type" => VERIFY_INT
],
[
"name" => "newname",
"keyword" => "newname",
"type" => VERIFY_STRING
],
[
"name" => "state",
"keyword" => "state",
"type" => VERIFY_STRING
],
]
];
function execute(){
$store = PlanStore::get(['plan_store_id' => $this->data['store_id']])[0];
if(isset($this->data['newname'])){
$store->name = $this->data['newname'];
}
elseif(isset($this->data['state'])){
$store->state = $this->data['state'];
}
$store->save();
$this->result = $store;
$this->success = true;
$this->message = "OK";
}
}
$request = new ModifyStoreApi();

View File

@ -0,0 +1,36 @@
<?php
class GetStoresApi extends Api {
protected $methods = [
"GET" => [
[
"name" => "space",
"keyword" => "space",
"type" => VERIFY_INT
],
],
"URI" => [
[
"name" => "space",
"keyword" => "space",
"type" => VERIFY_INT
],
]
];
/**
* @throws DatabaseException
*/
function execute(){
$stores = PlanStore::get(['space_id' => $this->data['space'] ]);
$this->result = $stores;
$this->success = true;
$this->message = "OK";
}
}
$request = new GetStoresApi();

View File

@ -0,0 +1,35 @@
<?php
class CreateSpacesApi extends Api {
protected $methods = [
"POST" => [
[
"name" => "space_name",
"keyword" => "space_name",
"type" => VERIFY_STRING
],
[
"name" => "space_type",
"keyword" => "space_type",
"type" => VERIFY_STRING
],
]
];
function execute(){
$space = new PlanSpace();
$space->space_name = $this->data['space_name'];
$space->space_type = $this->data['space_type'] ?? 'STORE';
$space->owner_id = Auth::currentUserId();
$this->result = $space->save();
$this->success = true;
$this->message = "OK";
}
}
$request = new CreateSpacesApi();

View File

@ -1,7 +1,5 @@
<?php
require_once '../api.php';
class GetSpacesApi extends Api {
protected $methods = [
@ -15,7 +13,8 @@ class GetSpacesApi extends Api {
];
function execute(){
$this->result = PlanSpace::get();
$this->result = PlanSpace::getUserSpaces();
$this->success = true;
$this->message = "OK";
}

View File

@ -227,7 +227,8 @@ class Store {
}
if(prevState !== state){
ajaxReq({ plan: 'setState', storeID: this.storeID, state: this.state });
// ajaxReq({ plan: 'setState', storeID: this.storeID, state: this.state });
qAPI('plan/modify', 'POST', { store_id: this.storeID, state: this.state })
}
}
@ -612,7 +613,7 @@ class Store {
getStoreID(){
let that = this;
return ajaxReq({ plan: 'saveStore', storeName: this.title })
return qAPI('plan/create', 'POST', { space_id: spaceID, name: this.title })
.done(json => {
console.log("getStore:", json);
that.storeID = json['data'];
@ -624,7 +625,14 @@ class Store {
this.title = newName;
if(this.storeID !== null){
return ajaxReq({ plan: 'renameStore', storeID: this.storeID, newName: newName });
return qAPI('plan/modify', 'POST', { store_id: this.storeID, newname: newName })
// return ajaxReq({ plan: 'renameStore', storeID: this.storeID, newName: newName });
}
else {
return qAPI('plan/create', 'POST', { space_id: spaceID, name: this.title }).done(json => {
this.storeID = json.data;
});
}
// Return blank ajax as a false
@ -663,63 +671,54 @@ function updateTotalPrice(){
}
let spaceID = 0;
function getSpaces(){
$("#stores").html("Loading...");
return ajaxReq({plan: 'spaces'}).done(json => {
let optionsHtml = "";
// console.log(json);
let spaceNum = 1;
for(const spaceI in json.data.spaces){
const space = json.data.spaces[spaceI];
if(spaceID === 0){
spaceID = space['space_id'];
}
let spaceName = space['space_name'] || "Space "+spaceNum;
optionsHtml += "<option value='"+space['space_id']+"'>"+spaceName+"</option>\n";
spaceNum++;
}
let spaceSelectElem = $("#spaceSelect");
spaceSelectElem
.html(optionsHtml)
.on('change', ev => {
spaceID = $(ev.target).val();
getStores(spaceID);
});
if(typeof json.data.lastSpace !== "undefined"){
spaceID = Number(json.data.lastSpace);
spaceSelectElem.val(spaceID);
}
});
// function getSpaces(){
// $("#stores").html("Loading...");
// return ajaxReq({plan: 'spaces'}).done(json => {
// let optionsHtml = "";
//
// console.log(json);
//
// let spaceNum = 1;
// for(const spaceI in json.data.spaces){
// const space = json.data.spaces[spaceI];
// if(spaceID === 0){
// spaceID = space['space_id'];
// }
// let spaceName = space['space_name'] || "Space "+spaceNum;
// optionsHtml += "<option value='"+space['space_id']+"'>"+spaceName+"</option>\n";
// spaceNum++;
// }
// .html(optionsHtml)
}
getSpaces().done(() => { getStores(spaceID); });
// if(typeof json.data.lastSpace !== "undefined"){
// spaceID = Number(json.data.lastSpace);
// spaceSelectElem.val(spaceID);
// }
// });
// }
// getSpaces().done(() => { getStores(spaceID); });
let spaceSelectElem = $("#spaceSelect");
spaceSelectElem.on('change', ev => {
// console.debug('Change space');
spaceID = $(ev.target).val();
getStores(spaceID);
}).trigger('change');
// GET STORES
function getStores(spaceID){
spaceID = spaceID || 0;
// $("#stores").html("");
stores = [];
let options = { plan: '' };
if(spaceID !== 0){
options = { plan: '', space: spaceID }
}
return $.getJSON('do.php', options)
return qAPI('plan/stores/'+spaceID )
.done(json => {
if(handleJsonErrors(json)){
return;
}
$("#stores").html("");
// console.log(json);
for(const store in json.data){
let storeKey = stores.length;
@ -735,12 +734,13 @@ function getStores(spaceID){
stores[storeKey].setState(json.data[store].state, 1);
}
updateTotalPrice();
})
.fail(handleAjaxErrors);
});
}
function ajaxReq( data ){
console.log("REQUEST STOPPED", data);
return false;
if(typeof spaceID !== "undefined" && spaceID !== 0){
data.space = spaceID;
}
@ -756,10 +756,31 @@ function ajaxReq( data ){
.fail(handleAjaxErrors);
}
function qAPI( path, method, data ){
method = method || 'GET';
data = data || {};
// if(typeof spaceID !== "undefined" && spaceID !== 0){
// data.space = spaceID;
// }
return $.ajax({
method: method,
url: "/api/v2/" + path,
data: data,
dataType: 'JSON'
})
.done(json => {
return !handleJsonErrors(json);
})
.fail(handleAjaxErrors);
}
function handleJsonErrors(json){
if(typeof json.status != "undefined" && json.status !== 0){
if(typeof json.status != "undefined" && json.status !== true && json.status !== 0){
if(json.message === "Not logged in"){
location.href = '../login.php';
// location.href = '../login.php';
alert("Not logged in...");
}
else {
alert(json.message);