From 6655db3dcf117cfd921a7b39600545c51e035b31 Mon Sep 17 00:00:00 2001 From: George Halkiadakis Date: Fri, 28 Apr 2023 02:22:41 +0300 Subject: brainstorming and first bytes of code --- README.md | 26 +- docker/bin/docker-entrypoint.sh | 7 +- public/app/controllers/JsonToForm.php | 685 ++++++++++++++++++++++++++++++++++ public/app/models/_info.md | 254 ++++++------- tests/code/menu.php | 0 tests/service/mailjet.php | 0 6 files changed, 814 insertions(+), 158 deletions(-) create mode 100644 public/app/controllers/JsonToForm.php mode change 100644 => 100755 tests/code/menu.php mode change 100644 => 100755 tests/service/mailjet.php diff --git a/README.md b/README.md index 8e7a43c..23e1b75 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,30 @@ # x-anom (another MVC framework) +An open-source, fast, super-light, secure, full-featured, modern, easy to setup, easy to learn, +highly extendable, php 8+, OOP MVC framework for the php-developer. -## pre-Check - -Update ```~./container/config/composer-copy.json``` according to -```~./composer.json``` or vice-versa. You actualy need just one of them; -if pulling the project into a server (bare-metar/vps/shared etc) you only -need the first; if pulling into container you need the second/ +## pre-Check -On a Linux system you can also create a link from the one file to the other -(then you need to use ralative paths on autoload.classmap section). - +(1) +There are several ```composer*.json``` versions; +the ```~./composer.json``` is the only one you actually need; +all others found under ```~./docker/config/composer-*,json``` are for testing/ +case-study puproses; so make sure that ```~./composer.json``` is updated with +all required packages + +(2) When deploying on PRODUCTION make sure that all development routes are deleted and debuging messages are disabled. +(3) +Anom sets-up two writable folders: +* ```~/storage``` (pre-public directory) ideal for file-sessioning, file-caching; +also ideal for file-uploading when serve permition is needed; +* ```~/public/files``` (post-public folder) which is ideal for public access content +Make sure to keep the one that suits your needs (or both if needed); diff --git a/docker/bin/docker-entrypoint.sh b/docker/bin/docker-entrypoint.sh index edcce41..b3f24f3 100644 --- a/docker/bin/docker-entrypoint.sh +++ b/docker/bin/docker-entrypoint.sh @@ -2,16 +2,15 @@ # setup writable directories # ------------------------------------------------------------------------------ -# grand to 'cache' directory writable permissions -# set file-cache directory to apache's user ownership +# grand to storage directory writable permissions +# set storage directory to apache's user ownership chmod -R 755 /var/www/storage chown -R www-data:www-data /var/www/storage chown -R www-data:www-data /var/www/public/files chmod -R 757 /var/www/public/files -# copy composer.json to 'www'; then prepare auutoloading +# prepare auutoloading # ------------------------------------------------------------------------------ -cp /var/www/docker/config/composer-naked.json /var/www/composer.json (cd /var/www ; composer update) (cd /var/www ; composer dump-autoload) diff --git a/public/app/controllers/JsonToForm.php b/public/app/controllers/JsonToForm.php new file mode 100644 index 0000000..9e305ce --- /dev/null +++ b/public/app/controllers/JsonToForm.php @@ -0,0 +1,685 @@ + $section) { + foreach ($section->childs as $kk => $field) { + + // find the field + if ($field->nam == $fkey) { + + $values = array(); // human readble values if select (comma separated) + + if ($field->typ == 'select') { + $multi = true; + + if ($inp !='') { + $codes = explode(",", $inp); // split coded values + foreach ($field->opt as $kkk => $v) { + if (in_array($v->id, $codes)) { // check if option is in array + $values[] = ($field->nam == 'ccode') ? ($v->id.": ".$v->tag) : $v->tag; + } + } + } + + } + else $multi = false; + + // return everything in an array + return array( + 'label' => $field->lab, + 'multi' => $multi, + 'value' => ($multi ? $values : $inp) + ); + } + } + } + + // if not escaped already, then name return same + return array('label' => $fkey, 'multi' => false, 'value' => $inp ); + } + + + + // Parse anythig from ccode + public static function parse_ccode($ckey) { + $ccARRAY = json_decode(CODEJSON); + + foreach ($ccARRAY as $key => $val) { + // find the field + if ($val->id == $ckey) { + // return everything in an array + return $val; + } + } + } + + + // Get totals of alla categories ///////////////////////////////////////////// + // RETURN array of items (value) per category (array key) + // --------------------------------------------------------------------------- + public static function get_totals() { + $result = array(); + $sum = 0; + + $dbc = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DBMS); + if ($dbc->connect_errno) { + echo "Database connection failed; Please try in a few minutes. "; + if (TESTING) echo $dbc->connect_error; + $dbc->close(); die(); + } + $dbc->set_charset("utf8"); + + // prepare statemet + $stm = $dbc->prepare("SELECT ccode, count(id) total FROM `items` GROUP BY ccode"); + $stm->execute(); // execute query + $stm->store_result(); // store result + $stm->bind_result($c, $tot); + while ($stm->fetch()) { + // using md5() you can have any unicode string as key ;) + // credit: https://stackoverflow.com/questions/10696067/characters-allowed-in-php-array-keys -> Rob's answer + // but newer versions of php (v7+) seem to handle unicide keys nicely + $result[$c] = $tot; + $sum += $tot; + } + + $result['all'] = $sum; + + return $result; + } + + + // Preview Local Datetime //////////////////////////////////////////////////// + // (in Greek format and names ) + // --------------------------------------------------------------------------- + public static function local_dt($t) { + $day = array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); + $dayL = array("Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"); + $mon = array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); + $monL = array("Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαϊ", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"); + $tm = array("am", "pm"); + $tmL = array("πμ", "μμ"); + $r = date("D. j M. Y, h:i:sa", $t); + $r = str_replace($day, $dayL, $r); + $r = str_replace($mon, $monL, $r); + $r = str_replace($tm, $tmL, $r); + return $r; + } + + + // Part of string + // UTF-8 SAFE + public static function str_part($str, $len) { + return (mb_strlen($str) > $len) ? mb_substr($str, 0, $len-1) ."…" : $str; + } + + + public static function make_a_form() + { + + // Script Workflow: + // --------------------------------------------------------------------------- + // 1. read fields options + // 2. generate HTML + // 3. generate JS needed + + // the UI + // --------------------------------------------------------------------------- + // Fields are grouped in sections + // These sections presented in tabs (or accordion if mobile device) + // Two (2) sections incduded to inform the user of empty fields or errors + + // Libraries and FrameWorks used + // --------------------------------------------------------------------------- + // Bootstrap 4.3 is used for easy responsive HTML code + // JQuery 3.3 is used to handle user interation + // Select2 is used to make select-boxes (single or multiple) easier to use + + // read fields options (json format) ///////////////////////////////////////// + // --------------------------------------------------------------------------- + $formJSON = file_get_contents('config/kallassa.json'); + $formARRAY = json_decode($formJSON); + + + // Init strigns for JS generator (needed to handle everything) /////////////// + // --------------------------------------------------------------------------- + $checkFilledJS = ""; // JS for checking empty fields + $ref2Select2JS = ""; // references to Select2-controls Javascript + $initSelectsJS = ""; // js to initialize select fields (single or multiple) + + + + $html = ' +
+

