/** * @param $uri * @return Entity|null */ function read($uri) { if (!($entity = Buffer::get_entity($uri))) { // Экземпляра объекта в буфере нет, проверяем массив его атрибутов в буфере $info = Buffer::get_info($uri); if (empty($info)) { try { // выбор по uri $q = $this->db->prepare(' SELECT o.* FROM {ids} as i , {objects} as o WHERE i.id = o.id AND i.uri = :uri LIMIT 0,1 '); $q->execute(['uri' => $uri]); if ($info = $q->fetch(DB::FETCH_ASSOC)) { $info['is_exists'] = true; $this->_local_ids[$uri] = intval($info['id']); $this->_global_ids[$info['id']] = $uri; if (!empty($info['file'])) { $info['is_default_file'] = false; } // Выборка текста if (!empty($info['is_text'])) { $q = $this->db->query('SELECT `value` FROM {text} WHERE id = ' . intval($info['id'])); if ($row = $q->fetch(DB::FETCH_ASSOC)) { $info['value'] = $row['value']; } } // вместо parent, proto, author их uri $info['parent'] = $this->globalId($info['parent']); $info['proto'] = $this->globalId($info['proto']); $info['author'] = $this->globalId($info['author']); unset($info['id'], $info['is_text']); } $info['uri'] = $uri; // Инфо о свойствах в буфер $info = Buffer::set_info($info); } catch (\Exception $e) { return null; } } // Создать экземпляр без свойств $entity = Data::entity($info); } return $entity; }
function read($uri) { if (!($entity = Buffer::get_entity($uri))) { // Экземпляра объекта в буфере нет, проверяем массив его атрибутов в буфере $info = Buffer::get_info($uri); if (empty($info)) { try { $q = $this->db->prepare(' SELECT * FROM `entity` WHERE `entity`.uri = :uri '); $q->execute(['uri' => $uri]); $row = $q->fetch(DB::FETCH_ASSOC); } catch (\Exception $e) { return false; } } } }
/** * @param $cond * <code> * [ * 'select' => 'children', //self, children, parents, heirs, protos, child, link * 'calc' => 'count', // false, exists, count, [sum, attr], [max, attr], [min, attr], [avg, attr] * 'from' => '/contents', * 'depth' => 1, // maximum depth * 'struct' => 'array', // value, object, array, tree * 'where' => [], //filter condition * 'order' => [['name', 'asc'], ['value','desc']], * 'limit' => [0,100], * 'key' => 'name', // attribute name * 'access' => true // check read access * ]; * </code> * @return array */ function find($cond) { // select, from, depth $dir = $cond['from'] === '' ? DIR : DIR . trim($cond['from'], '/') . '/'; $objects = []; try { if ($cond['depth'] > 0) { if ($cond['select'] == 'properties') { // Читаем, чтобы инфо о свойства попало в буфер $from = $this->read($cond['from']); // need for Buffer::get_props if ($prop_names = Buffer::get_props($cond['from'])) { foreach ($prop_names as $prop_uri) { // Проверка объекта на соответствие услвоию [where] if ($obj = $this->read($prop_uri)) { if (!$cond['where'] || $obj->verify($cond['where'])) { $objects[] = $obj; if ($cond['calc'] == 'exists') { break; } } } } } } else { if ($cond['select'] == 'children') { // Игнорируемые директории/файлы $ignore = array_flip(['.', '..', '.git']); // Перебор директории в глубь. (Рекурсия на циклах) if ($dh = new \DirectoryIterator($dir)) { $stack = [['name' => '', 'dh' => $dh, 'depth' => $cond['depth'], 'parent' => $cond['from']]]; do { $curr = end($stack); while ($curr['dh']->valid()) { /** @var \DirectoryIterator $file */ $file = $curr['dh']->current(); $cur_dh = $curr['dh']; if (($name = $file->getFilename()) !== '') { if (!isset($ignore[$name])) { $uri = $curr['name'] === '' ? $curr['parent'] : $curr['parent'] . '/' . $curr['name']; if ($name == $curr['name'] . '.info') { if (!($obj = Buffer::get_entity($uri))) { if (!($info = Buffer::get_info($uri))) { // Все сведения об объекте в формате json (если нет класса объекта) $f = file_get_contents($file->getPathname()); $info = json_decode($f, true); $error = json_last_error(); if ($error != JSON_ERROR_NONE) { $info = []; // throw new \Exception('Ошибка в "' . $curr['dir'] . $name . '"'); } $info['uri'] = $uri; if (!empty($info['file'])) { $info['is_default_file'] = false; // $info['is_file'] = true; // $info['value'] = $info['file']; } if (!empty($info['logic'])) { $info['is_default_logic'] = false; } if (!isset($info['is_default_logic'])) { $info['is_default_logic'] = true; } $info['is_exists'] = true; } if ($info && empty($info['is_property'])) { $info = Buffer::set_info($info); $obj = Data::entity($info); } } // Проверка объекта на соответствие услвоию [where] if ($obj && !$obj->is_property()) { if (!$cond['where'] || $obj->verify($cond['where'])) { $objects[] = $obj; if ($cond['calc'] == 'exists') { break; } } } } else { if ($curr['depth'] && $file->isDir()) { if ($dh = new \DirectoryIterator($file->getPathname())) { $stack[] = ['name' => $name, 'dh' => $dh, 'depth' => $curr['depth'] - 1, 'parent' => $uri]; $curr = end($stack); } } } } } $cur_dh->next(); } array_pop($stack); } while ($stack); } } } } } catch (\Exception $e) { } // access // calc if ($cond['calc']) { $calc = null; if ($cond['calc'] == 'exists') { $calc = !empty($objects); } else { if ($cond['calc'] == 'count') { $calc = count($objects); } else { if (is_array($cond['calc']) && count($cond['calc']) == 2) { $attr = $cond['calc'][1]; foreach ($objects as $o) { switch ($cond['calc'][0]) { case 'min': $calc = $calc === null ? $o->attr($attr) : min($o->attr($attr), $calc); break; case 'max': $calc = $calc === null ? $o->attr($attr) : max($o->attr($attr), $calc); break; case 'sum': case 'avg': default: $calc += $o->attr($attr); break; } } if ($objects && $cond['calc'][0] == 'avg') { $calc = $calc / count($objects); } } } } return $calc; } // order if ($order = $cond['order']) { $order_cnt = count($order); usort($objects, function ($a, $b) use($order, $order_cnt) { /** @var $a Entity */ /** @var $b Entity */ $i = 0; do { if (count($order[$i]) == 3) { $a = $a->{$order[$i][0]}; $b = $b->{$order[$i][0]}; array_shift($order[$i]); } $a = $a ? $a->{$order}[$i][0]() : null; $b = $b ? $b->{$order}[$i][0]() : null; if ($a == $b) { $comp = 0; } else { $comp = $a > $b || $a === null ? 1 : -1; if ($order[$i][1] == 'desc') { $comp = -$comp; } } $i++; } while ($comp == 0 && $i < $order_cnt); return $comp; }); } // limit (not for value and object) if ($cond['limit']) { $objects = array_slice($objects, $cond['limit'][0], $cond['limit'][1]); } // struct, key if ($cond['struct'] == 'tree') { $first_level = mb_substr_count($cond['from'], '/') + 1; $tree = []; $result = []; foreach ($objects as $obj) { $tree[$obj->uri()] = ['object' => $obj, 'sub' => []]; if ($obj->depth() == $first_level) { $key = $cond['key'] ? $obj->attr($cond['key']) : null; if ($key) { $result[$key] =& $tree[$obj->uri()]; } else { $result[] =& $tree[$obj->uri()]; } } } foreach ($tree as $uri => $obj) { $key = $cond['key'] ? $obj['object']->attr($cond['key']) : null; $p = $obj['object']->attr('parent'); if (isset($tree[$p])) { if ($key) { $tree[$p]['sub'][$key] =& $tree[$uri]; } else { $tree[$p]['sub'][] =& $tree[$uri]; } } } return $result; } else { if ($cond['struct'] == 'array' && $cond['key']) { $result = []; /** @var Entity $item */ foreach ($objects as $item) { $result[$item->attr($cond['key'])] = $item; } return $result; } } return $objects; }
static function entity($info) { $key = isset($info['uri']) ? $info['uri'] : null; if (!isset($key) || !($entity = Buffer::get_entity($key))) { try { $name = basename($info['uri']); if (isset($info['uri'])) { if (!empty($info['is_default_logic'])) { if (isset($info['proto'])) { // Класс от прототипа $class = get_class(self::read($info['proto'])); } else { // Класс наследуется, но нет прототипа $class = '\\boolive\\core\\data\\Entity'; } } else { if (empty($info['uri']) || preg_match('#^[a-zA-Z_0-9\\/]+$#ui', $info['uri'])) { $namespace = str_replace('/', '\\', rtrim($info['uri'], '/')); // Свой класс if (empty($namespace)) { $class = '\\project'; } else { if (substr($namespace, 0, 7) === '\\vendor') { $class = substr($namespace, 7) . '\\' . $name; } else { $class = $namespace . '\\' . $name; } } } else { $class = '\\boolive\\core\\data\\Entity'; } } } else { $class = '\\boolive\\core\\data\\Entity'; } if (isset($info['value']) && !isset($info['is_default_value'])) { $info['is_default_value'] = false; } if (!isset($info['is_default_value'])) { $info['is_default_value'] = true; } if (!isset($info['value']) && !empty($info['is_default_value']) && !empty($info['proto'])) { $info['value'] = Data::read($info['proto'])->value(); } // if (!isset($info['is_mandatory']) && isset($info['proto'])){ // $proto = self::read($info['proto']); // $info['is_mandatory'] = $proto->is_mandatory(); // } $entity = new $class($info); } catch (\ErrorException $e) { $entity = new Entity($info); } if (isset($key)) { Buffer::set_entity($entity); } } return $entity; }