[mod] alles mögliche verbessert [mod] SQLite-Anbindung
This commit is contained in:
parent
3497430fa4
commit
42e6b13597
18 changed files with 1151 additions and 389 deletions
|
@ -3,6 +3,4 @@
|
|||
## Zu erledigen
|
||||
|
||||
- sanitizing überprüfen
|
||||
- Persistenz mit SQLite
|
||||
- Datum für Dokumente ergänzen
|
||||
- für jedes bestehende Dokument soll es Funktionen zum Aufbereiten und Herunderladen geben in den Formaten pdf/odt (pandoc nutzen) und ogg
|
||||
|
|
|
@ -34,6 +34,7 @@ proof-of-concept für Partei-Arbeits-Dokumenten-Verwaltung, welche hörbare Vers
|
|||
### Voraussetzungen
|
||||
|
||||
- [PHP](https://www.php.net/)-Interpreter für Kommandozeile (Debian-Paket-Name: `php-cli`)
|
||||
- SQLite3-Modul für PHP (Debian-Paket-Name: `php-sqlite3`)
|
||||
- [FFmpeg](https://ffmpeg.org/) (Debian-Paket-Name: `ffmpeg`)
|
||||
- Browser
|
||||
|
||||
|
|
43
source/entities/doc.php
Normal file
43
source/entities/doc.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox\entities\doc;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class entity
|
||||
{
|
||||
public string $title;
|
||||
|
||||
public array $authors;
|
||||
|
||||
public string $content;
|
||||
|
||||
public ?string $reasoning;
|
||||
|
||||
public function __construct(
|
||||
string $title,
|
||||
array $authors,
|
||||
string $content,
|
||||
?string $reasoning
|
||||
)
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->authors = $authors;
|
||||
$this->content = $content;
|
||||
$this->reasoning = $reasoning;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function empty_() : entity
|
||||
{
|
||||
return (new entity(
|
||||
'',
|
||||
[],
|
||||
'',
|
||||
null,
|
||||
));
|
||||
}
|
39
source/helpers/list.php
Normal file
39
source/helpers/list.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox\helpers\list_;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function sequence(int $length) : array
|
||||
{
|
||||
return (($length <= 0) ? [] : \array_merge(sequence($length-1), [$length-1]));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function map(array $list, \Closure $function) : array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($list as $element)
|
||||
{
|
||||
\array_push($result, ($function)($element));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function to_map(array $pairs) : array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($pairs as $pair)
|
||||
{
|
||||
$result[$pair['key']] = $pair['value'];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
?>
|
112
source/helpers/sqlite.php
Normal file
112
source/helpers/sqlite.php
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox\helpers\sqlite;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function placeholder(
|
||||
string $name
|
||||
) : string
|
||||
{
|
||||
return (':' . $name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function map_type(string $type) : string
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case 'bool':
|
||||
{
|
||||
return 'INTEGER';
|
||||
break;
|
||||
}
|
||||
case 'integer':
|
||||
{
|
||||
return 'INTEGER';
|
||||
break;
|
||||
}
|
||||
case 'string':
|
||||
{
|
||||
return 'TEXT';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new \Exception('unhandled type: ' . $type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function format_value($value) : string
|
||||
{
|
||||
if ($value === null)
|
||||
{
|
||||
return 'NULL';
|
||||
}
|
||||
else
|
||||
{
|
||||
$type = \gettype($value);
|
||||
switch ($type)
|
||||
{
|
||||
case 'bool':
|
||||
{
|
||||
return ($value ? '1' : '0');
|
||||
break;
|
||||
}
|
||||
case 'int':
|
||||
{
|
||||
return \sprintf('%u', $value);
|
||||
break;
|
||||
}
|
||||
case 'string':
|
||||
{
|
||||
return \sprintf("'%s'", $value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new \Exception('unhandled type: ' . $type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function query(string $path, string $template, array $arguments) : array
|
||||
{
|
||||
/*
|
||||
\error_log(
|
||||
\json_encode(
|
||||
[
|
||||
'template' => $template,
|
||||
'arguments' => $arguments,
|
||||
]
|
||||
)
|
||||
);
|
||||
*/
|
||||
$connection = new \SQLite3($path);
|
||||
$statement = $connection->prepare($template);
|
||||
foreach ($arguments as $key => $value)
|
||||
{
|
||||
$statement->bindValue(placeholder($key), $value);
|
||||
}
|
||||
$result = $statement->execute();
|
||||
$last_insert_id = $connection->lastInsertRowID();
|
||||
return [
|
||||
'result' => $result,
|
||||
'last_insert_id' => $last_insert_id,
|
||||
];
|
||||
}
|
||||
|
||||
?>
|
25
source/helpers/storage-interface.php
Normal file
25
source/helpers/storage-interface.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox\helpers\storage;
|
||||
|
||||
|
||||
/**
|
||||
* @template Key
|
||||
* @template Value
|
||||
*/
|
||||
interface interface_
|
||||
{
|
||||
public function setup() : void;
|
||||
|
||||
public function list_() : array;
|
||||
|
||||
public function read(/*Key */$id)/* : Value*/;
|
||||
|
||||
public function create(/*Value */$value)/* : Key*/;
|
||||
|
||||
public function update(/*Key */$id, /*Value */$value) : void;
|
||||
|
||||
public function delete(/*Key */$id) : void;
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,32 +2,31 @@
|
|||
|
||||
namespace rosavox\helpers\storage;
|
||||
|
||||
/**
|
||||
*/
|
||||
interface interface_
|
||||
{
|
||||
public function list_() : array;
|
||||
|
||||
public function read(int $id);
|
||||
|
||||
public function create($value) : int;
|
||||
|
||||
public function update(int $id, $value) : void;
|
||||
|
||||
public function delete(int $id) : void;
|
||||
}
|
||||
require_once('helpers/storage-interface.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class class_jsonfile implements interface_
|
||||
class class_jsonfile implements interface_/*<int,any>*/
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private string $path;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private \Closure $id_encode;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private \Closure $id_decode;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct(
|
||||
string $path,
|
||||
\Closure $id_encode,
|
||||
|
@ -39,6 +38,9 @@ class class_jsonfile implements interface_
|
|||
$this->id_decode = $id_decode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private function get() : array
|
||||
{
|
||||
$content = (\file_exists($this->path) ? \file_get_contents($this->path) : null);
|
||||
|
@ -51,12 +53,26 @@ class class_jsonfile implements interface_
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private function put(array $data) : void
|
||||
{
|
||||
$content = \json_encode($data, \JSON_PRETTY_PRINT);
|
||||
\file_put_contents($this->path, $content);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function setup() : void
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function list_() : array
|
||||
{
|
||||
$data = $this->get();
|
||||
|
@ -69,7 +85,10 @@ class class_jsonfile implements interface_
|
|||
);
|
||||
}
|
||||
|
||||
public function read(int $id)
|
||||
|
||||
/**
|
||||
*/
|
||||
public function read($id)
|
||||
{
|
||||
$data = $this->get();
|
||||
$id_encoded = ($this->id_encode)($id);
|
||||
|
@ -83,7 +102,7 @@ class class_jsonfile implements interface_
|
|||
}
|
||||
}
|
||||
|
||||
public function create($value) : int
|
||||
public function create($value)
|
||||
{
|
||||
$data = $this->get();
|
||||
$id = ($data['last_id'] + 1);
|
||||
|
@ -94,7 +113,10 @@ class class_jsonfile implements interface_
|
|||
return $id;
|
||||
}
|
||||
|
||||
public function update(int $id, $value) : void
|
||||
|
||||
/**
|
||||
*/
|
||||
public function update($id, $value) : void
|
||||
{
|
||||
$data = $this->get();
|
||||
$id_encoded = ($this->id_encode)($id);
|
||||
|
@ -109,7 +131,10 @@ class class_jsonfile implements interface_
|
|||
}
|
||||
}
|
||||
|
||||
public function delete(int $id) : void
|
||||
|
||||
/**
|
||||
*/
|
||||
public function delete($id) : void
|
||||
{
|
||||
$data = $this->get();
|
||||
$id_encoded = ($this->id_encode)($id);
|
||||
|
@ -123,6 +148,7 @@ class class_jsonfile implements interface_
|
|||
$this->put($data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
311
source/helpers/storage-sqlitetable.php
Normal file
311
source/helpers/storage-sqlitetable.php
Normal file
|
@ -0,0 +1,311 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox\helpers\storage;
|
||||
|
||||
require_once('helpers/list.php');
|
||||
require_once('helpers/sqlite.php');
|
||||
require_once('helpers/storage-interface.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class class_sqlitetable implements interface_/*<int,list<any>>*/
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public static function field_name(
|
||||
array $field
|
||||
) : string
|
||||
{
|
||||
return \rosavox\helpers\string_\coin(
|
||||
'field_{{name}}',
|
||||
[
|
||||
'name' => $field['name'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private string $path;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
|
||||
/**
|
||||
* @param $fields {
|
||||
* list<
|
||||
* record<
|
||||
* name:string,
|
||||
* type:string,
|
||||
* nullable:boolean,
|
||||
* >
|
||||
* >
|
||||
* }
|
||||
*/
|
||||
private array $fields;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct(
|
||||
string $path,
|
||||
string $name,
|
||||
array $fields
|
||||
)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->name = $name;
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function setup() : void
|
||||
{
|
||||
$result = \rosavox\helpers\sqlite\query(
|
||||
$this->path,
|
||||
\rosavox\helpers\string_\coin(
|
||||
'CREATE TABLE IF NOT EXISTS {{name}}(id INTEGER PRIMARY KEY AUTOINCREMENT, {{fields}});',
|
||||
[
|
||||
'name' => $this->name,
|
||||
'fields' => \implode(
|
||||
', ',
|
||||
\array_map(
|
||||
fn ($field) => \rosavox\helpers\string_\coin(
|
||||
'{{name}} {{type}}{{macro_nullable}}',
|
||||
[
|
||||
'name' => self::field_name($field),
|
||||
'type' => \rosavox\helpers\sqlite\map_type($field['type']),
|
||||
'macro_nullable' => ($field['nullable'] ? '' : ' NOT NULL'),
|
||||
]
|
||||
),
|
||||
$this->fields
|
||||
)
|
||||
),
|
||||
]
|
||||
),
|
||||
[
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function list_() : array
|
||||
{
|
||||
$result = \rosavox\helpers\sqlite\query(
|
||||
$this->path,
|
||||
\rosavox\helpers\string_\coin(
|
||||
'SELECT id,{{fields}} FROM {{name}}',
|
||||
[
|
||||
'fields' => \implode(
|
||||
', ',
|
||||
\rosavox\helpers\list_\map(
|
||||
$this->fields,
|
||||
fn ($field) => self::field_name($field)
|
||||
)
|
||||
),
|
||||
'name' => $this->name,
|
||||
]
|
||||
),
|
||||
[
|
||||
]
|
||||
);
|
||||
$entries = [];
|
||||
while (true)
|
||||
{
|
||||
$row = $result['result']->fetchArray(\SQLITE3_NUM);
|
||||
if ($row !== false)
|
||||
{
|
||||
\array_push(
|
||||
$entries,
|
||||
[
|
||||
'id' => $row[0],
|
||||
'value' => \array_slice($row, 1),
|
||||
]
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $entries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function read($id)
|
||||
{
|
||||
$result = \rosavox\helpers\sqlite\query(
|
||||
$this->path,
|
||||
\rosavox\helpers\string_\coin(
|
||||
'SELECT {{fields}} FROM {{name}} WHERE (id = {{id}});',
|
||||
[
|
||||
'fields' => \implode(
|
||||
', ',
|
||||
\rosavox\helpers\list_\map(
|
||||
$this->fields,
|
||||
fn ($field) => self::field_name($field)
|
||||
)
|
||||
),
|
||||
'name' => $this->name,
|
||||
'id' => \rosavox\helpers\sqlite\placeholder('id'),
|
||||
]
|
||||
),
|
||||
[
|
||||
'id' => $id,
|
||||
]
|
||||
);
|
||||
$rows = [];
|
||||
while (true)
|
||||
{
|
||||
$row = $result['result']->fetchArray(\SQLITE3_NUM);
|
||||
if ($row !== false)
|
||||
{
|
||||
\array_push($rows, $row);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$count = \count($rows);
|
||||
if ($count === 0)
|
||||
{
|
||||
throw (new \Exception('not found'));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($count > 1)
|
||||
{
|
||||
throw (new \Exception('ambiguous'));
|
||||
}
|
||||
else
|
||||
{
|
||||
return $rows[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function create($row)
|
||||
{
|
||||
$result = \rosavox\helpers\sqlite\query(
|
||||
$this->path,
|
||||
\rosavox\helpers\string_\coin(
|
||||
'INSERT INTO {{name}}({{schema}}) VALUES ({{values}});',
|
||||
[
|
||||
'name' => $this->name,
|
||||
'schema' => \implode(
|
||||
', ',
|
||||
\array_map(
|
||||
fn ($field) => self::field_name($field),
|
||||
$this->fields
|
||||
)
|
||||
),
|
||||
'values' => \implode(
|
||||
', ',
|
||||
\array_map(
|
||||
fn ($field) => \rosavox\helpers\sqlite\placeholder(
|
||||
self::field_name($field)
|
||||
),
|
||||
$this->fields
|
||||
)
|
||||
),
|
||||
]
|
||||
),
|
||||
\rosavox\helpers\list_\to_map(
|
||||
\rosavox\helpers\list_\map(
|
||||
\rosavox\helpers\list_\sequence(
|
||||
\count($this->fields)
|
||||
),
|
||||
fn ($index) => [
|
||||
'key' => self::field_name($this->fields[$index]),
|
||||
'value' => $row[$index],
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
return $result['last_insert_id'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function update($id, $row) : void
|
||||
{
|
||||
$result = \rosavox\helpers\sqlite\query(
|
||||
$this->path,
|
||||
\rosavox\helpers\string_\coin(
|
||||
'UPDATE {{name}} SET {{sets}} WHERE (id = :id);',
|
||||
[
|
||||
'name' => $this->name,
|
||||
'sets' => \implode(
|
||||
', ',
|
||||
\array_map(
|
||||
fn ($field) => \rosavox\helpers\string_\coin(
|
||||
'{{name}} = {{placeholder}}',
|
||||
[
|
||||
'name' => self::field_name($field),
|
||||
'placeholder' => \rosavox\helpers\sqlite\placeholder(self::field_name($field)),
|
||||
]
|
||||
),
|
||||
$this->fields
|
||||
)
|
||||
),
|
||||
]
|
||||
),
|
||||
\array_merge(
|
||||
[
|
||||
'id' => $id,
|
||||
],
|
||||
\rosavox\helpers\list_\to_map(
|
||||
\rosavox\helpers\list_\map(
|
||||
\rosavox\helpers\list_\sequence(
|
||||
\count($this->fields)
|
||||
),
|
||||
fn ($index) => [
|
||||
'key' => self::field_name($this->fields[$index]),
|
||||
'value' => $row[$index],
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function delete($id) : void
|
||||
{
|
||||
$result = \rosavox\helpers\sqlite\query(
|
||||
$this->path,
|
||||
\rosavox\helpers\string_\coin(
|
||||
'DELETE * FROM {{name}} WHERE (id = {{id}});',
|
||||
[
|
||||
'name' => $this->name,
|
||||
'id' => \rosavox\helpers\sqlite\placeholder('id'),
|
||||
]
|
||||
),
|
||||
[
|
||||
'id' => $id,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,208 +1,5 @@
|
|||
<?php
|
||||
|
||||
require_once('helpers/string.php');
|
||||
require_once('helpers/misc.php');
|
||||
require_once('services/doc.php');
|
||||
|
||||
|
||||
\rosavox\services\doc\init();
|
||||
|
||||
$mode = ($_GET['mode'] ?? 'list');
|
||||
$id_encoded = (! empty($_GET['id']) ? $_GET['id'] : null);
|
||||
$id = (($id_encoded === null) ? null : \intval($id_encoded));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function make_link(string $mode, array $args) : string
|
||||
{
|
||||
$a = \array_merge($args, ['mode' => $mode]);
|
||||
return (
|
||||
'?'
|
||||
.
|
||||
\implode(
|
||||
'&',
|
||||
\array_map(
|
||||
fn ($key) => \rosavox\helpers\string_\coin(
|
||||
'{{key}}={{value}}',
|
||||
[
|
||||
'key' => $key,
|
||||
'value' => $a[$key],
|
||||
]
|
||||
),
|
||||
\array_keys($a)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function nav(string $mode, array $args) : void
|
||||
{
|
||||
\rosavox\helpers\misc\navigate(make_link($mode, $args));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function render_list() : string
|
||||
{
|
||||
return \rosavox\helpers\misc\render(
|
||||
'docs-list',
|
||||
[
|
||||
'label_make' => \rosavox\helpers\misc\translate('action.make'),
|
||||
'link_make' => make_link('make', []),
|
||||
'entries' => \implode(
|
||||
"\n",
|
||||
\array_map(
|
||||
fn ($entry) => \rosavox\helpers\misc\render(
|
||||
'docs-list-entry',
|
||||
[
|
||||
'label_read' => \rosavox\helpers\misc\translate('action.read'),
|
||||
'value_text' => $entry['value']['title'],
|
||||
'value_link_open' => make_link('edit', ['id' => \sprintf('%u', $entry['id'])]),
|
||||
'value_link_read' => \rosavox\services\doc\readable_path($entry['id']),
|
||||
'area_download_readable' => (
|
||||
(fn ($name, $path) => (
|
||||
(! \file_exists($path))
|
||||
?
|
||||
\rosavox\helpers\misc\render(
|
||||
'state-waiting',
|
||||
[
|
||||
'info' => \rosavox\helpers\misc\translate('state.generating'),
|
||||
]
|
||||
)
|
||||
:
|
||||
\rosavox\helpers\misc\render(
|
||||
'download',
|
||||
[
|
||||
'text' => \rosavox\helpers\misc\translate('item.readable.short'),
|
||||
'tooltip' => \rosavox\helpers\string_\coin(
|
||||
'{{item}} {{action}}',
|
||||
[
|
||||
'action' => \rosavox\helpers\misc\translate('action.download'),
|
||||
'item' => \rosavox\helpers\misc\translate('item.readable.long'),
|
||||
]
|
||||
),
|
||||
'link' => $path,
|
||||
'name' => \rosavox\helpers\string_\coin(
|
||||
'{{name}}.md',
|
||||
[
|
||||
'name' => $name,
|
||||
]
|
||||
),
|
||||
'type' => 'text/markdown',
|
||||
]
|
||||
)
|
||||
)) (
|
||||
\rosavox\services\doc\name($entry['id']),
|
||||
\rosavox\services\doc\readable_path($entry['id'])
|
||||
)
|
||||
),
|
||||
'area_download_audible' => (
|
||||
(fn ($name, $path) => (
|
||||
(! \file_exists($path))
|
||||
?
|
||||
\rosavox\helpers\misc\render(
|
||||
'state-waiting',
|
||||
[
|
||||
'info' => \rosavox\helpers\misc\translate('state.generating'),
|
||||
]
|
||||
)
|
||||
:
|
||||
\rosavox\helpers\misc\render(
|
||||
'download',
|
||||
[
|
||||
'text' => \rosavox\helpers\misc\translate('item.audible.short'),
|
||||
'tooltip' => \rosavox\helpers\string_\coin(
|
||||
'{{item}} {{action}}',
|
||||
[
|
||||
'action' => \rosavox\helpers\misc\translate('action.download'),
|
||||
'item' => \rosavox\helpers\misc\translate('item.audible.long'),
|
||||
]
|
||||
),
|
||||
'link' => $path,
|
||||
'name' => \rosavox\helpers\string_\coin(
|
||||
'{{name}}.oga',
|
||||
[
|
||||
'name' => $name,
|
||||
]
|
||||
),
|
||||
'type' => 'audio/ogg',
|
||||
]
|
||||
)
|
||||
)) (
|
||||
\rosavox\services\doc\name($entry['id']),
|
||||
\rosavox\services\doc\audible_path($entry['id'])
|
||||
)
|
||||
),
|
||||
'area_hear' => (
|
||||
(fn ($name, $path) => (
|
||||
(! \file_exists($path))
|
||||
?
|
||||
\rosavox\helpers\misc\render(
|
||||
'state-waiting',
|
||||
[
|
||||
'info' => \rosavox\helpers\misc\translate('state.generating'),
|
||||
]
|
||||
)
|
||||
:
|
||||
\rosavox\helpers\misc\render(
|
||||
'player',
|
||||
[
|
||||
'source_path' => $path,
|
||||
]
|
||||
)
|
||||
)) (
|
||||
\rosavox\services\doc\name($entry['id']),
|
||||
\rosavox\services\doc\audible_path($entry['id'])
|
||||
)
|
||||
),
|
||||
]
|
||||
),
|
||||
\rosavox\services\doc\list_()
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function render_edit(?int $id) : string
|
||||
{
|
||||
$doc = (
|
||||
($id === null)
|
||||
?
|
||||
\rosavox\services\doc\empty_()
|
||||
:
|
||||
\rosavox\services\doc\read($id)
|
||||
);
|
||||
return \rosavox\helpers\misc\render(
|
||||
'docs-edit',
|
||||
[
|
||||
'label_action_back' => \rosavox\helpers\misc\translate('action.back'),
|
||||
'label_action_save' => \rosavox\helpers\misc\translate('action.save'),
|
||||
'label_action_delete' => \rosavox\helpers\misc\translate('action.delete'),
|
||||
'label_doc_title' => \rosavox\helpers\misc\translate('domain.doc.title'),
|
||||
'label_doc_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'),
|
||||
'label_doc_content' => \rosavox\helpers\misc\translate('domain.doc.content'),
|
||||
'label_doc_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'),
|
||||
'value_action_back' => make_link('list', []),
|
||||
'value_action_save' => make_link('save', (($id === null) ? [] : ['id' => \strval($id)])),
|
||||
'value_action_delete' => make_link('delete', (($id === null) ? [] : ['id' => \strval($id)])),
|
||||
'value_doc_title' => $doc['title'],
|
||||
'value_doc_authors' => \implode(', ', $doc['authors']),
|
||||
'value_doc_content' => $doc['content'],
|
||||
'value_doc_reasoning' => ($doc['reasoning'] ?? ''),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
require_once('main.php');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -213,63 +10,6 @@ function render_edit(?int $id) : string
|
|||
</head>
|
||||
<body>
|
||||
<h1>rosavox</h1>
|
||||
<?php
|
||||
switch ($mode)
|
||||
{
|
||||
case 'delete':
|
||||
{
|
||||
if ($id === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
\rosavox\services\doc\delete($id);
|
||||
}
|
||||
nav('list', []);
|
||||
break;
|
||||
}
|
||||
case 'save':
|
||||
{
|
||||
$doc = [
|
||||
'title' => $_POST['title'],
|
||||
'authors' => \explode(',', $_POST['authors']),
|
||||
'content' => $_POST['content'],
|
||||
'reasoning' => (empty($_POST['reasoning']) ? null : $_GET['reasoning']),
|
||||
];
|
||||
if ($id === null)
|
||||
{
|
||||
$id = \rosavox\services\doc\create($doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
\rosavox\services\doc\update($id, $doc);
|
||||
}
|
||||
// nav('edit', ['id' => \rosavox\services\doc\id_encode($id)]);
|
||||
nav('list', []);
|
||||
break;
|
||||
}
|
||||
case 'list':
|
||||
{
|
||||
echo(render_list());
|
||||
break;
|
||||
}
|
||||
case 'make':
|
||||
{
|
||||
echo(render_edit(null));
|
||||
break;
|
||||
}
|
||||
case 'edit':
|
||||
{
|
||||
echo(render_edit($id));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new \Exception(\sprintf('invalid mode: %s', $mode)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php \rosavox\main($_GET, $_POST); ?>
|
||||
</body>
|
||||
</html>
|
||||
|
|
90
source/main.php
Normal file
90
source/main.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox;
|
||||
|
||||
require_once('entities/doc.php');
|
||||
require_once('services/doc.php');
|
||||
require_once('nav.php');
|
||||
require_once('renderings.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function main(array $get, array $post) : void
|
||||
{
|
||||
// init
|
||||
\rosavox\services\doc\init();
|
||||
|
||||
// args
|
||||
$mode = (
|
||||
$get['mode']
|
||||
??
|
||||
'list'
|
||||
);
|
||||
$id = (
|
||||
(! empty($get['id']))
|
||||
?
|
||||
\intval($get['id'])
|
||||
:
|
||||
null
|
||||
);
|
||||
|
||||
// exec
|
||||
switch ($mode)
|
||||
{
|
||||
case 'delete':
|
||||
{
|
||||
if ($id === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
\rosavox\services\doc\remove($id);
|
||||
}
|
||||
nav('list', []);
|
||||
break;
|
||||
}
|
||||
case 'save':
|
||||
{
|
||||
$doc = new \rosavox\entities\doc\entity(
|
||||
$post['title'],
|
||||
\explode(',', $post['authors']),
|
||||
$post['content'],
|
||||
(empty($post['reasoning']) ? null : $post['reasoning'])
|
||||
);
|
||||
if ($id === null)
|
||||
{
|
||||
$id = \rosavox\services\doc\add($doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
\rosavox\services\doc\change($id, $doc);
|
||||
}
|
||||
// \rosavox\nav('edit', ['id' => \strval($id)]);
|
||||
\rosavox\nav('list', []);
|
||||
break;
|
||||
}
|
||||
case 'list':
|
||||
{
|
||||
echo(\rosavox\renderings\doc_list());
|
||||
break;
|
||||
}
|
||||
case 'make':
|
||||
{
|
||||
echo(\rosavox\renderings\doc_edit(null));
|
||||
break;
|
||||
}
|
||||
case 'edit':
|
||||
{
|
||||
echo(\rosavox\renderings\doc_edit($id));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new \Exception(\sprintf('invalid mode: %s', $mode)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
42
source/nav.php
Normal file
42
source/nav.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox;
|
||||
|
||||
require_once('helpers/list.php');
|
||||
require_once('helpers/string.php');
|
||||
require_once('helpers/misc.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function make_link(string $mode, array $args) : string
|
||||
{
|
||||
$a = \array_merge($args, ['mode' => $mode]);
|
||||
return (
|
||||
'?'
|
||||
.
|
||||
\implode(
|
||||
'&',
|
||||
\rosavox\helpers\list_\map(
|
||||
\array_keys($a),
|
||||
fn ($key) => \rosavox\helpers\string_\coin(
|
||||
'{{key}}={{value}}',
|
||||
[
|
||||
'key' => $key,
|
||||
'value' => $a[$key],
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function nav(string $mode, array $args) : void
|
||||
{
|
||||
\rosavox\helpers\misc\navigate(make_link($mode, $args));
|
||||
}
|
||||
|
||||
?>
|
170
source/renderings.php
Normal file
170
source/renderings.php
Normal file
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox\renderings;
|
||||
|
||||
require_once('helpers/list.php');
|
||||
require_once('helpers/string.php');
|
||||
require_once('helpers/misc.php');
|
||||
require_once('entities/doc.php');
|
||||
require_once('services/doc.php');
|
||||
require_once('nav.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function doc_list() : string
|
||||
{
|
||||
return \rosavox\helpers\misc\render(
|
||||
'docs-list',
|
||||
[
|
||||
'label_make' => \rosavox\helpers\misc\translate('action.make'),
|
||||
'link_make' => \rosavox\make_link('make', []),
|
||||
'entries' => \implode(
|
||||
"\n",
|
||||
\rosavox\helpers\list_\map(
|
||||
\rosavox\services\doc\dump(),
|
||||
fn ($entry) => \rosavox\helpers\misc\render(
|
||||
'docs-list-entry',
|
||||
[
|
||||
'label_read' => \rosavox\helpers\misc\translate('action.read'),
|
||||
'value_text' => $entry['value']->title,
|
||||
'value_link_open' => \rosavox\make_link('edit', ['id' => \sprintf('%u', $entry['id'])]),
|
||||
'value_link_read' => \rosavox\services\doc\readable_path($entry['id']),
|
||||
'area_download_readable' => (
|
||||
(fn ($name, $path) => (
|
||||
(! \file_exists($path))
|
||||
?
|
||||
\rosavox\helpers\misc\render(
|
||||
'state-waiting',
|
||||
[
|
||||
'info' => \rosavox\helpers\misc\translate('state.generating'),
|
||||
]
|
||||
)
|
||||
:
|
||||
\rosavox\helpers\misc\render(
|
||||
'download',
|
||||
[
|
||||
'text' => \rosavox\helpers\misc\translate('item.readable.short'),
|
||||
'tooltip' => \rosavox\helpers\string_\coin(
|
||||
'{{item}} {{action}}',
|
||||
[
|
||||
'action' => \rosavox\helpers\misc\translate('action.download'),
|
||||
'item' => \rosavox\helpers\misc\translate('item.readable.long'),
|
||||
]
|
||||
),
|
||||
'link' => $path,
|
||||
'name' => \rosavox\helpers\string_\coin(
|
||||
'{{name}}.md',
|
||||
[
|
||||
'name' => $name,
|
||||
]
|
||||
),
|
||||
'type' => 'text/markdown',
|
||||
]
|
||||
)
|
||||
)) (
|
||||
\rosavox\services\doc\name($entry['id']),
|
||||
\rosavox\services\doc\readable_path($entry['id'])
|
||||
)
|
||||
),
|
||||
'area_download_audible' => (
|
||||
(fn ($name, $path) => (
|
||||
(! \file_exists($path))
|
||||
?
|
||||
\rosavox\helpers\misc\render(
|
||||
'state-waiting',
|
||||
[
|
||||
'info' => \rosavox\helpers\misc\translate('state.generating'),
|
||||
]
|
||||
)
|
||||
:
|
||||
\rosavox\helpers\misc\render(
|
||||
'download',
|
||||
[
|
||||
'text' => \rosavox\helpers\misc\translate('item.audible.short'),
|
||||
'tooltip' => \rosavox\helpers\string_\coin(
|
||||
'{{item}} {{action}}',
|
||||
[
|
||||
'action' => \rosavox\helpers\misc\translate('action.download'),
|
||||
'item' => \rosavox\helpers\misc\translate('item.audible.long'),
|
||||
]
|
||||
),
|
||||
'link' => $path,
|
||||
'name' => \rosavox\helpers\string_\coin(
|
||||
'{{name}}.oga',
|
||||
[
|
||||
'name' => $name,
|
||||
]
|
||||
),
|
||||
'type' => 'audio/ogg',
|
||||
]
|
||||
)
|
||||
)) (
|
||||
\rosavox\services\doc\name($entry['id']),
|
||||
\rosavox\services\doc\audible_path($entry['id'])
|
||||
)
|
||||
),
|
||||
'area_hear' => (
|
||||
(fn ($name, $path) => (
|
||||
(! \file_exists($path))
|
||||
?
|
||||
\rosavox\helpers\misc\render(
|
||||
'state-waiting',
|
||||
[
|
||||
'info' => \rosavox\helpers\misc\translate('state.generating'),
|
||||
]
|
||||
)
|
||||
:
|
||||
\rosavox\helpers\misc\render(
|
||||
'player',
|
||||
[
|
||||
'source_path' => $path,
|
||||
]
|
||||
)
|
||||
)) (
|
||||
\rosavox\services\doc\name($entry['id']),
|
||||
\rosavox\services\doc\audible_path($entry['id'])
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function doc_edit(?int $id) : string
|
||||
{
|
||||
$doc = (
|
||||
($id === null)
|
||||
?
|
||||
\rosavox\entities\doc\empty_()
|
||||
:
|
||||
\rosavox\services\doc\get($id)
|
||||
);
|
||||
return \rosavox\helpers\misc\render(
|
||||
'docs-edit',
|
||||
[
|
||||
'label_action_back' => \rosavox\helpers\misc\translate('action.back'),
|
||||
'label_action_save' => \rosavox\helpers\misc\translate('action.save'),
|
||||
'label_action_delete' => \rosavox\helpers\misc\translate('action.delete'),
|
||||
'label_doc_title' => \rosavox\helpers\misc\translate('domain.doc.title'),
|
||||
'label_doc_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'),
|
||||
'label_doc_content' => \rosavox\helpers\misc\translate('domain.doc.content'),
|
||||
'label_doc_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'),
|
||||
'value_action_back' => \rosavox\make_link('list', []),
|
||||
'value_action_save' => \rosavox\make_link('save', (($id === null) ? [] : ['id' => \strval($id)])),
|
||||
'value_action_delete' => \rosavox\make_link('delete', (($id === null) ? [] : ['id' => \strval($id)])),
|
||||
'value_doc_title' => $doc->title,
|
||||
'value_doc_authors' => \implode(', ', $doc->authors),
|
||||
'value_doc_content' => $doc->content,
|
||||
'value_doc_reasoning' => ($doc->reasoning ?? ''),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
164
source/repositories/doc.php
Normal file
164
source/repositories/doc.php
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace rosavox\repositories\doc;
|
||||
|
||||
require_once('helpers/storage-interface.php');
|
||||
require_once('helpers/storage-jsonfile.php');
|
||||
require_once('helpers/storage-sqlitetable.php');
|
||||
|
||||
require_once('entities/doc.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class repo implements \rosavox\helpers\storage\interface_/*<int,\rosavox\entities\doc\entity>*/
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private \rosavox\helpers\storage\interface_ $core;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
/*
|
||||
$this->core = new \rosavox\helpers\storage\class_jsonfile(
|
||||
'docs.json',
|
||||
fn ($id) => \sprintf('%u', $id),
|
||||
fn ($id_encoded) => \intval($id_encoded)
|
||||
);
|
||||
*/
|
||||
$this->core = new \rosavox\helpers\storage\class_sqlitetable(
|
||||
'data.sqlite',
|
||||
'docs',
|
||||
[
|
||||
[
|
||||
'name' => 'title',
|
||||
'type' => 'string',
|
||||
'nullable' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'authors',
|
||||
'type' => 'string',
|
||||
'nullable' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'content',
|
||||
'type' => 'string',
|
||||
'nullable' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'reasoning',
|
||||
'type' => 'string',
|
||||
'nullable' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private static ?repo $instance = null;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public static function get_instance()
|
||||
{
|
||||
if (self::$instance === null)
|
||||
{
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private static function encode(\rosavox\entities\doc\entity $doc) : array
|
||||
{
|
||||
return [
|
||||
$doc->title,
|
||||
\implode(',', $doc->authors),
|
||||
$doc->content,
|
||||
$doc->reasoning,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private static function decode(array $row) : \rosavox\entities\doc\entity
|
||||
{
|
||||
return (new \rosavox\entities\doc\entity(
|
||||
$row[0],
|
||||
\explode(',', $row[1]),
|
||||
$row[2],
|
||||
$row[3],
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public function setup() : void
|
||||
{
|
||||
$this->core->setup();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public function list_() : array
|
||||
{
|
||||
return \rosavox\helpers\list_\map(
|
||||
$this->core->list_(),
|
||||
fn ($entry) => [
|
||||
'id' => $entry['id'],
|
||||
'value' => self::decode($entry['value']),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public function read($id)
|
||||
{
|
||||
return self::decode($this->core->read($id));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public function create($doc)
|
||||
{
|
||||
return $this->core->create(self::encode($doc));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public function update($id, $doc) : void
|
||||
{
|
||||
$this->core->update($id, self::encode($doc));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public function delete($id) : void
|
||||
{
|
||||
$this->core->delete($id);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,16 +3,10 @@
|
|||
namespace rosavox\services\doc;
|
||||
|
||||
require_once('helpers/string.php');
|
||||
require_once('helpers/storage.php');
|
||||
require_once('helpers/misc.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class state
|
||||
{
|
||||
public static ?\rosavox\helpers\storage\interface_ $storage = null;
|
||||
}
|
||||
require_once('entities/doc.php');
|
||||
require_once('repositories/doc.php');
|
||||
|
||||
|
||||
/**
|
||||
|
@ -41,7 +35,7 @@ function audible_path(int $id) : string
|
|||
|
||||
/**
|
||||
*/
|
||||
function generate_readable(int $id, $doc) : void
|
||||
function generate_readable(int $id, \rosavox\entities\doc\entity $doc) : void
|
||||
{
|
||||
$markdown = \rosavox\helpers\string_\coin(
|
||||
"# {{value_title}}
|
||||
|
@ -58,7 +52,7 @@ function generate_readable(int $id, $doc) : void
|
|||
{{macro_reasoning}}",
|
||||
[
|
||||
'label_title' => \rosavox\helpers\misc\translate('domain.doc.title'),
|
||||
'value_title' => $doc['title'],
|
||||
'value_title' => $doc->title,
|
||||
'label_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'),
|
||||
'value_authors' => \implode(
|
||||
"\n",
|
||||
|
@ -69,13 +63,13 @@ function generate_readable(int $id, $doc) : void
|
|||
'author' => $author,
|
||||
]
|
||||
),
|
||||
$doc['authors']
|
||||
$doc->authors
|
||||
)
|
||||
),
|
||||
'label_content' => \rosavox\helpers\misc\translate('domain.doc.content'),
|
||||
'value_content' => $doc['content'],
|
||||
'value_content' => $doc->content,
|
||||
'macro_reasoning' => (
|
||||
($doc['reasoning'] === null)
|
||||
($doc->reasoning === null)
|
||||
?
|
||||
''
|
||||
:
|
||||
|
@ -86,7 +80,7 @@ function generate_readable(int $id, $doc) : void
|
|||
{{value_reasoning}}",
|
||||
[
|
||||
'label_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'),
|
||||
'value_reasoning' => $doc['reasoning'],
|
||||
'value_reasoning' => $doc->reasoning,
|
||||
]
|
||||
)
|
||||
)
|
||||
|
@ -101,9 +95,7 @@ function generate_readable(int $id, $doc) : void
|
|||
|
||||
/**
|
||||
*/
|
||||
function remove_readable(
|
||||
int $id
|
||||
) : void
|
||||
function remove_readable(int $id) : void
|
||||
{
|
||||
$path = readable_path($id);
|
||||
if (! \file_exists($path))
|
||||
|
@ -119,10 +111,7 @@ function remove_readable(
|
|||
|
||||
/**
|
||||
*/
|
||||
function generate_audible(
|
||||
int $id,
|
||||
$doc
|
||||
) : void
|
||||
function generate_audible(int $id, \rosavox\entities\doc\entity $doc) : void
|
||||
{
|
||||
$pause = " .\n";
|
||||
$text = \rosavox\helpers\string_\coin(
|
||||
|
@ -130,13 +119,13 @@ function generate_audible(
|
|||
[
|
||||
'pause' => $pause,
|
||||
'label_title' => \rosavox\helpers\misc\translate('domain.doc.title'),
|
||||
'value_title' => $doc['title'],
|
||||
'value_title' => $doc->title,
|
||||
'label_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'),
|
||||
'value_authors' => \implode($pause, $doc['authors']),
|
||||
'value_authors' => \implode($pause, $doc->authors),
|
||||
'label_content' => \rosavox\helpers\misc\translate('domain.doc.content'),
|
||||
'value_content' => $doc['content'],
|
||||
'value_content' => $doc->content,
|
||||
'macro_reasoning' => (
|
||||
($doc['reasoning'] === null)
|
||||
($doc->reasoning === null)
|
||||
?
|
||||
''
|
||||
:
|
||||
|
@ -145,7 +134,7 @@ function generate_audible(
|
|||
[
|
||||
'pause' => $pause,
|
||||
'label_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'),
|
||||
'value_reasoning' => $doc['reasoning'],
|
||||
'value_reasoning' => $doc->reasoning,
|
||||
]
|
||||
)
|
||||
)
|
||||
|
@ -163,9 +152,7 @@ function generate_audible(
|
|||
|
||||
/**
|
||||
*/
|
||||
function remove_audible(
|
||||
int $id
|
||||
) : void
|
||||
function remove_audible(int $id) : void
|
||||
{
|
||||
$path = audible_path($id);
|
||||
if (! \file_exists($path))
|
||||
|
@ -179,41 +166,28 @@ function remove_audible(
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function empty_() : array
|
||||
function dump() : array
|
||||
{
|
||||
return [
|
||||
'title' => '',
|
||||
'authors' => [],
|
||||
'content' => '',
|
||||
'reasoning' => null,
|
||||
];
|
||||
return \rosavox\repositories\doc\repo::get_instance()->list_();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function list_() : array
|
||||
function get(int $id) : \rosavox\entities\doc\entity
|
||||
{
|
||||
return state::$storage->list_();
|
||||
return \rosavox\repositories\doc\repo::get_instance()->read($id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function read(int $id) : array
|
||||
function add(\rosavox\entities\doc\entity $doc) : int
|
||||
{
|
||||
return state::$storage->read($id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo async generating
|
||||
*/
|
||||
function create(array $doc) : int
|
||||
{
|
||||
$id = state::$storage->create($doc);
|
||||
$id = \rosavox\repositories\doc\repo::get_instance()->create($doc);
|
||||
generate_readable($id, $doc);
|
||||
generate_audible($id, $doc);
|
||||
return $id;
|
||||
|
@ -222,9 +196,40 @@ function create(array $doc) : int
|
|||
|
||||
/**
|
||||
*/
|
||||
function update(int $id, array $doc) : void
|
||||
function add_examples() : void
|
||||
{
|
||||
state::$storage->update($id, $doc);
|
||||
$entities = [
|
||||
new \rosavox\entities\doc\entity(
|
||||
'Freibier bei Parteitagen',
|
||||
[
|
||||
'Björn Biernot',
|
||||
'Doreen Dauerdurst',
|
||||
],
|
||||
'Der Landesverband möge beschließen, dass zu Beginn eines jeden Parteitags für jeden Deligierten mindestens zwei Flaschen Bier auf den zugehörigen Platz zu stellen sind.',
|
||||
'Wir haben Durst!',
|
||||
),
|
||||
new \rosavox\entities\doc\entity(
|
||||
'Götterdämmerung',
|
||||
[
|
||||
'Fenriswolf',
|
||||
],
|
||||
'Der Allvater hat mich betrogen. Ich werde ihn und seine elende Asenbrut verschlingen. Diese Welt wird enden.',
|
||||
null,
|
||||
),
|
||||
];
|
||||
foreach ($entities as $entity)
|
||||
{
|
||||
add($entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function change(int $id, \rosavox\entities\doc\entity $doc) : void
|
||||
{
|
||||
\rosavox\repositories\doc\repo::get_instance()->update($id, $doc);
|
||||
remove_readable($id);
|
||||
remove_audible($id);
|
||||
generate_readable($id, $doc);
|
||||
|
@ -234,52 +239,21 @@ function update(int $id, array $doc) : void
|
|||
|
||||
/**
|
||||
*/
|
||||
function delete(int $id) : void
|
||||
function remove(int $id) : void
|
||||
{
|
||||
state::$storage->delete($id);
|
||||
\rosavox\repositories\doc\repo::get_instance()->delete($id);
|
||||
remove_readable($id);
|
||||
remove_audible($id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function add_examples() : void
|
||||
{
|
||||
create(
|
||||
[
|
||||
'title' => 'Freibier bei Parteitagen',
|
||||
'authors' => [
|
||||
'Björn Biernot',
|
||||
'Doreen Dauerdurst',
|
||||
],
|
||||
'content' => 'Der Landesverband möge beschließen, dass zu Beginn eines jeden Parteitags für jeden Deligierten mindestens zwei Flaschen Bier auf den zugehörigen Platz zu stellen sind.',
|
||||
'reasoning' => 'Wir haben Durst!',
|
||||
]
|
||||
);
|
||||
create(
|
||||
[
|
||||
'title' => 'Götterdämmerung',
|
||||
'authors' => [
|
||||
'Fenriswolf',
|
||||
],
|
||||
'content' => 'Der Allvater hat mich betrogen. Ich werde ihn und seine elende Asenbrut verschlingen. Diese Welt wird enden.',
|
||||
'reasoning' => null,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function init() : void
|
||||
{
|
||||
state::$storage = new \rosavox\helpers\storage\class_jsonfile(
|
||||
'docs.json',
|
||||
fn ($id) => \sprintf('%u', $id),
|
||||
fn ($id_encoded) => \intval($id_encoded)
|
||||
);
|
||||
if (empty(state::$storage->list_()))
|
||||
\rosavox\repositories\doc\repo::get_instance()->setup();
|
||||
|
||||
if (empty(dump()))
|
||||
{
|
||||
add_examples();
|
||||
}
|
||||
|
|
|
@ -82,16 +82,6 @@ button
|
|||
font-size: 1.0em;
|
||||
}
|
||||
|
||||
.docs-list-entry
|
||||
{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.docs-list-entry > *
|
||||
{
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.state-waiting
|
||||
{
|
||||
cursor: progress;
|
||||
|
@ -101,3 +91,37 @@ button
|
|||
{
|
||||
content: "\21A7 ";
|
||||
}
|
||||
|
||||
.docs-list > ul
|
||||
{
|
||||
padding: 0;
|
||||
margin: 0 0 0 16px;
|
||||
}
|
||||
|
||||
.docs-list-entry
|
||||
{
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
list-style-type: none;
|
||||
|
||||
}
|
||||
|
||||
.docs-list-entry:not(:first-child)
|
||||
{
|
||||
border-top: 2px solid hsl(var(--hue), 0%, 50%);
|
||||
}
|
||||
|
||||
.docs-list-entry-main
|
||||
{
|
||||
}
|
||||
|
||||
.docs-list-entry-actions
|
||||
{
|
||||
margin-top: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.docs-list-entry-actions > *
|
||||
{
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div id="docs-edit">
|
||||
<div class="docs-edit">
|
||||
<form method="POST">
|
||||
<label>
|
||||
<span>{{label_doc_title}}</span>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<li class="docs-list-entry">
|
||||
<div class="docs-list-entry-main">
|
||||
<a href="{{value_link_open}}">{{value_text}}</a>
|
||||
|
|
||||
</div>
|
||||
<div class="docs-list-entry-actions">
|
||||
{{area_download_readable}}
|
||||
|
|
||||
{{area_download_audible}}
|
||||
|
|
||||
{{area_hear}}
|
||||
</div>
|
||||
</li>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div id="docs-list">
|
||||
<div class="docs-list">
|
||||
<ul>
|
||||
{{entries}}
|
||||
</ul>
|
||||
|
|
Loading…
Add table
Reference in a new issue