File indexing completed on 2024-12-15 03:45:05
0001 <?php 0002 /* 0003 SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org> 0004 0005 SPDX-License-Identifier: MIT 0006 */ 0007 0008 require_once('aggregation.php'); 0009 require_once('schemaentry.php'); 0010 require_once('utils.php'); 0011 0012 /** Represents a product and its schema. */ 0013 class Product 0014 { 0015 public $name; 0016 public $schema = array(); 0017 public $aggregation = array(); 0018 0019 private $productId = -1; 0020 0021 /** Name of the primary data table for this product, ie. 0022 * the one containing all scalar data. 0023 */ 0024 public function dataTableName() 0025 { 0026 $tableName = 'pd_' . Utils::normalizeString($this->name); 0027 return strtolower($tableName); 0028 } 0029 0030 /** Returns the numeric database id of this product for use in queries. */ 0031 public function id() 0032 { 0033 return $this->productId; 0034 } 0035 0036 /** Retrieve all products from storage. */ 0037 public static function allProducts(Datastore $db) 0038 { 0039 $products = array(); 0040 $stmt = $db->prepare('SELECT col_id, col_name FROM tbl_product'); 0041 $db->execute($stmt); 0042 foreach ($stmt as $row) { 0043 $p = new Product(); 0044 $p->productId = intval($row['col_id']); 0045 $p->name = strval($row['col_name']); 0046 $p->schema = SchemaEntry::loadSchema($db, $p); 0047 $p->aggregation = Aggregation::aggregationsForProduct($db, $p); 0048 array_push($products, $p); 0049 } 0050 return $products; 0051 } 0052 0053 /** Retrieve a specific product by name from storage. */ 0054 public static function productByName(Datastore $db, $name) 0055 { 0056 if (!is_string($name) || strlen($name) <= 0) 0057 throw new RESTException('Invalid product name.', 400); 0058 0059 $stmt = $db->prepare('SELECT col_id, col_name FROM tbl_product WHERE col_name = :name'); 0060 $stmt->bindValue(':name', strval($name), PDO::PARAM_STR); 0061 $db->execute($stmt); 0062 foreach ($stmt as $row) { 0063 $p = new Product(); 0064 $p->productId = intval($row['col_id']); 0065 $p->name = strval($row['col_name']); 0066 $p->schema = SchemaEntry::loadSchema($db, $p); 0067 return $p; 0068 } 0069 return null; 0070 } 0071 0072 /** Insert new product into database. */ 0073 public function insert(Datastore $db) 0074 { 0075 // create product entry 0076 $stmt = $db->prepare('INSERT INTO tbl_product (col_name) VALUES (:name)'); 0077 $stmt->bindValue(':name', $this->name, PDO::PARAM_STR); 0078 $db->execute($stmt); 0079 $this->productId = $db->pdoHandle()->lastInsertId(); 0080 0081 // create data tables; 0082 $stmt = $db->prepare('CREATE TABLE ' . $this->dataTableName() . ' (' . 0083 Utils::primaryKeyColumnDeclaration($db->driver(), 'col_id') . 0084 ', col_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP) 0085 '); 0086 $db->execute($stmt); 0087 0088 // create schema entries 0089 foreach ($this->schema as $entry) 0090 $entry->insert($db, $this->productId); 0091 0092 // store aggregation settings 0093 Aggregation::update($db, $this, $this->aggregation); 0094 } 0095 0096 /** Update an existing product in the database to match @p $newProduct. */ 0097 public function update(Datastore $db, Product $newProduct) 0098 { 0099 $oldSchema = array(); 0100 foreach ($this->schema as $oldEntry) 0101 $oldSchema[$oldEntry->name] = $oldEntry; 0102 0103 foreach ($newProduct->schema as $newEntry) { 0104 if (array_key_exists($newEntry->name, $oldSchema)) { 0105 // update 0106 $oldEntry = $oldSchema[$newEntry->name]; 0107 $oldEntry->update($db, $newEntry); 0108 } else { 0109 // insert 0110 $newEntry->insert($db, $this->productId); 0111 } 0112 unset($oldSchema[$newEntry->name]); 0113 } 0114 0115 // delete whatever is left 0116 foreach($oldSchema as $entry) 0117 $entry->delete($db, $this->productId); 0118 0119 // store aggregation settings 0120 Aggregation::update($db, $this, $newProduct->aggregation); 0121 } 0122 0123 /** Delete an existing product in the database. */ 0124 public function delete(Datastore $db) 0125 { 0126 // delete aggregation settings 0127 Aggregation::delete($db, $this); 0128 0129 // delete schema entries 0130 foreach ($this->schema as $entry) 0131 $entry->delete($db, $this->productId); 0132 0133 // delete data tables 0134 $stmt = $db->prepare('DROP TABLE ' . $this->dataTableName() . ($db->driver() == 'sqlite' ? '' : ' CASCADE')); 0135 $db->execute($stmt); 0136 0137 // delete product 0138 $stmt = $db->prepare('DELETE FROM tbl_product WHERE col_id = :id'); 0139 $stmt->bindValue(':id', $this->productId, PDO::PARAM_INT); 0140 $db->execute($stmt); 0141 } 0142 0143 /** Create one Product instance based on JSON input and verifies it is valid. */ 0144 public static function fromJson($jsonString) 0145 { 0146 $jsonObj = json_decode($jsonString); 0147 if (!property_exists($jsonObj, 'name')) 0148 throw new RESTException('No product name specified.', 400); 0149 0150 $p = new Product(); 0151 $p->name = $jsonObj->name; 0152 $p->schema = SchemaEntry::fromJson($jsonObj->schema, $p); 0153 if (property_exists($jsonObj, 'aggregation')) 0154 $p->aggregation = Aggregation::fromJson($jsonObj->aggregation); 0155 0156 // verify 0157 if (strlen($p->name) <= 0 || !is_string($p->name)) 0158 throw new RESTException('Empty product name.', 400); 0159 if (!ctype_alpha($p->name[0])) 0160 throw new RESTException("Invalid product name, must start with a letter.", 400); 0161 0162 return $p; 0163 } 0164 } 0165 0166 ?>