xref: /plugin/struct/meta/Schema.php (revision 083afc55c907a52e46afc662d6f808a98112c779)
1*083afc55SAndreas Gohr<?php
2*083afc55SAndreas Gohr
3*083afc55SAndreas Gohrnamespace plugin\struct\meta;
4*083afc55SAndreas Gohr
5*083afc55SAndreas Gohruse plugin\struct\types\AbstractBaseType;
6*083afc55SAndreas Gohruse plugin\struct\types\Text;
7*083afc55SAndreas Gohr
8*083afc55SAndreas Gohrclass Schema {
9*083afc55SAndreas Gohr
10*083afc55SAndreas Gohr    /** @var \helper_plugin_sqlite|null */
11*083afc55SAndreas Gohr    protected $sqlite;
12*083afc55SAndreas Gohr
13*083afc55SAndreas Gohr    /** @var int The ID of this schema */
14*083afc55SAndreas Gohr    protected $id = 0;
15*083afc55SAndreas Gohr
16*083afc55SAndreas Gohr    /** @var string name of the associated table */
17*083afc55SAndreas Gohr    protected $table = '';
18*083afc55SAndreas Gohr
19*083afc55SAndreas Gohr    /**
20*083afc55SAndreas Gohr     * @var string the current checksum of this schema
21*083afc55SAndreas Gohr     */
22*083afc55SAndreas Gohr    protected $chksum = '';
23*083afc55SAndreas Gohr
24*083afc55SAndreas Gohr    /** @var AbstractBaseType[] all the colums */
25*083afc55SAndreas Gohr    protected $columns = array();
26*083afc55SAndreas Gohr
27*083afc55SAndreas Gohr    /** @var int */
28*083afc55SAndreas Gohr    protected $maxsort = 0;
29*083afc55SAndreas Gohr
30*083afc55SAndreas Gohr    /**
31*083afc55SAndreas Gohr     * Schema constructor
32*083afc55SAndreas Gohr     * @param string $table The table this schema is for
33*083afc55SAndreas Gohr     * @param int $ts The timestamp for when this schema was valid, 0 for current
34*083afc55SAndreas Gohr     */
35*083afc55SAndreas Gohr    public function __construct($table, $ts = 0) {
36*083afc55SAndreas Gohr        /** @var \helper_plugin_struct_db $helper */
37*083afc55SAndreas Gohr        $helper = plugin_load('helper', 'struct_db');
38*083afc55SAndreas Gohr        $this->sqlite = $helper->getDB();
39*083afc55SAndreas Gohr        if(!$this->sqlite) return;
40*083afc55SAndreas Gohr
41*083afc55SAndreas Gohr        $table = self::cleanTableName($table);
42*083afc55SAndreas Gohr        $this->table = $table;
43*083afc55SAndreas Gohr
44*083afc55SAndreas Gohr        // load info about the schema itself
45*083afc55SAndreas Gohr        if($ts) {
46*083afc55SAndreas Gohr            $sql = "SELECT *
47*083afc55SAndreas Gohr                      FROM schemas
48*083afc55SAndreas Gohr                     WHERE tbl = ?
49*083afc55SAndreas Gohr                       AND ts <= ?
50*083afc55SAndreas Gohr                  ORDER BY ts DESC
51*083afc55SAndreas Gohr                     LIMIT 1";
52*083afc55SAndreas Gohr            $opt = array($table, $ts);
53*083afc55SAndreas Gohr
54*083afc55SAndreas Gohr        } else {
55*083afc55SAndreas Gohr            $sql = "SELECT *
56*083afc55SAndreas Gohr                      FROM schemas
57*083afc55SAndreas Gohr                     WHERE tbl = ?
58*083afc55SAndreas Gohr                  ORDER BY ts DESC
59*083afc55SAndreas Gohr                     LIMIT 1";
60*083afc55SAndreas Gohr            $opt = array($table);
61*083afc55SAndreas Gohr        }
62*083afc55SAndreas Gohr        $res = $this->sqlite->query($sql, $opt);
63*083afc55SAndreas Gohr        if($this->sqlite->res2count($res)) {
64*083afc55SAndreas Gohr            $result = $this->sqlite->res2arr($res);
65*083afc55SAndreas Gohr            $this->id = $result['id'];
66*083afc55SAndreas Gohr            $this->chksum = $result['chksum'];
67*083afc55SAndreas Gohr
68*083afc55SAndreas Gohr        }
69*083afc55SAndreas Gohr        $this->sqlite->res_close($res);
70*083afc55SAndreas Gohr        if(!$this->id) return;
71*083afc55SAndreas Gohr
72*083afc55SAndreas Gohr        // load existing columns
73*083afc55SAndreas Gohr        $sql = "SELECT SC.*, T.*
74*083afc55SAndreas Gohr                  FROM schema_cols SC,
75*083afc55SAndreas Gohr                       types T
76*083afc55SAndreas Gohr                 WHERE SC.schema_id = ?
77*083afc55SAndreas Gohr                   AND SC.type_id = T.id
78*083afc55SAndreas Gohr              ORDER BY SC.sort";
79*083afc55SAndreas Gohr        $res = $this->sqlite->query($sql, $opt);
80*083afc55SAndreas Gohr        $rows = $this->sqlite->res2arr($res);
81*083afc55SAndreas Gohr        $this->sqlite->res_close($res);
82*083afc55SAndreas Gohr
83*083afc55SAndreas Gohr        foreach($rows as $row) {
84*083afc55SAndreas Gohr            $class = 'plugin\\struct\\type\\' . $row['class'];
85*083afc55SAndreas Gohr            $config = json_decode($row['config'], true);
86*083afc55SAndreas Gohr            $this->columns[$row['col']] = new $class($config, $row['label'], $row['ismulti']);
87*083afc55SAndreas Gohr            if($row['sort'] > $this->maxsort) $this->maxsort = $row['sort'];
88*083afc55SAndreas Gohr        }
89*083afc55SAndreas Gohr    }
90*083afc55SAndreas Gohr
91*083afc55SAndreas Gohr    /**
92*083afc55SAndreas Gohr     * Cleans any unwanted stuff from table names
93*083afc55SAndreas Gohr     *
94*083afc55SAndreas Gohr     * @param string $table
95*083afc55SAndreas Gohr     * @return string
96*083afc55SAndreas Gohr     */
97*083afc55SAndreas Gohr    static public function cleanTableName($table) {
98*083afc55SAndreas Gohr        $table = preg_replace('/[^a-z0-9_]+/', '', $table);
99*083afc55SAndreas Gohr        $table = preg_replace('/^[0-9_]+/', '', $table);
100*083afc55SAndreas Gohr        $table = trim($table);
101*083afc55SAndreas Gohr        return $table;
102*083afc55SAndreas Gohr    }
103*083afc55SAndreas Gohr
104*083afc55SAndreas Gohr    /**
105*083afc55SAndreas Gohr     * Returns a table to edit the schema
106*083afc55SAndreas Gohr     *
107*083afc55SAndreas Gohr     * @todo should this include the form?
108*083afc55SAndreas Gohr     *
109*083afc55SAndreas Gohr     * @return string
110*083afc55SAndreas Gohr     */
111*083afc55SAndreas Gohr    public function adminEditor() {
112*083afc55SAndreas Gohr        $html = '';
113*083afc55SAndreas Gohr
114*083afc55SAndreas Gohr        $html .= '<input type="hidden" name="table" value="' . hsc($this->table) . '">';
115*083afc55SAndreas Gohr
116*083afc55SAndreas Gohr        $html .= '<table class="inline">';
117*083afc55SAndreas Gohr        $html .= '<tr><th>Sort</th><th>Label</th><th>Multi-Input?</th><th>Configuration</th><th>Type</th></tr>'; // FIXME localize
118*083afc55SAndreas Gohr        foreach($this->columns as $key => $obj) {
119*083afc55SAndreas Gohr            $html .= $this->adminColumn($key, $obj);
120*083afc55SAndreas Gohr        }
121*083afc55SAndreas Gohr
122*083afc55SAndreas Gohr        // FIXME new one needs to be added dynamically, this is just for testing
123*083afc55SAndreas Gohr        $html .= $this->adminColumn('new1', new Text($this->maxsort+10));
124*083afc55SAndreas Gohr
125*083afc55SAndreas Gohr        $html .= '</table>';
126*083afc55SAndreas Gohr        return $html;
127*083afc55SAndreas Gohr    }
128*083afc55SAndreas Gohr
129*083afc55SAndreas Gohr    /**
130*083afc55SAndreas Gohr     * Returns the HTML to edit a single column definition of the schema
131*083afc55SAndreas Gohr     *
132*083afc55SAndreas Gohr     * @param string $column_id
133*083afc55SAndreas Gohr     * @param AbstractBaseType $type
134*083afc55SAndreas Gohr     * @return string
135*083afc55SAndreas Gohr     * @todo this should probably be reused for adding new columns via AJAX later?
136*083afc55SAndreas Gohr     */
137*083afc55SAndreas Gohr    protected function adminColumn($column_id, AbstractBaseType $type) {
138*083afc55SAndreas Gohr        $base = 'schema[' . $column_id . ']'; // base name for all fields
139*083afc55SAndreas Gohr
140*083afc55SAndreas Gohr        $html = '<tr>';
141*083afc55SAndreas Gohr
142*083afc55SAndreas Gohr        $html .= '<td>';
143*083afc55SAndreas Gohr        $html .= '<input type="text" name="' . $base . '[sort]" value="' . hsc($type->getSort()) . '" size="3">';
144*083afc55SAndreas Gohr        $html .= '</td>';
145*083afc55SAndreas Gohr
146*083afc55SAndreas Gohr        $html .= '<td>';
147*083afc55SAndreas Gohr        $html .= '<input type="text" name="' . $base . '[label]" value="' . hsc($type->getLabel()) . '">';
148*083afc55SAndreas Gohr        $html .= '</td>';
149*083afc55SAndreas Gohr
150*083afc55SAndreas Gohr        $html .= '<td>';
151*083afc55SAndreas Gohr        $checked = $type->isMulti() ? 'checked="checked"' : '';
152*083afc55SAndreas Gohr        $html .= '<input type="checkbox" name="' . $base . '[ismulti]" value="1" ' . $checked . '>';
153*083afc55SAndreas Gohr        $html .= '</td>';
154*083afc55SAndreas Gohr
155*083afc55SAndreas Gohr        $html .= '<td>';
156*083afc55SAndreas Gohr        $config = json_encode($type->getConfig(), JSON_PRETTY_PRINT);
157*083afc55SAndreas Gohr        $html .= '<textarea name="' . $base . '[config]" cols="45" rows="10">' . hsc($config) . '</textarea>';
158*083afc55SAndreas Gohr        $html .= '</td>';
159*083afc55SAndreas Gohr
160*083afc55SAndreas Gohr        $html .= '<td>';
161*083afc55SAndreas Gohr        $html .= substr(get_class($type), 20); //FIXME this needs to be a dropdown
162*083afc55SAndreas Gohr        $html .= '</td>';
163*083afc55SAndreas Gohr
164*083afc55SAndreas Gohr        $html .= '</tr>';
165*083afc55SAndreas Gohr
166*083afc55SAndreas Gohr        return $html;
167*083afc55SAndreas Gohr    }
168*083afc55SAndreas Gohr
169*083afc55SAndreas Gohr}
170