/** * Check object $field field value as $table column * and if database table does not have it - create. * $field is not set in object - error returns * * @param object $object Pointer to object to get field names data * @param string $table Database table name * @param string $field Object field name * @param string $type Database column name * * @return bool True if database table has field or field has been created */ public function createField($object, $table, $field, $type = 'INT') { // Check if db identifier field is configured if (class_exists($table)) { if (strlen($object->{$field})) { // Variable to get all social table attributes $attributes = array(); // Get table attributes - PHP 5.2 compatible eval('$attributes = ' . $table . '::$_attributes;'); // Remove namespaces $table = \samson\core\AutoLoader::getOnlyClass($table); // Make keys lowercase $attributes = array_change_key_case_unicode($attributes); // If table does not have defined identifier field if (!isset($attributes[strtolower($object->{$field})])) { // Add identifier field to social users table $this->simple_query('ALTER TABLE `' . $table . '` ADD `' . $object->{$field} . '` ' . $type . ' '); } return true; } else { // Signal error return e('Cannot load "' . get_class($object) . '" module - no $' . $field . ' is configured'); } } }
/** * Constructor * @param string $base_class Base class in relation * @param string $table_name Name/alias of table in relation * @param string $relation_class Classname that has to be created on joining * @param boolean $ignore Flag for not creating object instances for this class */ public function __construct($base_class, $table_name_simple, $relation_class = null, $ignore = false) { // If table name passed without namespace consider it as activerecord namespace $table_name = \samson\core\AutoLoader::className($table_name_simple, 'samson\\activerecord'); // If relation class not specified if (!isset($relation_class)) { // if there is no class exists for table name specified if (!class_exists($table_name, false)) { // PHP < 5.3 get relation aliases eval('$_relation_alias = ' . $base_class . '::$_relation_alias;'); // Try to find classname in relation aliases if (isset($_relation_alias[$table_name_simple])) { $relation_class = \samson\core\AutoLoader::className($_relation_alias[$table_name_simple], __NAMESPACE__); } else { if (isset($_relation_alias[$table_name])) { $relation_class = \samson\core\AutoLoader::className($_relation_alias[$table_name], __NAMESPACE__); } else { // use thi table name as class $relation_class = $table_name; } } } else { $relation_class = $table_name; } // Try to find closest parent class to dbRecord class $parent_class = get_parent_class($relation_class); if ($parent_class != \samson\core\AutoLoader::className('dbRecord', 'samson\\activerecord')) { $table_name = \samson\core\AutoLoader::getOnlyClass($parent_class); } } // Set defined class fields $this->base = $base_class; $this->relation = $relation_class; $this->table = \samson\core\AutoLoader::getOnlyClass($table_name); $this->ignore = $ignore; // TODO: fix this problem $this->table = str_replace('samson_activerecord_', '', $this->table); }
/** * Get CMSNav by selector * Field to search for can be specified, by default search if performed by URL field * * @param string $selector * @param string $field * @return string|NULL */ public function &navigation($selector, $field = 'Url') { $cmsnav = null; // If no selector passed if (!isset($selector)) { return $cmsnav; } // If id passed switch to real table column name if ($field == 'id') { $field = 'StructureID'; } // Build classname with PHP < 5.3 compatibility $classname = \samson\core\AutoLoader::className('CMSNav', 'samson\\cms'); // If instance of CMSNav passed - just return it if (is_a($selector, $classname)) { return $selector; } else { if (isset(dbRecord::$instances[$classname][$selector])) { $cmsnav =& dbRecord::$instances[$classname][$selector]; } else { if (dbQuery($classname)->cond('Active', 1)->cond($field, $selector)->join('children_relations')->join('children', '\\samson\\cms\\CMSNav')->join('parents_relations')->join('parents', '\\samson\\cms\\CMSNav')->first($cmsnav)) { $cmsnav->prepare(); } } } return $cmsnav; }
/** * Remove all USE statements and replace class shortcuts to full class names * * @param string $code Code to work with * @param array $classes Array of class names to replace * * @return bool|mixed|string */ private function removeUSEStatement($code, array $classes) { // Iterate found use statements foreach (array_unique($classes) as $full_class) { // Ignore trait uses if (trait_exists($full_class)) { continue; } // Get class shortcut $class_name = \samson\core\AutoLoader::getOnlyClass($full_class); // Check class existance if (!class_exists($full_class) && !interface_exists($full_class)) { //return e('Found USE statement for undeclared class ##', E_SAMSON_FATAL_ERROR, $full_class); continue; } // Replace class static call $code = preg_replace('/([^\\\\a-z])' . $class_name . '::/i', '$1' . $full_class . '::', $code); // Replace class implements calls $code = preg_replace('/\\s+implements(.*\\W)' . $class_name . '([^\\\\])/i', ' implements $1' . $full_class . '$2 ', $code); // Handle instanceof operator $code = preg_replace('/instanceof\\s+' . $class_name . '/i', 'instanceof ' . $full_class . '', $code); // Replace class extends calls $code = preg_replace('/extends\\s+' . $class_name . '/i', 'extends ' . $full_class . '', $code); // Replace multiple class extends calls $code = preg_replace('/\\s+extends(.*\\W),?\\s' . $class_name . '([^\\\\])/i', ' extends $1' . $full_class . '$2 ', $code); // Replace class hint calls $code = preg_replace('/(\\(|\\s|\\,)\\s*' . $class_name . '\\s*(&|$)/i', '$1' . $full_class . ' $2', $code); // Replace class creation call $code = preg_replace('/new\\s+' . $class_name . '\\s*\\(/i', 'new ' . $full_class . '(', $code); // Replace annotations $code = preg_replace('/([, (])' . $class_name . '\\s\\$/i', '$1 $2' . $full_class . ' $', $code); } return $code; }
/** * Сформировать правильное имя класса с использованием namespace, если оно не указано * Функция нужна для обратной совместимости с именами классов без NS * * @param string $class_name Имя класса для исправления * @param string $ns Пространство имен которому принадлежит класс * * @deprecated use \samson\core\AutoLoader::value() and pass full class name to it without splitting into class * name and namespace * @return string Исправленное имя класса */ function ns_classname($class_name, $ns = null) { return \samson\core\AutoLoader::className($class_name, $ns); }
/** Callback for CSS url rewriting */ public function src_replace_callback($matches) { // Если мы нашли шаблон - переберем все найденные патерны if (isset($matches[2]) && strpos($matches[2], 'data:') === false) { // Remove relative path from resource path $url = str_replace('../', '/', $matches[2]); // Routes with this module controller do not need changes if (strpos($url, '/' . $this->id . '/') === false) { // Remove possible GET parameters from resource path if (($getStart = stripos($url, '?')) !== false) { $url = substr($url, 0, $getStart); } // Remove possible HASH parameters from resource path if (($getStart = stripos($url, '#')) !== false) { $url = substr($url, 0, $getStart); } //trace($this->c_module->id.'-'.get_class($this->c_module).'-'.$url.'-'.is_a( $this->c_module, ns_classname('ExternalModule','samson\core')));; // Always rewrite url's for external modules and for remote web applications if (is_a($this->c_module, \samson\core\AutoLoader::className('ExternalModule', 'samson\\core')) || __SAMSON_REMOTE_APP) { // Build real path to resource $realPath = $this->c_module->path() . $url; // Try to find path in module root folder if (!file_exists($realPath)) { // Build path to "new" module public folder www $realPath = $this->c_module->path() . __SAMSON_PUBLIC_PATH . $url; // Try to find path in module Public folder if (file_exists($realPath)) { $url = 'www/' . $url; } else { // Signal error //e('[##][##] Cannot find CSS resource[##] in path[##]',D_SAMSON_DEBUG, array($this->c_module->id, $realPath, $url, $this->cResource)); } } // Rewrite URL using router $url = self::url($url, $this->c_module); } else { if (is_a($this->c_module, \samson\core\AutoLoader::className('LocalModule', 'samson\\core'))) { $url = url()->base() . $url; } } return 'url("' . $url . '")'; } else { return 'url("' . $matches[2] . '")'; } } else { // Just return original value return $matches[0]; } }
/** * 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();'; // Iterate all loaded modules foreach (s()->module_stack as &$module) { // Work only with compressible modules if (is_a($module, 'samson\\core\\iModuleCompressable')) { // $moduleCompressor = new Module(s(), $module, $this); //$moduleCompressor->compress(); } } // Iterate core ns resources collection foreach (s()->load_module_stack as $id => &$data) { // Get module instance $module =& s()->module_stack[$id]; // Work only with compressable modules if (is_a($module, ns_classname('iModuleCompressable', 'samson\\core'))) { /*if (in_array($id, array('local'))){ //trace($module); //trace($data); $this->compress_module( $module, $data ); }*/ $this->compress_module($module, $data); } } // Iterate only local modules foreach (s()->module_stack as $id => &$module) { if (is_a($module, \samson\core\AutoLoader::classname('samson\\core\\CompressableLocalModule'))) { // Change path to module $module->path(''); } } // If resourcer is loaded - copy css and js if (isset(s()->module_stack['resourcer'])) { // 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); // Manage javascript resource $javascriptManager = new resource\JavaScript($this); $javascriptManager->compress(__SAMSON_CWD__ . $rr->cached['js'], $this->output . basename($rr->cached['js'])); // Manage CSS resource $cssManager = new resource\CSS($this, $rr); $cssManager->compress(__SAMSON_CWD__ . $rr->cached['css'], $this->output . basename($rr->cached['css'])); } // 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 == Core::RENDER_ARRAY); // 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 == Core::RENDER_ARRAY) . '\');', $index_php); } $index_php = $this->removeBlankLines($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); }