Εισαγωγή Εγγραφής

'; + + $i = 1; + foreach ($formARRAY as $key => $section) { // only one section + + $html = '
'; + + foreach ($section->childs as $kk => $field) { + + + // get attributes + + $atrs = explode('|', $field->attr); // attributes array + $appendKey = in_array('append-key', $atrs) ? true : false; // append key (for selects) + $required = in_array('required', $atrs) ? 'required' : ''; // required + $asterisn = in_array('required', $atrs) ? '*' : ''; // asterisk in label if required + $class = (isset($field->len)) ? ' col-md-'.$field->len : 'col-md-12'; // column class (for width) + $name = $field->name; + $label = $field->label; + + + $html .= " +
+ + "; + + switch ($field->typ) { + + case 'select': + + if (in_array('multiple', $atrs)) { // if select is multiple + + $html .=" + + "; + + // prepare initialization of select2 (single) + $initSelectsJS .= " + var {$name} = $('#{$name}'); + {$name}.select2({ allowClear: true });"; + + // prepare check if empty field + $checkFilledJS .= " + if (getValues({$name}) =='') { empty += '{$label} {$asterisk}
'; } + values.{$name} = getValues($name);"; + + } + + // inject options + foreach ($field->options as $key => $val) { + $html .= " + "; + } + + // close select + $html .= ""; + + break; + + + case 'text': + + $html .= " + "; + + $checkFilledJS = " + if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}'
'; } + values.{$name} = $('input[name={$name}]').val();"; + + break; + + + case 'integer': + + $html .= " + "; + + $checkFilledJS .= " + if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}'
'; } + values.{$name} = $('input[name={$name}]').val();"; + + break; + + + case 'textarea': + + $html .= " + "; + + $checkFilledJS .= " + if ($('textarea[name={$name}]').val() =='') { empty += '{$label} {$asterisk}'
'; } + values.{$name} = $('textarea[name={$name}]').val();"; + + case 'date': + + $html .= " + "; + + $checkFilledJS .= " + if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}'
'; } + values.{$name} = $('input[name={$name}]').val();"; + + break; + + + case 'email': + + $html .= " + "; + + $checkFilledJS .= " + if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}'
'; } + values.{$name} = $('input[name={$name}]').val();"; + + break; + + + default: // label, acts as common text + + $html .= "
+ * + * + * + * + * + * + * + * + * + * + * + */ diff --git a/public/app/models/_info.md b/public/app/models/_info.md index 5504523..0c19c02 100644 --- a/public/app/models/_info.md +++ b/public/app/models/_info.md @@ -1,150 +1,114 @@ # info about the structrure of the models -According to the former impementation (atcom) the project will need to handle 200+ tables. -The former project includes 209 tables with 5 or more rows (and 325 tables totaly) - - - -## Database schema - -Main tables and recomended constraints: - -``` -SET NAMES utf8; -SET time_zone = '+00:00'; -SET foreign_key_checks = 0; -SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; - -SET NAMES utf8mb4; - -DROP TABLE IF EXISTS `course`; -CREATE TABLE `course` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `parent_id` int(11) NOT NULL COMMENT 'if 0 then this is a root course', - `label` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `lesson`; -CREATE TABLE `lesson` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `course_id` int(11) NOT NULL, - `title` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, - `body` text COLLATE utf8mb4_unicode_ci NOT NULL, - `published` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0 = unpublished, 1 = published', - PRIMARY KEY (`id`), - KEY `course_id` (`course_id`), - CONSTRAINT `lesson_ibfk_1` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`), - CONSTRAINT `lesson_ibfk_2` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `lesson_media`; -CREATE TABLE `lesson_media` ( - `lesson_id` int(11) NOT NULL, - `media_id` int(11) NOT NULL, - PRIMARY KEY (`lesson_id`,`media_id`), - KEY `media_id` (`media_id`), - CONSTRAINT `lesson_media_ibfk_1` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`), - CONSTRAINT `lesson_media_ibfk_2` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`), - CONSTRAINT `lesson_media_ibfk_3` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`), - CONSTRAINT `lesson_media_ibfk_4` FOREIGN KEY (`media_id`) REFERENCES `media` (`id`), - CONSTRAINT `lesson_media_ibfk_5` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`) ON DELETE NO ACTION, - CONSTRAINT `lesson_media_ibfk_6` FOREIGN KEY (`media_id`) REFERENCES `media` (`id`) ON DELETE NO ACTION, - CONSTRAINT `lesson_media_ibfk_7` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`) ON DELETE NO ACTION, - CONSTRAINT `lesson_media_ibfk_8` FOREIGN KEY (`media_id`) REFERENCES `media` (`id`) ON DELETE NO ACTION -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `lesson_privilege`; -CREATE TABLE `lesson_privilege` ( - `lesson_id` int(11) NOT NULL, - `privilege_id` int(11) NOT NULL COMMENT 'minimum privilege required to access the lesson', - KEY `lesson_id` (`lesson_id`), - KEY `privilege_id` (`privilege_id`), - CONSTRAINT `lesson_privilege_ibfk_1` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`), - CONSTRAINT `lesson_privilege_ibfk_2` FOREIGN KEY (`privilege_id`) REFERENCES `privilege` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `media`; -CREATE TABLE `media` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `label` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, - `type` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL, - `path` varchar(320) COLLATE utf8mb4_unicode_ci NOT NULL, - `referable` tinyint(4) NOT NULL DEFAULT '1' COMMENT '0 = hidden, 1 = referable', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `page`; -CREATE TABLE `page` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `title` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, - `body` text COLLATE utf8mb4_unicode_ci NOT NULL, - `published` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0 = unpublished; 1 = published', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `page_media`; -CREATE TABLE `page_media` ( - `page_id` int(11) NOT NULL, - `media_id` int(11) NOT NULL, - KEY `page_id` (`page_id`), - KEY `media_id` (`media_id`), - CONSTRAINT `page_media_ibfk_1` FOREIGN KEY (`page_id`) REFERENCES `page` (`id`) ON DELETE NO ACTION, - CONSTRAINT `page_media_ibfk_2` FOREIGN KEY (`media_id`) REFERENCES `media` (`id`) ON DELETE NO ACTION -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `privilege`; -CREATE TABLE `privilege` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `alias` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'keep it simple; use latin', - `label` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `alias` (`alias`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `privilege_inherit`; -CREATE TABLE `privilege_inherit` ( - `higher_id` int(11) NOT NULL COMMENT 'higher priviledges inherit (include) lower ones', - `lower_id` int(11) NOT NULL, - PRIMARY KEY (`higher_id`,`lower_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `user`; -CREATE TABLE `user` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `first_name` int(11) NOT NULL, - `last_name` int(11) NOT NULL, - `email` int(11) NOT NULL, - `expiration` int(11) NOT NULL COMMENT 'account expiration date; 0 = never', - `password` int(11) NOT NULL, - `salt` int(11) NOT NULL, - `otp` int(11) NOT NULL COMMENT 'one time password for reset password', - `otp_expiration` int(11) NOT NULL, - `active` int(11) NOT NULL COMMENT 'account flag; 1=active, 0=inactive', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - - -DROP TABLE IF EXISTS `user_privilege`; -CREATE TABLE `user_privilege` ( - `user_id` int(11) NOT NULL, - `privilege_id` int(11) NOT NULL, - PRIMARY KEY (`user_id`,`privilege_id`), - KEY `privilege_id` (`privilege_id`), - CONSTRAINT `user_privilege_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`), - CONSTRAINT `user_privilege_ibfk_2` FOREIGN KEY (`privilege_id`) REFERENCES `privilege` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - -``` +## user fields; insert / update sql queries + +INSERT INTO user +( id, + prefix, + first_name, + last_name, + email, + father_name, + registration_number, + sector_id, + specialty, + belonging_school, + working_shcool, + position_type_id, + phone, + password, + expiration, + otp, + otp_expiration, + activation, + creation, +active) VALUES (:id, + :prefix, + :first_name, + :last_name, + :email, + :father_name, + :registration_number, + :sector_id, + :specialty, + :belonging_school, + :working_shcool, + :position_type_id, + :phone, + :password, + :expiration, + :otp, + :otp_expiration, + :activation, + :creation, +:active ) + + + +UPDATE user +SET prefix = :prefix, +first_name = :first_name, +last_name = :last_name, +email = :email, +father_name = :father_name, +registration_number = :registration_number, +sector_id = :sector_id, +specialty = :specialty, +belonging_school = :belonging_school, +working_shcool = :working_shcool, +position_type_id = :position_type_id, +phone = :phone, +password = :password, +expiration = :expiration, +otp = :otp, +otp_expiration = :otp_expiration, +activation = :activation, +creation = :creation, +active = :active, + + +## record_types + +document forms -> json + +request = { + user_id -> user: { + ... + } + date: ... + body: ... + media: [ ... array of media-id(s) ] +} + +penalty = { + user_id -> user: { + ... + }, + date: + time: + subject: + of_student: + place: + president: + members: [ list ] + reason: + apology: + decision: +} + + +## records + +id +user_id +type +source_json + + +## record_media + +record_id +media_id diff --git a/tests/code/menu.php b/tests/code/menu.php old mode 100644 new mode 100755 diff --git a/tests/service/mailjet.php b/tests/service/mailjet.php old mode 100644 new mode 100755 -- cgit v1.2.3