xref: /plugin/struct/meta/Schema.php (revision 097f4a53a9f2c54a89643d357681041c89816aed)
1<?php
2
3namespace plugin\struct\meta;
4use plugin\struct\types\AbstractBaseType;
5
6/**
7 * Class Schema
8 *
9 * Represents the schema of a single data table and all its properties. It defines what can be stored in
10 * the represented data table and how those contents are formatted.
11 *
12 * It can be initialized with a timestamp to access the schema as it looked at that particular point in time.
13 *
14 * @package plugin\struct\meta
15 */
16class Schema {
17
18    /** @var \helper_plugin_sqlite|null */
19    protected $sqlite;
20
21    /** @var int The ID of this schema */
22    protected $id = 0;
23
24    /** @var string name of the associated table */
25    protected $table = '';
26
27    /**
28     * @var string the current checksum of this schema
29     */
30    protected $chksum = '';
31
32    /** @var Column[] all the colums */
33    protected $columns = array();
34
35    /** @var int */
36    protected $maxsort = 0;
37
38    /** @var int */
39    protected $ts = 0;
40
41    /**
42     * Schema constructor
43     *
44     * @param string $table The table this schema is for
45     * @param int $ts The timestamp for when this schema was valid, 0 for current
46     */
47    public function __construct($table, $ts = 0) {
48        /** @var \helper_plugin_struct_db $helper */
49        $helper = plugin_load('helper', 'struct_db');
50        $this->sqlite = $helper->getDB();
51        if(!$this->sqlite) return;
52
53        $table = self::cleanTableName($table);
54        $this->table = $table;
55        $this->ts = $ts;
56
57        // load info about the schema itself
58        if($ts) {
59            $sql = "SELECT *
60                      FROM schemas
61                     WHERE tbl = ?
62                       AND ts <= ?
63                  ORDER BY ts DESC
64                     LIMIT 1";
65            $opt = array($table, $ts);
66        } else {
67            $sql = "SELECT *
68                      FROM schemas
69                     WHERE tbl = ?
70                  ORDER BY ts DESC
71                     LIMIT 1";
72            $opt = array($table);
73        }
74        $res = $this->sqlite->query($sql, $opt);
75        if($this->sqlite->res2count($res)) {
76            $schema = $this->sqlite->res2arr($res);
77            $result = array_shift($schema);
78            $this->id = $result['id'];
79            $this->chksum = $result['chksum'];
80
81        }
82        $this->sqlite->res_close($res);
83        if(!$this->id) return;
84
85        // load existing columns
86        $sql = "SELECT SC.*, T.*
87                  FROM schema_cols SC,
88                       types T
89                 WHERE SC.sid = ?
90                   AND SC.tid = T.id
91              ORDER BY SC.sort";
92        $res = $this->sqlite->query($sql, $this->id);
93        $rows = $this->sqlite->res2arr($res);
94        $this->sqlite->res_close($res);
95
96        foreach($rows as $row) {
97            $class = 'plugin\\struct\\types\\' . $row['class'];
98            if(!class_exists($class)) {
99                // This usually never happens, except during development
100                msg('Unknown type "'.hsc($row['class']).'" falling back to Text', -1);
101                $class = 'plugin\\struct\\types\\Text';
102            }
103
104            $config = json_decode($row['config'], true);
105            /** @var AbstractBaseType $type */
106            $type = new $class($config, $row['label'], $row['ismulti'], $row['tid']);
107            $column = new Column(
108                $row['sort'],
109                $type,
110                $row['colref'],
111                $row['enabled'],
112                $table
113            );
114            $type->setContext($column);
115
116            $this->columns[$row['colref']] = $column;
117            if($row['sort'] > $this->maxsort) $this->maxsort = $row['sort'];
118        }
119    }
120
121    /**
122     * Cleans any unwanted stuff from table names
123     *
124     * @param string $table
125     * @return string
126     */
127    static public function cleanTableName($table) {
128        $table = strtolower($table);
129        $table = preg_replace('/[^a-z0-9_]+/', '', $table);
130        $table = preg_replace('/^[0-9_]+/', '', $table);
131        $table = trim($table);
132        return $table;
133    }
134
135    /**
136     * Gets a list of all available schemas
137     *
138     * @return string[]
139     */
140    static public function getAll() {
141        /** @var \helper_plugin_struct_db $helper */
142        $helper = plugin_load('helper', 'struct_db');
143        $db = $helper->getDB();
144        if(!$db) return array();
145
146        $res = $db->query("SELECT DISTINCT tbl FROM schemas ORDER BY tbl");
147        $tables = $db->res2arr($res);
148        $db->res_close($res);
149
150        $result = array();
151        foreach($tables as $row) {
152            $result[] = $row['tbl'];
153        }
154        return $result;
155    }
156
157    /**
158     * @return string
159     */
160    public function getChksum() {
161        return $this->chksum;
162    }
163
164    /**
165     * @return int
166     */
167    public function getId() {
168        return $this->id;
169    }
170
171    /**
172     * Returns a list of columns in this schema
173     *
174     * @param bool $withDisabled if false, disabled columns will not be returned
175     * @return Column[]
176     */
177    public function getColumns($withDisabled = true) {
178        if(!$withDisabled) {
179            return array_filter(
180                $this->columns,
181                function (Column $col) {
182                    return $col->isEnabled();
183                }
184            );
185        }
186
187        return $this->columns;
188    }
189
190    /**
191     * Find a column in the schema by its label
192     *
193     * Only enabled columns are returned!
194     *
195     * @param $name
196     * @return bool|Column
197     */
198    public function findColumn($name) {
199        foreach($this->columns as $col) {
200            if($col->isEnabled() && utf8_strtolower($col->getLabel()) == utf8_strtolower($name)) {
201                return $col;
202            }
203        }
204        return false;
205    }
206
207    /**
208     * @return string
209     */
210    public function getTable() {
211        return $this->table;
212    }
213
214    /**
215     * @return int the highest sort number used in this schema
216     */
217    public function getMaxsort() {
218        return $this->maxsort;
219    }
220
221}
222