public function __toString() { if ($this->_ob_cache !== null) { return $this->_ob_cache; } $path = $this->_path; $locale = \Gini\Config::get('system.locale'); $localeSpecificPath = "@{$locale}/{$path}"; $engines = \Gini\Config::get('view.engines'); if (isset($GLOBALS['gini.view_map'][$localeSpecificPath])) { $realPath = $GLOBALS['gini.view_map'][$localeSpecificPath]; $engine = $engines[pathinfo($realPath, PATHINFO_EXTENSION)]; } elseif (isset($GLOBALS['gini.view_map'][$path])) { $realPath = $GLOBALS['gini.view_map'][$path]; $engine = $engines[pathinfo($realPath, PATHINFO_EXTENSION)]; } else { foreach ($engines as $ext => $engine) { $realPath = \Gini\Core::locatePharFile(VIEW_DIR, "{$localeSpecificPath}.{$ext}"); if (!$realPath) { $realPath = \Gini\Core::locatePharFile(VIEW_DIR, "{$path}.{$ext}"); } if ($realPath) { break; } } } if ($engine && $realPath) { $class = '\\Gini\\View\\' . $engine; $output = \Gini\IoC::construct($class, $realPath, $this->_vars); } return $this->_ob_cache = (string) $output; }
public static function possibleCommands($argv) { // list available cli programs $candidates = ['/' => []] + Util::pathAndArgs($argv, true); $commands = []; $class = null; foreach (array_reverse($candidates) as $path => $params) { $paths = \Gini\Core::pharFilePaths(CLASS_DIR, rtrim('Gini/Controller/CLI/' . ltrim($path, '/'), '/')); foreach ($paths as $p) { if (!is_dir($p)) { continue; } \Gini\File::eachFilesIn($p, function ($file) use(&$commands) { $name = basename(strtolower(explode('/', $file, 2)[0]), '.php'); $commands[$name] = $name; }); } // enumerate actions in class $path = strtr(ltrim($path, '/'), ['-' => '', '_' => '']); $basename = basename($path); $dirname = dirname($path); $class_namespace = '\\Gini\\Controller\\CLI\\'; if ($dirname != '.') { $class_namespace .= strtr($dirname, ['/' => '\\']) . '\\'; } $class = $class_namespace . $basename; if (class_exists($class)) { break; } $class = $class_namespace . 'Controller' . $basename; if (class_exists($class)) { break; } $class = null; } if (!$class) { $class = '\\Gini\\Controller\\CLI\\App'; $params = $argv; } if (class_exists($class)) { $rc = new \ReflectionClass($class); $methods = $rc->getMethods(\ReflectionMethod::IS_PUBLIC); foreach ($methods as $m) { if (strncmp('action', $m->name, 6) != 0) { continue; } if (preg_match_all('`([A-Z]+[a-z\\d]+|.+)`', substr($m->name, 6), $parts)) { $method = strtolower(implode('-', $parts[0])); if ($params[0] === $method) { $commands = []; break; } $commands[] = $method; } } } return $commands; }
public function actionExport($args) { printf("Exporting ORM structures...\n\n"); $orm_dirs = \Gini\Core::pharFilePaths(CLASS_DIR, 'Gini/ORM'); foreach ($orm_dirs as $orm_dir) { if (!is_dir($orm_dir)) { continue; } \Gini\File::eachFilesIn($orm_dir, function ($file) use($orm_dir) { $oname = strtolower(preg_replace('|.php$|', '', $file)); if ($oname == 'object') { return; } $class_name = '\\Gini\\ORM\\' . str_replace('/', '\\', $oname); // Check if it is abstract class $rc = new \ReflectionClass($class_name); if ($rc->isAbstract()) { return; } printf(" %s\n", $oname); $o = \Gini\IoC::construct($class_name); $structure = $o->structure(); // unset system fields unset($structure['id']); unset($structure['_extra']); $i = 1; $max = count($structure); foreach ($structure as $k => $v) { if ($i == $max) { break; } printf(" ├─ %s (%s)\n", $k, implode(',', array_map(function ($k, $v) { return $v ? "{$k}:{$v}" : $k; }, array_keys($v), $v))); ++$i; } printf(" └─ %s (%s)\n\n", $k, implode(',', array_map(function ($k, $v) { return $v ? "{$k}:{$v}" : $k; }, array_keys($v), $v))); }); } }
public function actionFormat($argv) { if (count($argv) < 1) { exit("usage: [1;34mgini i18n format[0m <locales>\n"); } $appname = APP_ID; foreach ($argv as $locale) { $lodir = I18N_PATH . '/' . $locale . '/LC_MESSAGES'; \Gini\File::ensureDir($lodir); $pofile = $lodir . '/' . $appname . '.po'; $paths = \Gini\Core::filePaths(RAW_DIR . '/l10n/' . $locale . '.po'); echo "merge: {$appname}.po\n"; $cmd = sprintf('msgcat -o %1$s %2$s', escapeshellarg($pofile), implode(' ', array_map('escapeshellarg', $paths))); passthru($cmd); $mofile = $lodir . '/' . $appname . '.mo'; echo "compile: {$appname}.po => {$appname}.mo\n"; $cmd = sprintf('msgfmt -o %s %s', escapeshellarg($mofile), escapeshellarg($pofile)); passthru($cmd); } }
private static function _getORMPlurals() { $orm_dirs = \Gini\Core::pharFilePaths(CLASS_DIR, 'Gini/ORM'); $onames = []; foreach ($orm_dirs as $orm_dir) { if (!is_dir($orm_dir)) { continue; } \Gini\File::eachFilesIn($orm_dir, function ($file) use($orm_dir, &$onames) { $oname = preg_replace('|.php$|', '', $file); if ($oname == 'Object') { return; } $class_name = '\\Gini\\ORM\\' . str_replace('/', '\\', $oname); // Check if it is abstract class $rc = new \ReflectionClass($class_name); if ($rc->isAbstract()) { return; } $onames[] = strtolower($oname); }); } if (count($onames) == 0) { return []; } printf("%s\n", 'Generating ORM plurals cache...'); if (!class_exists('\\Doctrine\\Common\\Inflector\\Inflector')) { echo " [31m*[0m doctrine/inflector is missing! Perhaps you did't update your composer packages yet.\n\n"; return []; } $plurals = []; $onames = array_unique($onames); foreach ($onames as $oname) { $plural = \Doctrine\Common\Inflector\Inflector::pluralize($oname); printf(" %s => %s\n", $plural, $oname); $plurals[$plural] = $oname; } echo "\n"; return $plurals; }
public function actionInit($args) { $app = \Gini\Core::moduleInfo(APP_ID); $composer_json = ['name' => $app->id, 'description' => $app->description ?: '', 'license' => 'proprietary', 'repositories' => [['type' => 'composer', 'url' => 'http://satis.genee.cn']]]; $opt = \Gini\Util::getOpt($args, 'n', ['no-packagist']); if (isset($opt['n']) || isset($opt['--no-packagist'])) { $composer_json['repositories'][] = ['packagist' => false]; echo "Generating Composer configuration file without Packagist...\n"; } else { echo "Generating Composer configuration file...\n"; } $walked = []; $walk = function ($info) use(&$walk, &$walked, &$composer_json) { $walked[$info->id] = true; foreach ($info->dependencies as $name => $version) { if (isset($walked[$name])) { continue; } $app = \Gini\Core::moduleInfo($name); if ($app) { $walk($app); } } $composer_json = \Gini\Util::arrayMergeDeep($info->composer ?: [], $composer_json); }; $walk($app); if (isset($composer_json['require']) || isset($composer_json['require-dev'])) { if (file_exists(APP_PATH . '/composer.json')) { $confirm = strtolower(readline('File exists. Overwrite? [Y/n] ')); if ($confirm && $confirm != 'y') { echo " [33mcanceled.[0m\n"; return; } } file_put_contents(APP_PATH . '/composer.json', J($composer_json, JSON_PRETTY_PRINT)); echo " [32mdone.[0m\n"; } }
public static function fetch($env = null) { $env = $env ?: APP_PATH . '/.env'; if (file_exists($env)) { $rows = file($env, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($rows as &$row) { if (!$row || $row[0] == '#') { continue; } putenv($row); } } $items = []; $paths = \Gini\Core::pharFilePaths(RAW_DIR, 'config'); foreach ($paths as $path) { self::_load_config_dir($path, $items); } $env = $_SERVER['GINI_ENV']; if ($env) { $paths = \Gini\Core::pharFilePaths(RAW_DIR, 'config/@' . $env); foreach ($paths as $path) { self::_load_config_dir($path, $items); } } return $items; }
public function actionInstall($argv) { count($argv) > 0 || APP_ID != 'gini' or die("Usage: gini index install <module> <version>\n\n"); if (!class_exists('\\Sabre\\DAV\\Client')) { self::_loadGiniComposer(); } list($options, $headers) = self::_davOptionsAndHeaders(); $client = new \Sabre\DAV\Client($options); $installedModules = []; $installModule = function ($module, $versionRange, $targetDir, $isApp = false) use(&$installModule, &$installedModules, &$client, &$options, &$headers) { if (isset($installedModules[$module])) { $info = $installedModules[$module]; $v = new \Gini\Version($info->version); // if installed version is incorrect, abort the operation. if (!$v->satisfies($versionRange)) { die("Conflict detected on {$module}! Installed: {$v->fullVersion} Expecting: {$versionRange}\n"); } } else { // try to see if we've already got it somewhere if (isset(\Gini\Core::$MODULE_INFO[$module])) { $info = \Gini\Core::$MODULE_INFO[$module]; $v = new \Gini\Version($info->version); if ($v->satisfies($versionRange)) { $matched = $v; } } // fetch index.json echo "Fetching catalog of {$module}...\n"; while (true) { $response = $client->request('GET', $module . '/index.json', null, $headers); if ($response['statusCode'] == 401 && isset($response['headers']['www-authenticate'])) { // Authentication required // prompt user/password and try again if (!isset($options['userName'])) { list($options, $headers) = self::_davOptionsAndHeaders(true); $client = new \Sabre\DAV\Client($options); continue; } $matched or die("Access denied for fetch catalog of {$module} .\n"); $response = null; } elseif ($response['statusCode'] < 200 || $response['statusCode'] > 206) { $matched or die('Error: ' . $response['statusCode'] . "\n"); $response = null; } break; } if ($response) { $indexInfo = (array) json_decode($response['body'], true); // find latest match version foreach ($indexInfo as $version => $foo) { $v = new \Gini\Version($version); if ($v->satisfies($versionRange)) { if ($matched) { if ($matched->compare($v) > 0) { continue; } } $matched = $v; } } } if (!$matched) { die("Failed to locate required version!\n"); } if (!$info || $matched->fullVersion != $info->version) { $version = $matched->fullVersion; $info = (object) $indexInfo[$version]; $tarPath = "{$module}/{$version}.tgz"; echo "Downloading {$module} from {$tarPath}...\n"; while (true) { $response = $client->request('GET', $tarPath, null, $headers); if ($response['statusCode'] == 401 && isset($response['headers']['www-authenticate'])) { // Authentication required // prompt user/password and try again if (!isset($options['userName'])) { list($options, $headers) = self::_davOptionsAndHeaders(true); $client = new \Sabre\DAV\Client($options); continue; } die("Access denied for fetch catalog of {$module}.\n"); } if ($response['statusCode'] < 200 || $response['statusCode'] > 206) { die('Error: ' . $response['statusCode'] . "\n"); } break; } if ($isApp) { $modulePath = $targetDir; } else { $modulePath = "{$targetDir}/modules/{$module}"; } if (is_dir($modulePath) && file_exists($modulePath)) { \Gini\File::removeDir($modulePath); } \Gini\File::ensureDir($modulePath); echo "Extracting {$module}...\n"; $ph = popen('tar -zx -C ' . escapeshellcmd($modulePath), 'w'); if (is_resource($ph)) { fwrite($ph, $response['body']); pclose($ph); } } else { $version = $info->version; echo "Found local copy of {$module}/{$version}.\n"; } $installedModules[$module] = $info; echo "\n"; } if ($info) { foreach ((array) $info->dependencies as $m => $r) { if ($m == 'gini') { continue; } $installModule($m, $r, $targetDir, false); } } }; if (count($argv) > 0) { // e.g. gini install xxx $module = $argv[0]; if (count($argv) > 1) { $versionRange = $argv[1]; } else { $versionRange = readline('Please provide a version constraint for the ' . $module . ' requirement:'); } $installModule($module, $versionRange, $_SERVER['PWD'] . "/{$module}", true); } else { // run: gini install, then you should be in module directory if (APP_ID != 'gini') { // try to install its dependencies $app = \Gini\Core::moduleInfo(APP_ID); $installedModules[APP_ID] = $app; $installModule(APP_ID, $app->version, APP_PATH, true); } } }
if (!isset($_SERVER['GINI_MODULE_BASE_PATH'])) { $_SERVER['GINI_MODULE_BASE_PATH'] = dirname(SYS_PATH); } if (!isset($_SERVER['GINI_APP_PATH'])) { $_SERVER['GINI_APP_PATH'] = SYS_PATH; } chdir($_SERVER['GINI_APP_PATH']); // load class map $class_map_file = $_SERVER['GINI_APP_PATH'] . '/cache/class_map.json'; if (file_exists($class_map_file)) { $class_map = @json_decode(@file_get_contents($class_map_file), true); if ($class_map) { $GLOBALS['gini.class_map'] = $class_map; } } // load view map $view_map_file = $_SERVER['GINI_APP_PATH'] . '/cache/view_map.json'; if (file_exists($view_map_file)) { $view_map = @json_decode(@file_get_contents($view_map_file), true); if ($view_map) { $GLOBALS['gini.view_map'] = $view_map; } } $class_path = SYS_PATH . '/class'; if (file_exists($class_path . '.phar')) { require 'phar://' . $class_path . '.phar/Gini/Core.php'; } else { require $class_path . '/Gini/Core.php'; } \Gini\Core::start();
public static function setup() { $host = $_SERVER['HTTP_HOST']; $scheme = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?: ($_SERVER['HTTPS'] ? 'https' : 'http'); $dir = dirname($_SERVER['SCRIPT_NAME']); if (substr($dir, -1) != '/') { $dir .= '/'; } self::$_base = $scheme . '://' . $host . $dir; self::$_rurl = \Gini\Core::moduleInfo(APP_ID)->rurl ?: ['*' => 'assets']; }
public function actionVersion($argv) { $info = \Gini\Core::moduleInfo(APP_ID); $version = $argv[0]; if ($version) { // set current version $v = new \Gini\Version($version); $v->compare($info->version) > 0 or die("A newer version (>{$info->version}) is required!\n"); $info->version = $version; \Gini\Core::saveModuleInfo($info); // commit it if it is a git repo if (is_dir(APP_PATH . '/.git')) { $WORK_TREE = escapeshellarg(APP_PATH); $GIT_DIR = escapeshellarg(APP_PATH . '/.git'); $GIT_MSG = escapeshellarg("Bumped version to {$version}"); $command = "git --git-dir={$GIT_DIR} --work-tree={$WORK_TREE} commit -m {$GIT_MSG} gini.json && git --git-dir={$GIT_DIR} tag {$version}"; passthru($command); return; } } echo "{$info->name} ({$info->id}/{$info->version})\n"; }
public function testPharFilePaths() { $paths = \Gini\Core::pharFilePaths(CLASS_DIR, 'Gini/Core.php'); $this->assertTrue(in_array(SYS_PATH . '/class/Gini/Core.php', $paths)); }
public function actionUpgradeId() { // ORM required class map. if (!isset($GLOBALS['gini.class_map'])) { echo "[31mYou need to run [1m\"gini cache class\"[0;31m before upgrade ORM id.[0m\n"; return; } // enumerate orms echo "Updating database structures according ORM definition...\n"; $orm_dirs = \Gini\Core::pharFilePaths(CLASS_DIR, 'Gini/ORM'); foreach ($orm_dirs as $orm_dir) { if (!is_dir($orm_dir)) { continue; } \Gini\File::eachFilesIn($orm_dir, function ($file) use($orm_dir) { $oname = preg_replace('|.php$|', '', $file); if ($oname == 'Object') { return; } $class_name = '\\Gini\\ORM\\' . str_replace('/', '\\', $oname); // Check if it is abstract class $rc = new \ReflectionClass($class_name); if ($rc->isAbstract()) { return; } $o = \Gini\IoC::construct($class_name); // some object might not have database backend $db = $o->db(); if (!$db) { return; } printf(" %s\n", $oname); $structure = $o->structure(); foreach ($structure as $field => $option) { if (isset($option['object'])) { $db->query('UPDATE :table SET :field=NULL WHERE :field=0', [':table' => $o->tableName(), ':field' => $field . '_id']); } } }); } echo " [32mdone.[0m\n"; }
public static function fetch($env = null) { $items = []; $paths = \Gini\Core::pharFilePaths(RAW_DIR, 'config'); foreach ($paths as $path) { self::_load_config_dir($path, $items); } $env = $env ?: $_SERVER['GINI_ENV'] ?: ''; if ($env) { $paths = \Gini\Core::pharFilePaths(RAW_DIR, 'config/@' . $env); foreach ($paths as $path) { self::_load_config_dir($path, $items); } } return $items; }
private static function _rurl_mod($url, $type) { $info = \Gini\Core::moduleInfo(APP_ID); $config = (array) \Gini\Config::get('system.rurl_mod'); if ($type) { $query = $config[$type]['query']; $query = $query ? strtr($query, ['$(TIMESTAMP)' => time(), '$(VERSION)' => $info->version]) : null; } return empty($query) ? $url : self::url($url, $query); }