Commit a440cd46 authored by Volker Krause's avatar Volker Krause
Browse files

Completely port the server code to the new classes

parent 1938dce1
......@@ -18,6 +18,7 @@
require_once('datastore.php');
require_once('product.php');
require_once('sample.php');
require_once('survey.php');
require_once('utils.php');
......@@ -38,16 +39,8 @@ public function get_check_schema()
public function get_products()
{
$db = new DataStore();
$products = $db->allProducts();
$result = array();
foreach ($products as $p) {
$schema = $db->productSchema($p['id']);
$p['schema'] = $schema;
array_push($result, $p);
}
$json = json_encode($result);
$products = Product::allProducts($db);
$json = json_encode($products);
echo($json);
}
......@@ -55,52 +48,42 @@ public function get_products()
public function post_products()
{
$rawPostData = file_get_contents('php://input');
$product = json_decode($rawPostData, true);
if ($product['name'] == "")
Utils::httpError(400, "Product name is empty.");
$product = Product::fromJson($rawPostData);
$db = new DataStore();
$db->beginTransaction();
$product['id'] = $db->addProduct($product);
$db->updateProductSchema($product, $product['schema']);
$product->insert($db);
$db->commit();
echo('Product ' . $product['name'] . " added.");
echo('Product ' . $product->name . " added.");
}
/** Update a given product. */
public function put_products($productId)
public function put_products($productName)
{
$raw = file_get_contents('php://input');
$productData = json_decode($raw, true);
$newProduct = Product::fromJson($raw);
$db = new DataStore();
$db->beginTransaction();
$product = $db->productByName($productId);
if (is_null($product))
Utils::httpError(404, "Unknown product " . $productId . '.');
$oldProduct = Product::productByName($db, $productName);
if (is_null($oldProduct))
throw new RESTException('Product not found.', 404);
$db->updateProductSchema($product, $productData['schema']);
$oldProduct->update($db, $newProduct);
$db->commit();
echo('Product ' . $productData['name'] . ' updated.');
echo('Product ' . $productName . ' updated.');
}
/** Delete product and associated data. */
public function delete_products($productName)
{
if ($productName == "")
Utils::httpError(400, "Empty product name.");
$db = new DataStore();
$db->beginTransaction();
$product = $db->productByName($productName);
$product = Product::productByName($db, $productName);
if (is_null($product))
Utils::httpError(404, "Product not found.");
$schema = $db->productSchema($product['id']);
$db->deleteProduct($product, $schema);
throw new RESTException('Product not found.', 404);
$product->delete($db);
$db->commit();
echo('Product ' . $productName . ' deleted.');
}
......@@ -109,45 +92,10 @@ public function delete_products($productName)
public function get_data($productName)
{
$db = new DataStore();
$product = $db->productByName($productName);
$product = Product::productByName($db, $productName);
if (is_null($product))
Utils::httpError(404, "Unknown product.");
$schema = $db->productSchema($product['id']);
$productTableName = Utils::tableNameForProduct($product['name']);
$basicEntries = array();
foreach ($schema as $entry) {
switch ($entry['type']) {
case 'int':
case 'string':
$basicEntries[$entry['name']] = $entry;
break;
}
}
$data = $db->basicRecords($productTableName, $basicEntries);
foreach ($schema as $entry) {
$complexRecords = NULL;
$complexTableName = Utils::tableNameForComplexEntry($product['name'], $entry['name']);
switch ($entry['type']) {
case 'string_list':
$complexRecords = $db->stringListRecords($complexTableName);
break;
case 'ratio_set':
$complexRecords = $db->ratioSetRecords($complexTableName);
break;
}
if (is_null($complexRecords))
continue;
foreach ($data as &$row) {
if (!array_key_exists($row['id'], $complexRecords))
continue;
$row[$entry['name']] = $complexRecords[$row['id']];
}
}
echo(json_encode($data));
throw new RESTException('Product not found.', 404);
echo(Sample::dataAsJson($db, $product));
}
/** List all surveys for a product. */
......
......@@ -134,311 +134,6 @@ private function applySchemaChange($schemaDef)
$this->checkError($res);
}
/** List all products. */
public function allProducts()
{
$products = array();
$res = $this->db->query('SELECT * FROM products');
$this->checkError($res);
foreach ($res as $row)
array_push($products, $row);
return $products;
}
/** Add a new product. */
public function addProduct($product)
{
// create product entry
$res = $this->db->exec('INSERT INTO products (name) VALUES (' . $this->db->quote($product['name']) . ')');
$this->checkError($res);
// create product table
$tableName = Utils::tableNameForProduct($product['name']);
$res = $this->db->exec('CREATE TABLE ' . $tableName . ' ('
. 'id INTEGER PRIMARY KEY AUTOINCREMENT, '
. 'timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP)'
);
$this->checkError($res);
return $this->db->lastInsertId();
}
/** Delete a product. */
public function deleteProduct($product, $schema)
{
foreach ($schema as $entry) {
switch ($entry['type']) {
case "string_list":
$this->deleteComplexSchemaEntry($product, $entry);
break;
}
}
$res = $this->db->exec('DELETE FROM product_schema WHERE productId = ' . intval($product['id']));
$this->checkError($res);
$res = $this->db->exec('DELETE FROM products WHERE id = ' . intval($product['id']));
$this->checkError($res);
$res = $this->db->exec('DROP TABLE ' . Utils::tableNameForProduct($product['name']));
$this->checkError($res);
}
/** Look up product by name. */
public function productByName($name)
{
$res = $this->db->query('SELECT * FROM products WHERE name = ' . $this->db->quote($name));
$this->checkError($res);
foreach ($res as $row)
return $row;
return NULL;
}
/** Get the schema of product $productId. */
public function productSchema($productId)
{
$res = $this->db->query('SELECT * FROM product_schema WHERE productId = ' . intval($productId));
$this->checkError($res);
$schema = array();
foreach ($res as $row) {
$entry = array();
$entry['name'] = $row['name'];
$entry['type'] = $row['type'];
$entry['aggregation'] = $row['aggregation'];
array_push($schema, $entry);
}
return $schema;
}
/** Update product schema to $schema. */
public function updateProductSchema($product, $schema)
{
$oldSchema = array();
foreach ($this->productSchema($product['id']) as $o) {
$oldSchema[$o['name']] = $o;
}
foreach ($schema as $entry) {
if (array_key_exists($entry['name'], $oldSchema)) {
// update
$oldType = $oldSchema[$entry['name']]['type'];
if ($oldType != $entry['type'])
die('Cannot change data type of entry ' . $entry['name'] . '!');
$res = $this->db->exec('UPDATE product_schema SET ' .
'aggregation = ' . $this->db->quote($entry['aggregation']) . ' WHERE ' .
'productId = ' . intval($product['id']) . ' AND ' .
'name = ' . $this->db->quote($entry['name'])
);
$this->checkError($res);
} else {
// insert
$res = $this->db->exec('INSERT INTO product_schema (productId, name, type, aggregation) VALUES (' .
intval($product['id']) . ', ' .
$this->db->quote($entry['name']) . ', ' .
$this->db->quote($entry['type']) . ', ' .
$this->db->quote($entry['aggregation']) . ')'
);
$this->checkError($res);
$this->addProductSchemaEntry($product, $entry);
}
unset($oldSchema[$entry['name']]);
}
// delete whatever is left
foreach($oldSchema as $entry) {
$res = $this->db->exec('DELETE FROM product_schema WHERE ' .
'productId = ' . intval($product['id']) . ' AND ' .
'name = ' . $this->db->quote($entry['name'])
);
$this->checkError($res);
$this->deleteProductSchemaEntry($product, $entry);
}
}
/** Add a database elements needed for a given product schema entry. */
private function addProductSchemaEntry($product, $entry)
{
$productTable = Utils::tableNameForProduct($product['name']);
switch ($entry['type']) {
case 'string':
$res = $this->db->exec('ALTER TABLE ' . $productTable . ' ADD COLUMN ' . $entry['name'] . ' VARCHAR');
$this->checkError($res);
break;
case 'int':
$res = $this->db->exec('ALTER TABLE ' . $productTable . ' ADD COLUMN ' . $entry['name'] . ' INTEGER');
$this->checkError($res);
break;
case 'string_list':
{
$tableName = Utils::tableNameForComplexEntry($product['name'], $entry['name']);
$res = $this->db->exec('CREATE TABLE ' . $tableName . ' ('
. 'id INTEGER PRIMARY KEY AUTOINCREMENT, '
. 'sampleId INTEGER REFERENCES ' . $productTable . '(id), '
. 'value VARCHAR)'
);
$this->checkError($res);
break;
}
case 'ratio_set':
{
$tableName = Utils::tableNameForComplexEntry($product['name'], $entry['name']);
$res = $this->db->exec('CREATE TABLE ' . $tableName . ' ('
. 'id INTEGER PRIMARY KEY AUTOINCREMENT, '
. 'sampleId INTEGER REFERENCES ' . $productTable . '(id), '
. 'key VARCHAR, '
. 'value DOUBLE)'
);
$this->checkError($res);
break;
}
}
}
/** Delete database elements for a given product schema entry. */
private function deleteProductSchemaEntry($product, $entry)
{
$productTable = Utils::tableNameForProduct($product['name']);
switch ($entry['type']) {
case 'string':
case 'int':
$res = $this->db->exec('ALTER TABLE ' . $productTable . ' DROP COLUMN ' . $entry['name']);
// FIXME: DROP COLUMN does not work with sqlite
//$this->checkError($res);
break;
case 'string_list':
case 'ratio_set':
$this->deleteComplexSchemaEntry($product, $entry);
break;
}
}
/** Delete database elements for a complex product schema entry. */
private function deleteComplexSchemaEntry($product, $entry)
{
$tableName = Utils::tableNameForComplexEntry($product['name'], $entry['name']);
$res = $this->db->exec("DROP TABLE " . $tableName);
$this->checkError($res);
}
/** All data for the give product table and schema entries. */
public function basicRecords($productTableName, $basicEntries)
{
$res = $this->db->query('SELECT id, timestamp, ' . implode(', ', array_keys($basicEntries)) . ' FROM ' . $productTableName);
$this->checkError($res);
$data = array();
foreach ($res as $row) {
$sample = array();
$sample['id'] = $row['id'];
$sample['timestamp'] = $row['timestamp'];
foreach ($basicEntries as $col) {
if (is_null($row[$col['name']]))
continue;
switch ($col['type']) {
case 'int':
$sample[$col['name']] = intval($row[$col['name']]);
break;
case 'string':
$sample[$col['name']] = $row[$col['name']];
break;
}
}
array_push($data, $sample);
}
return $data;
}
/** Add a new record into the given product data table. */
public function addBasicRecord($productTable, $data)
{
$quotedData = array();
foreach(array_keys($data) as $key) {
if (is_string($data[$key]))
array_push($quotedData, $this->db->quote($data[$key]));
else
array_push($quotedData, $data[$key]);
}
$res = $this->db->exec('INSERT INTO ' . $productTable . ' ('
. implode(', ', array_keys($data)) . ') VALUES ('
. implode(', ', $quotedData) . ')'
);
$this->checkError($res);
return $this->db->lastInsertId();
}
/** Returns all string list records for the given complex entry table. */
public function stringListRecords($tableName)
{
$res = $this->db->query('SELECT sampleId, value FROM ' . $tableName);
$this->checkError($res);
$data = array();
foreach ($res as $row) {
if (!array_key_exists($row['sampleId'], $data))
$data[$row['sampleId']] = array();
array_push($data[$row['sampleId']], $row['value']);
}
return $data;
}
/** Add string list records into the given complex entry table. */
public function addStringListRecord($complexTable, $sampleId, $stringList)
{
foreach ($stringList as $str) {
if (!is_string($str))
continue;
$res = $this->db->exec('INSERT INTO ' . $complexTable . ' (sampleId, value) VALUES ('
. intval($sampleId) . ', ' . $this->db->quote($str) . ')'
);
$this->checkError($res);
}
}
/** Returns all ratio set record for the given complex entry table. */
public function ratioSetRecords($tableName)
{
$res = $this->db->query('SELECT sampleId, key, value FROM ' . $tableName);
$this->checkError($res);
$data = array();
foreach ($res as $row) {
if (!array_key_exists($row['sampleId'], $data))
$data[$row['sampleId']] = array();
$data[$row['sampleId']][$row['key']] = floatval($row['value']);
}
return $data;
}
/** Add ratio set record into the given complex entry table. */
public function addRatioSetRecord($complexTable, $sampleId, $ratioSet)
{
foreach (array_keys($ratioSet) as $ratioKey) {
$res = $this->db->exec('INSERT INTO ' . $complexTable . ' (sampleId, key, value) VALUES ('
. intval($sampleId) . ', '
. $this->db->quote($ratioKey) . ', '
. floatval($ratioSet[$ratioKey]) . ')'
);
$this->checkError($res);
}
}
/** List all active surveys for a given product. */
public function activeSurveysForProduct($product)
{
$res = $this->db->query('SELECT * FROM surveys WHERE productId = ' . $product['id'] . ' AND active = 1');
$this->checkError($res);
$surveys = array();
foreach ($res as $row)
array_push($surveys, $row);
return $surveys;
}
}
?>
......@@ -16,71 +16,38 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
include_once('datastore.php');
include_once('utils.php');
require_once('datastore.php');
require_once('product.php');
require_once('restexception.php');
require_once('utils.php');
require_once('sample.php');
require_once('survey.php');
/** Command handler for the data receiver. */
class Receiver
{
/** Data submission command. */
function post_submit()
function post_submit($productName)
{
// load JSON data sent by the client
$rawPostData = file_get_contents('php://input');
$data = json_decode($rawPostData, true);
// look up product
$db = new DataStore();
$db->beginTransaction();
$product = $db->productByName($data['productId']);
$product = Product::productByName($db, $productName);
if (is_null($product))
die("Unknown product.");
$productSchema = $db->productSchema($product['id']);
throw RESTException('Unknown product.', 404);
// write basic record
$tableName = Utils::tableNameForProduct($product['name']);
$basicData = array();
foreach ($productSchema as $entry) {
if (!array_key_exists($entry['name'], $data))
continue;
switch($entry['type']) {
case 'string':
$basicData[$entry['name']] = $data[$entry['name']];
break;
case 'int':
$basicData[$entry['name']] = intval($data[$entry['name']]);
break;
}
}
$recordId = $db->addBasicRecord($tableName, $basicData);
// add complex data to sub-tables
foreach ($productSchema as $entry) {
if (!array_key_exists($entry['name'], $data))
continue;
$tableName = Utils::tableNameForComplexEntry($product['name'], $entry['name']);
switch($entry['type']) {
case 'string_list':
$db->addStringListRecord($tableName, $recordId, $data[$entry['name']]);
break;
case 'ratio_set':
$db->addRatioSetRecord($tableName, $recordId, $data[$entry['name']]);
break;
}
}
Sample::insert($db, $rawPostData, $product);
// read survey from db
$responseData = array();
$surveys = $db->activeSurveysForProduct($product);
if (sizeof($surveys) > 0) {
$surveyInfo = array();
$surveyInfo['id'] = intval($surveys[0]['id']);
$surveyInfo['url'] = $surveys[0]['url'];
$responseData['survey'] = $surveyInfo;
}
$surveys = Survey::activeSurveysForProduct($db, $product);
$responseData['surveys'] = $surveys;
$db->commit();
echo(json_encode($responseData));
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment