runQuery( "SELECT * FROM course ORDER BY `order`", [] ); } /** courses struct * * a super array with almost any info needed about courses * * @return (array) ['tree' => ..., 'breadcrumbs' => ... ] */ public static function courses_struct() { $tree = self::category_tree(); return [ 'tree' => $tree, 'breadcrumbs' => self::breadcrumbs($tree) ]; } /** constuct a category_tree * * returns a tree representation of the categories * * NOTE: * category_tree() is an expensive method; * it calls 2 other methods implementing recursive algorithms * thus it uses many sources to run (particularly RAM). * Caching the result is strogly recommended. * */ public static function category_tree() { $categories = self::get_categories(); // get all categories $tree = self::to_tree($categories); // format to a tree $tree_wParents = self::tree_parents($tree); // add parents section for each tree-node return $tree_wParents; } /** to_tree * * constructs a tree from raw-table data; * this is a private method and uses a recursive algorithm * * @param $dataset (array): flar array of records with id/parent-id pairs * @return $root (array): id of root category * * (**) each node has 2 parts: * .... .. rec : all record attributes/data as passed into $dataset * .... .. childs : array of (children) nodes */ private static function to_tree($dataset, $root = 0) { $return = []; // loop data ; search for direct children of root foreach($dataset as $key => $rec) { $child = $rec['id']; $parent = $rec['parent_id']; if ($parent == $root) { // a direct child is found unset($dataset[$key]); // remove item (no need to traverse again) // Append the child into result array ; parse its children $return[] = [ 'rec' => [ 'id' => $rec['id'], 'label' => $rec['label'], 'order' => $rec['order'], 'parent' => $rec['parent_id'] ], 'childs' => self::to_tree($dataset, $child) // recursively ]; } } return empty($return) ? [] : $return; } /** tree_parents * * adds a section to each tree node with all parents of each node * * @param $tree (array) : nodes array (each node has `rec` and `childs` sections ) * @param $parents (array); DO NOT SET IT (takes values automaticaly) * @return array of nodes with an extra node[parents] section * */ private static function tree_parents($tree, $parents = []) { $tree_with_parents = []; foreach($tree as $key => $node) { // parents to be pushed for node's children $push_parents = $parents; // parents so far $push_parents[] = $node['rec']; // this record will be a new parent $tree_with_parents[$key] = [ 'rec' => $node['rec'], 'parents' => $parents, 'childs' => ($node['childs'] == []) ? [] : self::tree_parents($node['childs'], $push_parents) ]; } return $tree_with_parents; } /** all_breadcrumbs * ------------------------------------------------------------------------- * * returns an array of all breadcrumbs * where array-key of each record is category[id] * * NOTE: * --- * Course_model::all_breadcrumbs returns an indexed super-array; * each array item includes a banch of information: [ * breadcrumb, * rec: [ id , title ], * parents: [ [id, title] , ... ] * childs: [ [id, title] , ... ], * level * ] * * Use Cases: * --- * as a super-array, the output can be used in many cases * for example... * into form elements * .. while selecting category for a post * .. or editing a category * or directry referring to category's parents/childs * * Arguments: * --- * @param $tree (array) : category tree (with childs and parents parts) * @param $detimiter (string, optional) : string to split breadcrumb's path-nodes * @param $exception (int, optional) : id of category to exclude (subcategories shall be excluded too) * @param $l (int, not-pass) : depth level of the node; DO NOT SET (takes values automaticaly) * @return array of breadcrumbs * ------------------------------------------------------------------------- */ static public function breadcrumbs($tree, $delimiter = " / ", $exception = 0, $l = 0) { $all = []; // results array foreach($tree as $node) { // loop through all nodes if (intval($node['rec']['id']) != $exception) { // if node is not exception // construct breadcrumb html of node // --- -- -- - - - $breadcrumb = ""; foreach($node['parents'] as $par) { // first: join path titles $breadcrumb .= $par['label'] . $delimiter; } $breadcrumb .= $node['rec']['label']; // last: append title // make a new super record // --- -- -- - - - $all[$node['rec']['id']] = [ // set record is as key 'breadcrumb' => $breadcrumb, // add breadcrump to results 'rec' => $node['rec'], // + node info 'parents' => $node['parents'], // + parents array 'childs' => self::first_level_childs($node), // + direct childs 'level' => $l // + level ]; // recursively traverse children nodes // --- -- -- - - - if (isset($node['childs']) && $node['childs'] != []) { $child_breadcrumbs = self::breadcrumbs( $node['childs'], $delimiter, $exception, $l+1 ); $all = $all + $child_breadcrumbs; // concatenate arrays (keep array-keys) } } } return $all; } /** first_level_childs * --- -- -- - - - * used by all_breadcrumbs() */ static private function first_level_childs($node) { $childs = []; if ($node['childs'] == []) { return []; } foreach($node['childs'] as $key => $kid) { $childs[] = [ 'id' => $kid['rec']['id'], 'label' => $kid['rec']['label'] ]; } return $childs; } /** LESSONS * ------------------------------------------------------------------------- */ /** lessons of course * * @param $course_id */ public static function lessons_of_course($id) { // TODO: order results in some way return Registry::use('database')->runQuery( "SELECT lesson.*, lesson_privilege.privilege_id FROM lesson LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id WHERE lesson.status = 1 AND lesson.course_id = :id", [':id' => $id] ); } /** files * return all files * @param void * @return array */ public static function files() { return Registry::use('database')->runQuery("SELECT * from media", []); } }