/** * Compress web-application * @param boolean $debug Disable errors output * @param string $php_version PHP version to support */ public function compress($debug = false, $environment = 'prod', $php_version = PHP_VERSION) { // Set compressed project environment $this->environment = $environment; elapsed('Started web-application compression[' . $this->environment . ']'); s()->async(true); ini_set('memory_limit', '256M'); // Check output path if (!isset($this->output[0])) { return $this->log('Cannot compress web-application from [##] - No output path is specified', $this->input); } // Define rendering model depending on PHP version $php_version = isset($php_version[0]) ? $php_version : PHP_VERSION; if (version_compare($php_version, '5.3.0', '<')) { $this->view_mode = Core::RENDER_ARRAY; } // Add url base to path $this->output .= url()->base(); // Creating output project folder $result = \samson\core\File::mkdir($this->output); if ($result) { $this->log('Created output project folder [##]', $this->output); } else { if ($result == -1) { return $this->log('Compression failed! Cannot create output project folder [##]', $this->output); } } // Remove all trailing slashes $this->output = realpath($this->output) . '/'; $this->log('[##]## Compressing web-application[##] from [##] to [##]', $environment, $debug ? '[DEBUG]' : '', $php_version, $this->input, $this->output); // Add generic composer auto loader require $this->php['__before_all']['composer'] = "\n" . 'if(file_exists("vendor/autoload.php")) require "vendor/autoload.php";'; // Define global views collection $this->php[self::NS_GLOBAL][self::VIEWS] = "\n" . '$GLOBALS["__compressor_files"] = array();'; // If resourcer is loaded - copy css and js // Link $rr =& s()->module_stack['resourcer']; // Iterate all css and js resources $ignoreFolders = array(); foreach ($this->ignoredFolders as $folder) { $ignoreFolders[] = $this->output . $folder; } // Remove all old javascript and css \samson\core\File::clear($this->output, array('js', 'css'), $ignoreFolders); $moduleListArray = []; //$moduleListArray[Router::I_MAIN_PROJECT_TEMPLATE] = $this->system->module_stack; Event::fire(self::E_CREATE_MODULE_LIST, array(&$moduleListArray)); $resource = new Resource($this->fileManager); foreach ($moduleListArray as $template => $moduleList) { $resourceUrls = []; Event::fire(self::E_CREATE_RESOURCE_LIST, array(&$resourceUrls, $moduleList)); foreach ($resourceUrls as $type => $urls) { $file = $resource->compress($urls, $type, $this->output); $this->resourceUrlsList[$template][$type] = [DIRECTORY_SEPARATOR . $file]; } } // Iterate core ns resources collection foreach (s()->module_stack as $id => &$module) { // Work only with compressable modules if (is_a($module, ns_classname('CompressInterface', 'samsonframework\\core')) || isset($this->composerParameters['samsonphp_package_compressable']) && ($this->composerParameters['samsonphp_package_compressable'] = 1)) { $this->compress_module($module, $module->resourceMap); } // Change path to local modules if (is_a($module, '\\samson\\core\\VirtualModule')) { $module->path(''); } } /*foreach ($rr->cached['js'] as $jsCachedFile) { // Manage javascript resource $javascriptManager = new resource\JavaScript($this); $javascriptManager->compress(__SAMSON_CWD__ . $jsCachedFile, $this->output . basename($jsCachedFile)); } foreach ($rr->cached['css'] as $cssCachedFile) { // Manage CSS resource $cssManager = new resource\CSS($this, $rr); $cssManager->compress(__SAMSON_CWD__ . $cssCachedFile, $this->output . basename($cssCachedFile)); }*/ //} // Copy main project composer.json $composerPath = __SAMSON_CWD__ . 'composer.json'; if (file_exists($composerPath)) { // Read json file $composerJSON = (array) json_decode(file_get_contents($composerPath)); // Remove development dependencies unset($composerJSON['require-dev']); // Remove autoload section unset($composerJSON['autoload']); // Remove install/update scripts unset($composerJSON['scripts']); // Write modified composer.json file_put_contents($this->output . 'composer.json', json_encode($composerJSON)); } // Set errors output $this->php[self::NS_GLOBAL][self::VIEWS] .= "\n" . '\\samson\\core\\Error::$OUTPUT = ' . (!$debug ? 'false' : 'true') . ';'; // Create SamsonPHP core compressor $core = new \samsonphp\compressor\Core(s(), $environment, $this); // Add global base64 serialized core string $this->php[self::NS_GLOBAL][self::VIEWS] .= "\n" . '$GLOBALS["__CORE_SNAPSHOT"] = \'' . $core->compress() . '\';'; // Add all specified requires foreach ($this->require as $require) { $this->php[self::NS_GLOBAL][self::VIEWS] .= "\n" . 'require("' . $require . '");'; } // Add localization data $locale_str = array(); foreach (\samson\core\SamsonLocale::$locales as $locale) { if ($locale != '') { $locale_str[] = '\'' . $locale . '\''; } } // Add [setlocales] code $this->php[self::NS_GLOBAL][self::VIEWS] .= "\n" . 'setlocales( ' . implode(',', $locale_str) . ');'; // TODO: add generic handlers to modules to provide compressing logic for each module // TODO: add generic constants namespace to put all constants definition there - and put only defined constrat and redeclare them // TODO: WTF???? Thi must be local module logic // If this is remote web-app - collect local resources if (__SAMSON_REMOTE_APP) { // Gather all resources $path = __SAMSON_CWD__; $ls = array(); s()->resources($path, $ls); // If we have any resources if (isset($ls['resources'])) { $this->copy_path_resources($ls['resources'], __SAMSON_CWD__, ''); } } // If default locale is defined if (!defined('DEFAULT_LOCALE')) { define('DEFAULT_LOCALE', 'ru'); } // Add default system locale to them end of core definition $this->php['samson\\core'][self::VIEWS] = "\n" . 'define("DEFAULT_LOCALE", "' . DEFAULT_LOCALE . '");'; // Pointer to entry script code $entryScriptPath = __SAMSON_CWD__ . __SAMSON_PUBLIC_PATH . 'index.php'; $entryScript =& $this->php[self::NS_GLOBAL][$entryScriptPath]; // Collect all event system data $eventCompressor = new EventCompressor(); $eventCompressor->collect($entryScript); // Remove standard framework entry point from index.php - just preserve default controller if (preg_match('/start\\(\\s*(\'|\\")(?<default>[^\'\\"]+)/i', $entryScript, $matches)) { /* * Temporary solution to support compressed version, because other way localization does not work, * as chain is broken, first time URL object is created and URL is parsed only after start, so * CMS::afterCompress does not knows what is current locale and does not inject it to all material * queries. */ $this->php[self::NS_GLOBAL][self::VIEWS] .= "\n" . 'url();'; $this->php[self::NS_GLOBAL][self::VIEWS] .= "\n" . 's()->start(\'' . $matches['default'] . '\');'; } else { e('Default module definition not found - possible errors at compressed version'); } // Clear default entry point unset($this->php[self::NS_GLOBAL][$entryScriptPath]); // Set global namespace as last $global_ns = $this->php[self::NS_GLOBAL]; unset($this->php[self::NS_GLOBAL]); $this->php[self::NS_GLOBAL] = $global_ns; // Set view data to the end of global namespace $s = $this->php[self::NS_GLOBAL][self::VIEWS]; unset($this->php[self::NS_GLOBAL][self::VIEWS]); $this->php[self::NS_GLOBAL][self::VIEWS] = $s; // Load all OOP entities $classes = array(); // Соберем коллекцию загруженных интерфейсов их файлов по пространствам имен $this->classes_to_ns_files(get_declared_interfaces(), $classes); // Соберем коллекцию загруженных классов их файлов по пространствам имен $this->classes_to_ns_files(get_declared_classes(), $classes); // Fix OOP entities foreach ($this->php as $ns => &$files) { // If this namespace has been loaded if (isset($classes[$ns])) { // Fill namespace entities, make OOP entities correct order $files = array_merge($classes[$ns], $files); } } // Соберем весь PHP код в один файл $index_php = $this->code_array_to_str($this->php, $this->view_mode == 2); // Collect all event system data $eventCompressor->collect($index_php); // Transform event system in all project code if ($eventCompressor->transform($index_php, $index_php)) { //trace($eventCompressor->subscriptions, true); } // Remove url_base parsing and put current url base if (preg_match('/define\\(\'__SAMSON_BASE__\',\\s*([^;]+)/i', $index_php, $matches)) { $index_php = str_replace($matches[0], 'define(\'__SAMSON_BASE__\',\'' . __SAMSON_BASE__ . '\');', $index_php); } // Set global constant to specify supported PHP version if (preg_match('/define\\s*\\(\'__SAMSON_PHP_OLD[^;]+/', $index_php, $matches)) { $index_php = str_replace($matches[0], 'define(\'__SAMSON_PHP_OLD\',\'' . ($this->view_mode == 2) . '\');', $index_php); } $index_php = $this->removeBlankLines($index_php); $index_php = preg_replace('/(declare *\\( *strict_types *= *1 *\\) *;)/i', ' ', $index_php); // Запишем пусковой файл file_put_contents($this->output . 'index.php', '<?php ' . $index_php . "\n" . '?>'); // Minify PHP code if no debug is needed if (!$debug) { file_put_contents($this->output . 'index.php', php_strip_whitespace($this->output . 'index.php')); } elapsed('Site has been successfully compressed to ' . $this->output); }
/** * * @param unknown $object * @param string $viewprefix */ private function _setObject($object, $viewprefix = null) { // Generate viewprefix as only lowercase classname without NS if it is not specified $class_name = is_string($viewprefix) ? $viewprefix : '' . mb_strtolower(ns_classname(get_class($object)), 'UTF-8'); // Save object to view data $this->data[$class_name] = $object; // Add separator $class_name .= '_'; // Generate objects view array data and merge it with view data $this->data = array_merge($this->data, $object->toView($class_name)); }
/** @see \samson\core\ExternalModule::init() */ public function prepare(array $params = null) { // TODO: Change this logic to make tab loading more simple // Create new gallery tab object to load it class_exists(ns_classname('RelatedTabLocalized', 'samson\\cms\\web\\relatedmaterial')); }
/** * Constructor * @param string $material_id CMSMaterial identifier */ public function __construct($material_id = null, $parentStructure = null) { // Variable to store navigation ids to get fields by them from structurefields $navigationForFields = array(); // Add structure material condition $scg = new dbConditionGroup('or'); $scg->arguments[] = new dbConditionArgument(dbMySQLConnector::$prefix . 'structurematerial_Active', 1); $scg->arguments[] = new dbConditionArgument(dbMySQLConnector::$prefix . 'structurematerial_Active', NULL, dbRelation::ISNULL); // Perform CMSMaterial request with related CMSNavs if (dbQuery(ns_classname('CMSMaterial', 'samson\\cms'))->MaterialID($material_id)->join('structurematerial')->join('structure')->join('user')->Active(1)->cond($scg)->first($this->material)) { // Existing material handling // If material has relations with cmsnav $cmsnavs =& $this->material->onetomany['_structure']; if (isset($cmsnavs)) { // WYSIWYG query $fields_query = dbQuery('\\samson\\cms\\CMSNavField')->join('\\samson\\cms\\CMSField')->order_by('FieldID', 'ASC')->Active(1); // If material has related cmsnavs - gather material related cmsnavs info foreach ($cmsnavs as $structure) { $this->navs[$structure->id] = $structure; if ($structure->type != 2) { $navigationForFields[] = $structure->id; } } // Add cmsnavs ids to query $fields_query->StructureID($navigationForFields); // Perform DB request if ($fields_query->exec($fields)) { foreach ($fields as $data) { // Pointer to field object $db_field =& $data->onetoone['_field']; // Add field data to collection $this->fields[] = $db_field; if (isset($db_field->Type) && $db_field->Type == '8') { $this->tabs[] = new MaterialFieldLocalizedTab($this, $db_field, 'WYSIWYG'); } } } } } else { // Material empty draft creation $this->material = new CMSMaterial(); $this->material->Draft = $this->material->id; $this->material->Name = 'Новый материал'; $this->material->Created = date('h:m:i d.m.y'); // $this->material->UserID = auth()->user->id; $this->material->UserID = m('social')->user()->UserID; $this->material->Active = 1; $this->material->save(); if (isset($parentStructure)) { /** @var \samson\cms\web\navigation\CMSNav $str */ $str = null; if (dbQuery('\\samson\\cms\\web\\navigation\\CMSNav')->id($parentStructure)->first($str)) { while (isset($str)) { $this->navs[$str->id] = $str; $str = $str->parent(); } } } } // Autoload base tab classes class_exists('samsoncms\\app\\material\\MainTab'); class_exists('samsoncms\\app\\material\\FieldLocalizedTab'); // Iterate declared classes to find other FormTab children to load to form foreach (get_declared_classes() as $class) { // If class if samson\cms\web\material\FormTab child if (is_subclass_of($class, ns_classname('FormTab', 'samsoncms\\app\\material'))) { // Tab supports automatic rendering flag eval('$ar = ' . $class . '::$AUTO_RENDER;'); // PHP 5.2 support if ($ar === true) { // Create and add FormTab instance to form tabs collection $this->tabs[] = new $class($this); } } } // Sort tabs by their index usort($this->tabs, array($this, 'tabs_sorter')); }
/** * Преобразовать массив записей из БД во внутреннее представление dbRecord * @param string $class_name Имя класса * @param array $response Массив записей полученных из БД * @return array Коллекцию записей БД во внутреннем формате * @see dbRecord */ protected function &toRecords($class_name, array &$response, array $join = array(), array $virtual_fields = array()) { // Сформируем правильное имя класса $class_name = ns_classname($class_name, 'samson\\activerecord'); // Результирующая коллекция полученных записей из БД $collection = array(); // Получим переменные для запроса extract($this->__get_table_data($class_name)); // Generate table metadata for joined tables $joinedTableData = array(); foreach ($join as $relationData) { // Generate full joined table name(including prefix) $joinTable = self::$prefix . $relationData->table; // Get real classname of the table without alias $tableName = $_relation_alias[$joinTable]; // Get joined table class metadata $joinedTableData[$tableName] = $this->__get_table_data($tableName); } // Получим имя главного $main_primary = $_primary; // Перебем массив полученных данных от БД - создадим для них объекты $records_count = sizeof($response); // Идентификатор текущего создаваемого объекта $main_id = isset($response[0]) ? $response[0][$main_primary] : 0; // Указатель на текущий обрабатываемый объект $main_obj = null; // Переберем полученные записи из БД for ($i = 0; $i < $records_count; $i++) { // Строка данных полученная из БД $db_row =& $response[$i]; // Get object instance $collection[$main_id] =& $this->createObject($class_name, $main_id, $_attributes, $db_row, $virtual_fields); // Pointer to main object $main_obj =& $collection[$main_id]; // Выполним внутренний перебор строк из БД начиная с текущей строки // Это позволит нам розабрать объекты полученные со связью один ко многим // А если это связь 1-1 то цикл выполниться только один раз for ($j = $i; $j < $records_count; $j++) { // Строка данных полученная из БД $db_inner_row =& $response[$j]; // Получим идентфиикатор главного объекта в текущей строче БД $obj_id = $db_inner_row[$main_primary]; // Если в строке из БД новый идентификатор if ($obj_id != $main_id) { // Установим новый текущий идентификатор материала $main_id = $obj_id; // Установим индекс главного цикла на строку с новым главным элементом // учтем что главный цикл сам увеличит на единицу индекс $i = $j - 1; //trace(' - Найден новый объект на строке №'.$j.'-'.$db_inner_row[$main_primary]); // Прервем внутренний цикл break; } //else trace(' + Заполняем данные из строки №'.$j); // Переберем все присоединенные таблицы в запросе foreach ($join as $relation_data) { /**@var \samson\activerecord\RelationData $relation_data */ // If this table is not ignored if (!$relation_data->ignore) { // TODO: Prepare all data in RelationObject to speed up this method $join_name = $relation_data->relation; $join_table = self::$prefix . $relation_data->table; //trace('Filling related table:'.$join_name.'/'.$join_table); // Get real classname of the table without alias $_relation_name = $_relation_alias[$join_table]; $join_class = str_replace(self::$prefix, '', $relation_data->table); // Get joined table metadata from previously prepared object $r_data = $joinedTableData[$_relation_name]; // Try to get identifier if (isset($_relations[$join_table][$r_data['_primary']])) { $r_obj_id_field = $_relations[$join_table][$r_data['_primary']]; } else { e('Cannot find related table(##) primary field(##) description', E_SAMSON_ACTIVERECORD_ERROR, array($join_table, $r_data['_primary'])); } // Если задано имя ключевого поля связанного объекта - создадим его if (isset($db_inner_row[$r_obj_id_field])) { // Получим ключевое поле связанного объекта $r_obj_id = $db_inner_row[$r_obj_id_field]; // Get joined object instance $r_obj =& $this->createObject($join_name, $r_obj_id, $_relations[$join_table], $db_inner_row); // Call handler for object filling $r_obj->filled(); // TODO: Это старый подход - сохранять не зависимо от алиаса под реальным именем таблицы // Если связанный объект привязан как один-к-одному - просто довами ссылку на него if ($_relation_type[$join_table] == 0) { $main_obj->onetoone['_' . $join_table] = $r_obj; $main_obj->onetoone['_' . $join_class] = $r_obj; } else { $main_obj->onetomany['_' . $join_table][$r_obj_id] = $r_obj; $main_obj->onetomany['_' . $join_class][$r_obj_id] = $r_obj; } } } } } // Call handler for object filling $main_obj->filled(); // Если внутренний цикл дошел до конца остановим главный цикл if ($j == $records_count) { break; } } // Вернем то что у нас вышло return $collection; }
/** * Get CMSMaterial by selector * Field to search for can be specified, by default search if performed by URL field * Function supports finding material by own fields and by any additional fields * * @param string $selector Value of CMSMaterial to search * @param string $field Field name for searching * @return CMSMaterial Instance of CMSMaterial on successfull search */ public function &material($selector, $field = 'Url') { $db_cmsmat = null; // If id passed switch to real table column name if ($field == 'id') { $field = 'MaterialID'; } // Build classname with PHP < 5.3 compatibility $classname = ns_classname('cmsmaterial', 'samson\\cms'); // If instance of CMSMaterial passed - just return it if ($selector instanceof $classname) { return $selector; } else { if (isset(dbRecord::$instances[$classname][$selector])) { $db_cmsmat =& dbRecord::$instances[$classname][$selector]; } else { // Get material by field $db_cmsmat = CMSMaterial::get(array($field, $selector), NULL, 0, 1); // If we have found material - get the first one if (is_array($db_cmsmat) && sizeof($db_cmsmat)) { $db_cmsmat = array_shift($db_cmsmat); } else { $db_cmsmat = null; } } } return $db_cmsmat; }