function work(Request $request) { $name = $this->name(); $version = $this->version->value(); if (!is_dir(DIR . 'vendor_front/' . $name)) { CLI::run_php('bowerphp.phar install --save ' . $name . '#' . $version, false, true); } $files = explode(';', $this->import->value()); if ($file = $this->file()) { $files[] = $file; } foreach ($files as $file) { $file = '/vendor_front/' . trim($file); switch (File::fileExtention($file)) { case 'js': $request->htmlHead('script', ['type' => 'text/javascript', 'src' => $file, 'text' => '']); break; case 'css': $request->htmlHead('link', ['rel' => "stylesheet", 'type' => "text/css", 'href' => $file]); break; default: } } }
/** * Сохранение сущности * @param Entity $entity * @throws Error */ function write($entity) { // Если объект свойство, то сохранять родительский объект?? if ($entity->is_property()) { if ($parent = $entity->parent(null, true)) { $parent->__set($entity->name(), $entity); Data::write($parent); } } else { // Текущие сведения об объекте $info = []; if ($entity->is_exists()) { // Текущие сведения об объекта $uri = $entity->is_changed('uri') ? $entity->changes('uri') : $entity->uri(); if ($uri === '') { $file = DIR . 'project.info'; } else { $file = DIR . trim($uri, '/') . '/' . File::fileName($uri) . '.info'; } if (is_file($file)) { $info = file_get_contents($file); $info = json_decode($info, true); } } // Подбор уникального имени // @todo Перенос php файлов влечет за собой фатальные ошибки!!!! так как меняется namespace и class name if ($entity->is_changed('uri') || !$entity->is_exists()) { // Проверка уникальности нового имени путём создания папки // Если подбор уникального имени, то создавать пока не создаться (попробовать постфикс) $path = dirname($entity->dir(true)) . '/'; $name = $entity->name(); if ($new_path = File::makeUniqueDir($path, $name, 1, $entity->is_auto_namig())) { $entity->name(basename($new_path)); $info['name'] = $entity->name(); } else { $entity->errors()->_attributes->name->add(new Error('Не уникальное', 'unique')); throw $entity->errors(); } // Перемещение старой папки в новую if ($entity->is_exists()) { File::rename($entity->dir(true, true), $entity->dir(true, false)); } if ($entity->is_changed('name') && $entity->is_exists()) { // @todo Переименовать .info, .php и, возможно, привязанный файл. } // Обновить URI подчиненных объектов не фиксируя изменения $entity->updateChildrenUri(); } // Новые сведения об объекте $info_new = $this->export($entity, isset($info['properties']) ? $info['properties'] : [], function (Entity $entity, $file) { return Data::save_file($entity, $file); }); // Порядковый номер // 1. Подбор максимального среди существующих // 2. Смещение порядка у последующих объектов // Сохранить объект с свлйствами JSON $uri = $entity->uri(); if ($uri === '') { $file = DIR . 'project.info'; } else { $file = DIR . trim($uri, '/') . '/' . File::fileName($uri) . '.info'; } File::create(F::toJSON($info_new, true), $file); } // Сохранить подчиненные foreach ($entity->children() as $child) { /** @var Entity $child */ if (!$child->is_property()) { Data::write($child); } } }
/** * Сохранение сущности * @param Entity $entity * @throws Error */ function write($entity) { // @todo // Смена родителя/прототипа требует соответсвующие сдвиги в таблице отношений // При смене uri нужно обновить uri подчиненных $attr = $entity->attributes(); // Локальные id $attr['parent'] = isset($attr['parent']) ? $this->localId($attr['parent']) : 0; $attr['proto'] = isset($attr['proto']) ? $this->localId($attr['proto']) : 0; $attr['author'] = isset($attr['author']) ? $this->localId($attr['author']) : 0; //$this->localId(Auth::get_user()->uri()); // Подбор уникального имени, если указана необходимость в этом if ($entity->is_changed('uri') || !$entity->is_exists()) { $q = $this->db->prepare('SELECT 1 FROM {objects} WHERE parent=? AND `name`=? LIMIT 0,1'); $q->execute(array($attr['parent'], $attr['name'])); if ($q->fetch()) { //Выбор записи по шаблону имени с самым большим префиксом $q = $this->db->prepare('SELECT `name` FROM {objects} WHERE parent=? AND `name` REGEXP ? ORDER BY CAST((SUBSTRING_INDEX(`name`, "_", -1)+1) AS SIGNED) DESC LIMIT 0,1'); $q->execute(array($attr['parent'], '^' . $attr['name'] . '(_[0-9]+)?$')); if ($row = $q->fetch(DB::FETCH_ASSOC)) { preg_match('|^' . preg_quote($attr['name']) . '(?:_([0-9]+))?$|u', $row['name'], $match); $attr['name'] .= '_' . (isset($match[1]) ? $match[1] + 1 : 1); } } $entity->name($attr['name']); $attr['uri'] = $entity->uri(); } Buffer::set_entity($entity); // Локальный идентификатор объекта $attr['id'] = $this->localId($entity->uri($entity->is_exists()), true, $new_id); // Если смена файла, то удалить текущий файл if ($entity->is_changed('file')) { $current_file = $entity->changes('file'); if (is_string($current_file)) { File::delete($entity->dir(true) . $current_file); } } // Если привязан файл if (!$entity->is_default_file()) { if ($entity->is_file()) { $file_attache = $entity->file(); if (is_array($file_attache)) { // Загрузка файла if (!($attr['file'] = Data::save_file($entity, $file_attache))) { $attr['file'] = ''; } } else { $attr['file'] = basename($file_attache); } } else { // файла нет, но нужно отменить наследование файла $attr['file'] = ''; } } else { $attr['file'] = ''; } // Уникальность order // Если изменено на конкретное значение (не максимальное) if ($attr['order'] != Entity::MAX_ORDER && (!$entity->is_exists() || $entity->is_changed('order'))) { // Проверка, занят или нет новый order $q = $this->db->prepare('SELECT 1 FROM {objects} WHERE `parent`=? AND `order`=?'); $q->execute(array($attr['parent'], $attr['order'])); if ($q->fetch()) { // Сдвиг order существующих записей, чтоб освободить значение для новой $q = $this->db->prepare(' UPDATE {objects} SET `order` = `order`+1 WHERE `parent`=? AND `order`>=?'); $q->execute(array($attr['parent'], $attr['order'])); } unset($q); } else { // Новое максимальное значение для order, если объект новый или явно указано order=null if (!$entity->is_exists() || $attr['order'] == Entity::MAX_ORDER) { // Порядковое значение вычисляется от максимального существующего $q = $this->db->prepare('SELECT MAX(`order`) m FROM {objects} WHERE parent=?'); $q->execute(array($attr['parent'])); if ($row = $q->fetch(DB::FETCH_ASSOC)) { $attr['order'] = $row['m'] + 1; } unset($q); } } $this->db->beginTransaction(); // Если новое имя или родитель, то обновить свой URI и URI подчиненных if ($entity->is_changed('name') || $entity->is_changed('parent')) { if ($entity->is_exists()) { $current_uri = $entity->uri(true); $current_name = $entity->is_changed('name') ? $entity->changes('name') : $attr['name']; // Текущий URI $names = F::splitRight('/', $current_uri, true); $uri = (isset($names[0]) ? $names[0] . '/' : '') . $current_name; // Новый URI $names = F::splitRight('/', $attr['uri'], true); $uri_new = (isset($names[0]) ? $names[0] . '/' : '') . $attr['name']; $entity->change('uri', $uri_new); // @todo Обновление URI подчиенных в базе // нужно знать текущий уковень вложенности и локальный id // // $q = $this->db->prepare('UPDATE {ids}, {parents} SET {ids}.uri = CONCAT(?, SUBSTRING(uri, ?)) WHERE {parents}.parent_id = ? AND {parents}.object_id = {ids}.id AND {parents}.is_delete=0'); // $v = array($uri_new, mb_strlen($uri)+1, $attr['id']); // $q->execute($v); // // Обновление уровней вложенностей в objects // if (!empty($current) && $current['parent']!=$attr['parent']){ // $dl = $attr['parent_cnt'] - $current['parent_cnt']; // $q = $this->db->prepare('UPDATE {objects}, {parents} SET parent_cnt = parent_cnt + ? WHERE {parents}.parent_id = ? AND {parents}.object_id = {objects}.id AND {parents}.is_delete=0'); // $q->execute(array($dl, $attr['id'])); // // Обновление отношений // $this->makeParents($attr['id'], $attr['parent'], $dl, true); // } if (!empty($uri) && is_dir(DIR . $uri)) { // Переименование/перемещение папки объекта $dir = DIR . $uri_new; File::rename(DIR . $uri, $dir); if ($entity->is_changed('name')) { // Переименование файла класса File::rename($dir . '/' . $current_name . '.php', $dir . '/' . $attr['name'] . '.php'); // Переименование .info файла File::rename($dir . '/' . $current_name . '.info', $dir . '/' . $attr['name'] . '.info'); } } unset($q); } // Обновить URI подчиненных объектов не фиксируя изменения $entity->updateChildrenUri(); } // Если значение больше 255 if (mb_strlen($attr['value']) > 255) { $q = $this->db->prepare(' INSERT INTO {text} (`id`, `value`) VALUES (:id, :value) ON DUPLICATE KEY UPDATE `value` = :value '); $q->execute(array(':id' => $attr['id'], ':value' => $attr['value'])); $attr['value'] = mb_substr($attr['value'], 0, 255); $attr['is_text'] = 1; } else { $attr['is_text'] = 0; } // Запись $attr_names = array('id', 'parent', 'proto', 'author', 'order', 'name', 'value', 'file', 'is_text', 'is_draft', 'is_hidden', 'is_link', 'is_mandatory', 'is_property', 'is_relative', 'is_default_value', 'is_default_logic', 'created', 'updated'); $cnt = sizeof($attr_names); // Запись объекта (создание или обновление при наличии) // Объект идентифицируется по id if (!$entity->is_exists()) { $q = $this->db->prepare(' INSERT INTO {objects} (`' . implode('`, `', $attr_names) . '`) VALUES (' . str_repeat('?,', $cnt - 1) . '?) ON DUPLICATE KEY UPDATE `' . implode('`=?, `', $attr_names) . '`=? '); $i = 0; foreach ($attr_names as $name) { $value = $attr[$name]; $i++; $type = is_int($value) ? DB::PARAM_INT : (is_bool($value) ? DB::PARAM_BOOL : (is_null($value) ? DB::PARAM_NULL : DB::PARAM_STR)); $q->bindValue($i, $value, $type); $q->bindValue($i + $cnt, $value, $type); } $q->execute(); } else { $q = $this->db->prepare(' UPDATE {objects} SET `' . implode('`=?, `', $attr_names) . '`=? WHERE id = ? '); $i = 0; foreach ($attr_names as $name) { $value = $attr[$name]; $i++; $type = is_int($value) ? DB::PARAM_INT : (is_bool($value) ? DB::PARAM_BOOL : (is_null($value) ? DB::PARAM_NULL : DB::PARAM_STR)); $q->bindValue($i, $value, $type); } $q->bindValue(++$i, $attr['id']); $q->execute(); } $this->db->commit(); foreach ($entity->children() as $child) { Data::write($child); } return true; }
/** * Загрузка файла в директорию объекта * @param Entity $entity * @param array $file Инфо о файла в формате $_FILES * @return null|string Имя файла */ static function save_file($entity, $file) { // Обработка файла у объекта и его свойств $f = File::fileInfo($file['tmp_name']); $name = ($f['back'] ? '../' : '') . $entity->name(); // расширение if (empty($file['name'])) { if ($f['ext']) { $name .= '.' . $f['ext']; } } else { $f = File::fileInfo($file['name']); if ($f['ext']) { $name .= '.' . $f['ext']; } } // $path = $entity->dir(true) . $name; if ($file['tmp_name'] != $path) { if (!File::upload($file['tmp_name'], $path)) { // @todo Проверить безопасность? // Копирование, если объект-файл создаётся из уже имеющихся на сервере файлов, например при импорте каталога if (!File::copy($file['tmp_name'], $path)) { $name = null; } } } return $name; }
/** * Файл, ассоциированный с объектом * @param null|array|string $new Информация о новом файле. Полный путь к новому файлу или сведения из $_FILES * @param bool $root Возвращать полный путь или от директории сайта * @return null|string */ function file($new = null, $root = false) { // Установка нового файла if (isset($new)) { if (empty($new)) { $this->change('file', ''); } else { if (is_string($new)) { $new = ['tmp_name' => $new, 'name' => basename($new), 'size' => @filesize($new), 'error' => is_file($new) ? 0 : true]; } if (empty($new['name']) && $this->is_file()) { $new['name'] = $this->name() . '.' . File::fileExtention($this->file()); } $this->change('file', $new); } $this->change('is_default_file', false); $this->_def_file = null; } // Возврат пути к текущему файлу, если есть if ($this->is_file()) { if (($proto = $this->is_default_file(null, true)) && $proto->is_exists()) { return $proto->file(null, $root); } else { if (is_array($this->_attributes['file'])) { return $this->_attributes['file']; } return $this->dir($root) . $this->_attributes['file']; } } return null; }
/** * Запись форматированного значения в лог файл * @return \boolive\core\develop\Trace */ function log() { //error_log(self::Format($this, $trace_buf = [], ' ', false)); File::create(date('Y.m.d G:i.s') . ' ' . self::Format($this, true, $trace_buf = [], ' ', false) . "\r\n", DIR_TEMP . 'trace.log'); return $this; }