public function __construct($compile_dir = NULL, $template_dir = NULL, $cache_dir = NULL, $plugins_dir = [], $config_dir = [], $disable_security = FALSE, Loops $loops = NULL) { parent::__construct($loops); $loops = $this->getLoops(); $application = $loops->getService("application"); $renderer = $loops->getService("renderer"); $app_dir = $application->app_dir; $cache_dir = $application->cache_dir; //adjust directories $compile_dir = Misc::fullPath($compile_dir ?: "renderer_cache/smarty", $cache_dir); $template_dir = array_map(function ($path) use($app_dir) { return Misc::fullPath($path, $app_dir); }, (array) ($template_dir ?: $renderer->view_dir)); $cache_dir = Misc::fullPath($compile_dir ?: "renderer_cache/smarty_cache", $cache_dir); $plugins_dir = array_map(function ($path) use($app_dir) { return Misc::fullPath($path, $app_dir); }, (array) $plugins_dir); $config_dir = array_map(function ($path) use($app_dir) { return Misc::fullPath($path, $app_dir); }, (array) $config_dir); //setup smarty $this->smarty = new Smarty(); $this->smarty->setCompileDir($compile_dir); $this->smarty->setTemplateDir($template_dir); $this->smarty->setCacheDir($cache_dir); $this->smarty->addPluginsDir($plugins_dir); $this->smarty->setConfigDir($config_dir); if ($disable_security) { $this->smarty->disableSecurity(); } //register extra modifier $this->smarty->registerPlugin("modifier", "render", [$loops->getService("renderer"), "render"]); $this->smarty->registerPlugin("modifier", "tr", [$this, "tr"]); }
public function __construct($filename = "loops.log", $mode = "a+", $level = "notice", Loops $loops = NULL) { parent::__construct($level, $loops); $application = $this->getLoops()->getService("application"); $filename = Misc::fullPath($filename, $application->cache_dir); $this->fo = new SplFileObject($filename, $mode); }
public function setValue($value) { if (is_array($value)) { $value = new ArrayObject($value); } $current = $this->subform->getFormElements(); foreach (array_keys($current) as $key) { $this->subform->offsetUnset($key); } if ($value instanceof ArrayObject) { $values = $value->toArray(); } elseif ($value instanceof Traversable) { $values = iterator_to_array($value); } else { $values = (array) $value; } static $meh = 0; if ($meh++ > 40) { throw new \Exception("Meh"); } foreach ($values as $k => $v) { $element = array_key_exists($k, $current) ? $current[$k] : Misc::deepClone($this->newelement); $element->setValue($v); $value->offsetSet($k, $element->getValue(FALSE)); $this->subform->offsetSet($k, $element); } return parent::setValue($value); }
/** * Creates the logging service. * * A logger name can be specified in config variable 'plugin'. * An instance of "Loops\Logger\%Logger" will be attached to this logger * with % being the camelized version of the loggers name. * An array can also be passed to attach multiple loggers. * Alternatively multiple loggers can be passed as a comma separated * string. * Other configuration parameters are passed to the constructor(s) of the * logging class(es). */ public static function getService(ArrayObject $config, Loops $loops) { $logger = parent::getService($config, $loops); $plugin = $config->offsetExists("plugin") ? $config->offsetGet("plugin") : "stderr"; foreach (array_filter(is_array($plugin) ? $plugin : explode(",", $plugin)) as $plugin) { $classname = "Loops\\Logger\\" . Misc::camelize($plugin) . "Logger"; $logger->attach(Misc::reflectionInstance($classname, $config)); } return $logger; }
public function __construct($view_dir = [], Loops $loops = NULL) { parent::__construct($loops); $this->view_dir = array_map(function ($dir) { return Misc::fullPath($dir, $this->getLoops()->getService("application")->app_dir); }, (array) $view_dir); $this->view_dir = array_filter($this->view_dir, "is_dir"); $loops_views = realpath(__DIR__ . "/../../../views"); if (!in_array($loops_views, $this->view_dir)) { $this->view_dir[] = $loops_views; } }
public static function getService(ArrayObject $config, Loops $loops) { $config = static::getConfig($loops, $config); $classname = str_replace("%", $config->plugin, static::getClassname($loops)); if (!class_exists($classname)) { throw new Exception("Class '{$classname}' is requested by '" . get_called_class() . "' but it was not found."); } $reflection = new ReflectionClass($classname); $interface = static::getInterface($loops); if (!$reflection->implementsInterface($interface)) { throw new Exception("Class '{$classname}' must implement '{$interface}'."); } return Misc::reflectionInstance($classname, $config); }
public function __construct($entity, $filter = NULL, $fields = [], $limit = 10, $alias = NULL, $order = [], $prepare_callback = NULL, $context = NULL, Loops $loops = NULL) { parent::__construct($entity, $limit, $alias, $order, $context, $loops); //set default filter from classname if ($filter === NULL) { $parts = explode("\\", get_class($context ?: $this)); $filter = Misc::underscore(array_pop($parts)); } //create filterform $this->filterform = $this->initChild("filterform", new Form(NULL, $filter, $context, $loops)); $this->filterform->addFromAnnotations($this->entity, $filter, $this, $loops); $this->filterform->onConfirm = function () { return FALSE; }; EntityForm::enhanceFromEntity($this->filterform, $entity, $filter, $fields, $loops); if (is_string($prepare_callback)) { $prepare_callback = [$context, $prepare_callback]; } if (is_callable($prepare_callback)) { $this->prepare_callback = $prepare_callback; } }
public static function getService(ArrayObject $config, Loops $loops) { $redis = parent::getService($config, $loops); $params = static::getDefaultConfig($loops); $params->merge($config); $params = $params->toArray(); //use closure to forward connect call - Redis objects can not be analyzed for some reason by the reflection api $connect = function ($host = "localhost", $port = 6379, $timeout = 0, $persistent_id = NULL, $retry_interval = NULL, $persistent = FALSE) use($redis) { if ($persistent) { return $redis->pconnect($host, $port, $timeout, $persistent_id, $retry_interval); } else { return $redis->connect($host, $port, $timeout, $persistent_id, $retry_interval); } }; Misc::reflectionFunction($connect, $params); if (!empty($params["password"])) { $redis->auth($params["password"]); } if (!empty($params["database"])) { $redis->select((int) $params["database"]); } return $redis; }
/** * Setups a Loops application. * * This constructor will take a Loops context (via the $config parameter) or create a new one. * * The application will register itself as a service named 'application'. * Therefore, the application instance can be quickly accessed in a Loops\Object by $this->application. * * In Debug mode, changes in the application folder are attempted to be detected and if so, the complete cache (according to service 'cache') and renderer cache files (according to service 'renderer') will be deleted. * * The application will also speed up autoloading classes by remembering the filenames of class definitions in the cache module. * This behaviour can be disabled by setting the config value ->application->enable_cached_autoload to FALSE * * Include Dir: * The value ->application->include_dir is read from the config and defines paths that are consided for autoloading in the PSR-4 format. * This value can be an absolute path or relative to $app_dir. If not specified, [ 'inc' ] is used by default which specifies the 'inc' directory insied the application directory. * * Boot: * The value ->application->boot can hold a name of a php file that is executed after application creation. * This value can be an absolute path or relative to $app_dir. By default the file 'boot.php' inside the application directory is used. * Inside the boot script only the variable $loops is set. * * @param string $app_dir The application directory * @param string $cache_dir The directory for temporary files (as full paths or relative to $appdir) * @param string|Loops|Loops\ArrayObject $config A Loops context, a Loops\ArrayObject that is used to create a Loops context or the location of a php file that returns a Loops\ArrayObject or Loops context. * @param bool $boot Specifies if the boot script should be executed */ public function __construct($app_dir, $cache_dir = "/tmp", $config = "config.php", $boot = TRUE) { //setup directories $app_dir = realpath($app_dir); $cache_dir = Misc::fullPath($cache_dir, $app_dir); //make a context from config file if (is_string($config)) { $config = (include Misc::fullPath($config, $app_dir)); } if ($config instanceof ArrayObject) { $loops = new Loops($config, @$config->loops->debug === NULL ? TRUE : (bool) @$config->loops->debug); } elseif ($config instanceof Loops) { $loops = $config; } else { throw new Exception("Failed to create Loops Context."); } //register application service $loops->registerService("application", $this); $this->app_dir = $app_dir; $this->cache_dir = $cache_dir; $this->include_dir = (array) (@$loops->config->application->include_dir === NULL ? ["inc"] : $loops->config->application->include_dir); $this->boot = @$loops->config->application->boot ?: "boot.php"; $this->enable_cached_autoload = @$loops->config->application->enable_cached_autoload === NULL ? TRUE : $loops->config->application->enable_cached_autoload; $this->enable_cache_flush = @$loops->config->application->enable_cache_flush === NULL ? TRUE : $loops->config->application->enable_cache_flush; if (substr($this->boot, 0, 1) != "/") { $this->boot = "{$app_dir}/" . $this->boot; } foreach ($this->include_dir as $key => $include_dir) { if (substr($include_dir, 0, 1) != "/") { $this->include_dir[$key] = "{$app_dir}/{$include_dir}"; } } //register autoload foreach ($this->include_dir as $path) { spl_autoload_register(function ($classname) use($path) { $filename = $path . "/" . str_replace("\\", "/", $classname) . ".php"; if (!file_exists($filename)) { return; } require_once $filename; }); } if ($this->enable_cached_autoload) { $this->setupCachedAutoload($loops); } //delete cache if files have changed - do this check only in debugmode if ($this->enable_cache_flush && $loops->debug) { $cache = $loops->getService("cache"); $renderer = $loops->getService("renderer"); $dirs = []; if ($this->enable_cache_flush & 0x1) { $dirs[] = $this->app_dir; } if ($this->enable_cache_flush & 0x2) { $dirs = array_merge($dirs, $this->include_dir); } if ($this->enable_cache_flush & 0x4) { $dirs = array_merge($dirs, $renderer->view_dir); } if ($file = Misc::lastChange($dirs, $cache, $key)) { Misc::recursiveUnlink("{$this->cache_dir}/renderer_cache"); $cache->flushAll(); $cache->save($key, $file->getMTime()); } } parent::__construct($loops); //boot if requested if ($boot) { $this->boot(); } }
public function __get($key) { if (!$this->swiftclassname) { $key = Misc::camelize($key); return new Swiftmailer($this->config, "Swift_{$key}"); } }
public function getAddForm() { if (is_string($this->persist)) { $arguments["entity"] = $this->entity; $arguments["filter"] = $this->persist_filter; $arguments["fields"] = $this->persist_fields; $arguments["context"] = $this; $arguments["loops"] = $this->getLoops(); return Misc::reflectionInstance($this->persist, $arguments); } if ($this->persist) { if ($this->persist instanceof Form) { return $this->persist; } return new PersistEntityForm($this->entity, $this->persist_filter, $this->persist_fields, $this, $this->getLoops()); } }
public function testFullPathsUpper() { $cwd = getcwd(); $parts = explode(DIRECTORY_SEPARATOR, $cwd); array_pop($parts); $path = implode(DIRECTORY_SEPARATOR, $parts); if ($cwd != "/") { $this->assertEquals($path . DIRECTORY_SEPARATOR . 'test', Misc::fullPath('../test', NULL, TRUE)); } $this->assertEquals('/test' . DIRECTORY_SEPARATOR . 'test', Misc::fullPath('../test', '/test' . DIRECTORY_SEPARATOR . 'sub', TRUE)); $this->assertEquals('/test' . DIRECTORY_SEPARATOR . 'test', Misc::fullPath('../test', '/test' . DIRECTORY_SEPARATOR . 'sub' . DIRECTORY_SEPARATOR, TRUE)); $this->assertEquals('C:\\test' . DIRECTORY_SEPARATOR . 'test', Misc::fullPath('../test', 'C:\\test' . DIRECTORY_SEPARATOR . 'sub', TRUE)); $this->assertEquals('C:\\test' . DIRECTORY_SEPARATOR . 'test', Misc::fullPath('../test', 'C:\\test' . DIRECTORY_SEPARATOR . 'sub' . DIRECTORY_SEPARATOR, TRUE)); }
/** * @Listen("Form\onCleanup") */ protected function deleteFile() { return Misc::recursiveUnlink($this->getUploadDir()); }
private function resolveOutput($url, $is_ajax) { $loops = $this->getLoops(); foreach ($this->resolvePage($url) as $set) { list($pageclass, $this->page_parameter, $this->parameter) = $set; $this->page = $pageclass; $this->page = Misc::reflectionInstance($pageclass, ["parameter" => $this->page_parameter, "loops" => $loops]); $action_result = $this->page->action($this->parameter); if (is_string($action_result)) { return $action_result; } if ($action_result === TRUE) { return $this->page; } if (is_object($action_result)) { return $is_ajax ? $action_result : $this->page; } if (is_integer($action_result)) { if ($action_result == 404) { continue; } if ($action_result <= 0) { return ""; } $loops->getService("response")->setStatusCode($action_result); $this->page = Misc::reflectionInstance($this->error_page, ['status_code' => $action_result, 'loops' => $loops]); return $this->page; } } $this->page_parameter = []; $this->parameter = $url == "/" ? [] : explode("/", ltrim($url, "/")); $this->page = Misc::reflectionInstance($this->error_page, ['status_code' => 404, 'loops' => $loops]); $loops->getService("response")->setStatusCode(404); return $this->page; }
<?php use Loops\Misc; use Loops\Application\CliApplication; use Doctrine\ORM\Tools\Console\ConsoleRunner; require_once __DIR__ . "/vendor/autoload.php"; class HelperSetCreator extends CliApplication { public function exec($params) { $entity_manager = $this->getLoops()->getService("doctrine"); return ConsoleRunner::createHelperSet($entity_manager); } } try { return (new HelperSetCreator(__DIR__ . "/../app/"))->run(); } catch (Exception $e) { Misc::displayException($e, FALSE); }
private function getJobs() { $loops = $this->getLoops(); $application = $loops->getService("application"); $classnames = array_filter($application->definedClasses(), function ($classname) { if (!class_exists($classname)) { return FALSE; } $reflection = new ReflectionClass($classname); if ($reflection->isAbstract()) { return FALSE; } if (!$reflection->implementsInterface("Loops\\Jobs\\JobInterface")) { return FALSE; } return TRUE; }); $jobs = []; foreach ($classnames as $classname) { if (substr($classname, 0, 5) == "Jobs\\") { $name = substr($classname, 5); } $job = Misc::reflectionInstance($classname, ["loops" => $loops]); $jobs[$name] = $job; } return $jobs; }
public function offsetGet($key) { if (parent::offsetExists($key)) { return parent::offsetGet($key); } return $this->repository(Misc::camelize($key)); }
/** * Creates a new instance of a service * * @param $name The service name * @param array $config * @return Loops\Service\ServiceInterface The new service */ public function createService($name, ArrayObject $config = NULL, $merge_into_config = FALSE) { if ($merge_into_config) { $service_config = $this->config->offsetExists($name) ? $this->config->offsetGet($name) : new ArrayObject(); if (is_array($service_config)) { $service_config = ArrayObject::fromArray($service_config); } if ($config) { $service_config->merge($config); } } else { $service_config = $config ?: new ArrayObject(); } if (!$this->hasService($name)) { throw new Exception("Service '{$name}' does not exist."); } $service = $this->services[$name]; if (array_key_exists("classname", $service)) { $reflection = new ReflectionClass($service["classname"]); $params = new ArrayObject($service["params"]); $params->merge($service_config); if ($reflection->implementsInterface("Loops\\ServiceInterface")) { return call_user_func_array([$service["classname"], "getService"], [$params, $this]); } else { $params->offsetSet("loops", $this); return Misc::reflectionInstance($service["classname"], $params); } } if (array_key_exists("callback", $service)) { $params = new ArrayObject($service["params"]); $params->merge($service_config); return call_user_func_array($service["callback"], $params->toArray()); } if (array_key_exists("object", $service)) { return $service["object"]; } }
/** * Outputs a file that can be paused and resumed by the client (by following the partial content spec) * * Additionally, this function will also set up correct file headers (Content-Type, Content-Disposition, etc) * or can return them as an array if $returnheader is set to TRUE. * In this case no fileoutput will be generated. You can use Loops\Misc::readpartialfile to actually send the file. * * The Content-Disposition header will always be set to 'attachment'. 'servefiles' purpose is to provide * a resumeable download. If you want to send inline content, use PHPs readfile and header functions instead. * * $filename or $mimetype can be also set to a boolean. If boolean TRUE, values will be infered from the $file. * If set to FALSE, values will NOT be included in the headers. * i.e. no filename="..." in Content-Disposition and/or no Content-Type header. * * If the file and headers have been sent, -1 is returned, thus not genarating additional output. * In case of an error, a http status code is generated (4xx, 5xx series) and returned. * You can conveniently use this funcion in the action method of loops elements: * <code> * use Loops\Misc; * * public function action($parameter) { * return Misc::servefile("example.png"); * } * </code> * * This function will raise an exeption if there is already data in an outbut buffer or headers were already sent. * * @todo Do not rely on $_SERVER variable for the partial spec * * @param string $file The physical location of the file (must be understood by fopen) * @param bool|string $filename An alternate filename that is sent in Content-Disposition (must be an UTF-8 string or bool) * @param bool|string $mimetype The mimetype that is used for the Content-Type header. * @param bool $returnheader If set to TRUE, headers will be returned as an array (no output is generated) * @param resource $context The context passed to fopen. * @return int|array An http status code or an array of headers */ public static function servefile($file, $filename = TRUE, $mimetype = TRUE, $returnheader = FALSE, $force = FALSE, $context = NULL) { if (headers_sent()) { throw new Exception("Can't serve file because output headers have already been sent."); } if (!$force) { if (!@file_exists($file)) { return 404; } if (!@is_readable($file)) { return 403; } } //detect mimetype - note that spl fileobject does not support this over data urls for some reason if ($mimetype === TRUE) { $mimetype = "application/octet-stream"; if ($finfo = finfo_open(FILEINFO_MIME_TYPE)) { if ($type = finfo_file($finfo, $file)) { $mimetype = $type; } finfo_close($finfo); } } //open file if (!$file instanceof SplFileObject) { $file = new SplFileObject($file); } //get size $filesize = $file->getSize(); //get requested range from header $range = FALSE; if (isset($_SERVER["HTTP_RANGE"])) { $range = $_SERVER["HTTP_RANGE"]; } else { if (isset($_SERVER["HTTP_CONTENT_RANGE"])) { $range = $_SERVER["HTTP_CONTENT_RANGE"]; } else { if (function_exists('apache_request_headers')) { $headers = apache_request_headers(); foreach ($headers as $key => $value) { if (strtolower($key) == "range") { $range = $value; break; } } } } } //partial information $partial = FALSE; if ($range) { if (strpos($range, '=') === FALSE) { return 400; } list($param, $range) = explode('=', $range, 2); if (strtolower(trim($param)) != 'bytes') { // Bad request - range unit is not 'bytes' return 400; } $range = explode(',', $range); $range = explode('-', $range[0]); // We only deal with the first requested range if (count($range) != 2) { // Bad request - 'bytes' parameter is not valid return 400; } if ($range[0] === '') { // First number missing, return last $range[1] bytes $offset = $filesize - intval($range[1]); if ($offset && $offset < $filesize) { $partial = [$offset, $filesize - 1]; } else { return 416; } } else { if ($range[1] === '') { // Second number missing, return from byte $range[0] to end $offset = intval($range[0]); if ($offset < $filesize) { $partial = [$offset, $filesize - 1]; } else { return 416; } } else { // Both numbers present, return specific range $offset1 = intval($range[0]); $offset2 = intval($range[1]); if ($offset1 < $filesize && $offset2 < $filesize) { $partial = [$offset1, $offset2]; } else { return 416; } } } } if ($filename) { if ($filename === TRUE) { $filename = basename($file); } // get user-agent from header $useragent = FALSE; if (isset($_SERVER["HTTP_USER_AGENT"])) { $useragent = $_SERVER["HTTP_USER_AGENT"]; } else { if (function_exists('apache_request_headers')) { $headers = apache_request_headers(); foreach ($headers as $key => $value) { if (strtolower($key) == "user-agent") { $useragent = $value; break; } } } } //we need to get a cross browser compatible filename for the header. oh boy.... //lets trust the following stack overflow question: // http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http if ($useragent && preg_match("/IE [5678]\\./", $useragent)) { $filename = " filename=" . urlencode($filename); } else { if ($useragent && preg_match("/Safari/", $useragent)) { $filename = " filename={$filename}"; } else { if ($useragent && preg_match("/[^a-zA-Z0-9_\\.]/", $filename)) { $filename = " filename=\"{$filename}\"; filename*=UTF-8''" . urlencode($filename); } else { $filename = " filename=\"{$filename}\";"; } } } } //create output headers $length = $partial ? $partial[1] - $partial[0] + 1 : $filesize; $headers = array(); $headers[] = "Content-Type: {$mimetype}"; $headers[] = "Content-Disposition: attachment;{$filename}"; $headers[] = "Content-Length: {$length}"; $headers[] = "Accept-Ranges: bytes"; if ($partial) { $headers[] = "Content-Range: bytes {$partial['0']}-{$partial['1']}/{$filesize}"; } if ($returnheader) { return $headers; } //actual output happens from now on //set status code and header if (!$context) { $context = Loops::getCurrentLoops(); } if ($partial) { $context->response->setStatusCode(206); } foreach ($headers as $line) { $context->response->addHeader($line); } $context->response->setHeader(); if ($filesize) { if ($partial) { $bytes = Misc::readPartialFile($file, $partial[0], $partial[1], $context); } else { $bytes = $file->fpassthru(); } //if no output was generated, the above functions failed and we have to/can recover if (!$bytes) { //remove previously set headers foreach ($headers as $line) { $context->response->removeHeader($line); } return 500; } } //do not generate output return -1; }
public function factory($context = NULL, Loops $loops = NULL) { if ($this->type == "CALLBACK") { if (!$context) { throw new Exception("Context needed for callback based annotation."); } $callback = [$context, $this->class]; if (!is_callable($callback)) { throw new Exception("Can't call method '{$this->class}' on object of class '" . get_class($context) . "'."); } $arguments = array_values(array_merge($this->arguments, [$context, $loops])); return call_user_func_array($callback, $arguments); } elseif ($this->type == "PROPERTY") { if (!$context) { throw new Exception("Context needed for property based annotation."); } $key = $this->class; if ($context instanceof ArrayAcces) { return $context->offsetGet($this->class); } elseif (property_exists($context, $this->class) || method_exists($context, "__get")) { return $context->{$key}; } throw new Exception("Property '{$key}' does not exist on object of class '" . get_class($context) . "'."); } elseif ($this->delegate_annotation_namespace && !$this->delegating) { $annotation_classname = $this->delegate_annotation_namespace . $this->class; if (class_exists($annotation_classname)) { $this->delegating = TRUE; $vars = get_object_vars($this); $reflection = new ReflectionClass($annotation_classname); if ($reflection->getConstructor()) { $vars = array_merge($vars, $this->arguments); $vars["arguments"] = []; $annotation = $reflection->newInstance($vars); } else { $annotation = $reflection->newInstance(); foreach ($vars as $key => $value) { if (!property_exists($annotation, $key)) { continue; } $annotation->{$key} = $value; } } $result = $annotation->factory($context, $loops); $this->delegating = FALSE; return $result; } } $arguments = $this->arguments; self::transformAnnotations($arguments, $context, $loops); $arguments["context"] = $context; $arguments["loops"] = $loops; return Misc::reflectionInstance($this->getClassname($context), new ArrayObject($arguments), TRUE, FALSE, ["context", "loops"]); }
/** * Runs the request by by dispaching the request via the web core service. * This method will print the resulting output and set http status codes accordingly. * Exceptions will be caught and rendered. */ public function run() { try { $request = $this->getLoops()->getService("request"); $response = $this->getLoops()->getService("response"); $web_core = $this->getLoops()->getService("web_core"); //dispatch request echo $web_core->dispatch($this->url, $request, $response); } catch (Throwable $exception) { http_response_code(500); try { $renderer = $this->getLoops()->getService("renderer"); echo $renderer->render($exception); } catch (Throwable $render_exception) { Misc::displayException($exception); } } }
/** * Implements parsing of a modules action * * See class documentation for details */ protected function parse($strict = TRUE) { if (!($arguments = $this->flags->args())) { $message = "Module not specified.\n"; $message .= "\n"; $message .= "To get help type:\n"; $message .= "\n"; $message .= " {$this->command} " . implode(" ", array_merge($this->arguments, ["help"])); return $this->printError($message); } $module = array_shift($arguments); // check if we are in help mode $is_help = $module == "help"; if ($is_help) { if (!$arguments) { $modules = []; if (class_exists("Loops\\Application\\LoopsAdmin\\Cache")) { $modules[] = "cache"; } if (class_exists("Loops\\Application\\LoopsAdmin\\Jobs")) { $modules[] = "jobs"; } $message = "Welcome to the Loops admin.\n"; $message .= "\n"; $message .= "You can run Loops internal commands via this interface.\n"; $message .= "Loops internal commands are grouped into modules.\n"; $message .= "\n"; $message .= "Available (and known) modules:\n"; $message .= "\n"; $message .= $this->ident(implode(", ", $modules)) . "\n"; $message .= "\n"; $message .= "\n"; $message .= "To get help about a module:\n"; $message .= "\n"; $message .= " {$this->command} [<flags>...] help <module>\n"; $message .= "\n"; $message .= "Each module defines action(s) which are listed on the modules help page.\n"; $message .= "\n"; $message .= "\n"; $message .= "To get help about an action:\n"; $message .= "\n"; $message .= " {$this->command} [<flags>...] help <module> <action>\n"; $message .= "\n"; $message .= "\n"; $message .= "Available flags:"; return $this->printHelp($message); } // help for this module requested $module = array_shift($arguments); } $classname = "Loops\\Application\\LoopsAdmin\\" . Misc::camelize($module); if (!class_exists($classname)) { return $this->printError("Module not found: {$module}"); } $annotations = $this->getLoops()->getService("annotations")->get($classname); if (!$arguments) { if ($is_help) { if (!($help = $annotations->findFirst("Admin\\Help"))) { return $this->printError("Module '{$module}' does not define a help message."); } $actions = []; foreach ($annotations->methods as $method => $method_annotations) { if (!$method_annotations->findFirst("Admin\\Action")) { continue; } $actions[] = Misc::underscore($method); } $message = "Help for module '{$module}':\n"; $message .= "\n"; $message .= $this->ident($help->help) . "\n"; $message .= "\n"; $message .= "\n"; $message .= "Available actions:\n"; $message .= "\n"; $message .= $this->ident($actions ? implode(", ", $actions) : "No actions defined.") . "\n"; $message .= "\n"; $message .= "\n"; $message .= "To get help about an action:\n"; $message .= "\n"; $message .= " {$this->command} [<flags>...] help {$module} <action>\n"; $message .= "\n"; $message .= "\n"; $message .= "Available flags:"; return $this->printHelp($message); } else { return $this->printError("Action not specified for module '{$module}'."); } } $action = array_shift($arguments); $method = lcfirst(Misc::camelize($action)); if (empty($annotations->methods->{$method}) || !($action_annotation = $annotations->methods->{$method}->findFirst("Admin\\Action"))) { return $this->printError("Module '{$module}' does not support action: {$action}"); } $instance = new $classname($this->getLoops()); if ($action_annotation->init_flags) { if (!method_exists($instance, $action_annotation->init_flags)) { throw new Exception("Failed to init flags. Method '{$action_annotation->init}' is not defined."); } Misc::reflectionFunction([$instance, $action_annotation->init_flags], [$this->flags]); } if ($is_help) { if (!($help = $annotations->methods->{$method}->findFirst("Admin\\Help"))) { return $this->printError("Action '{$action}' of module '{$module}' does not define a help message."); } $message = "Usage:\n"; $message .= "\n"; $message .= " {$this->command} [<flags>...] {$module} {$action}" . ($action_annotation->arguments ? " {$action_annotation->arguments}" : "") . "\n"; $message .= "\n"; $message .= "\n"; $message .= "Help for action '{$module} {$action}':\n"; $message .= "\n"; $message .= $this->ident($help->help) . "\n"; $message .= "\n"; $message .= "\n"; $message .= "Available flags:"; return $this->printHelp($message); } try { $result = $this->flags->parse($this->arguments, !$strict, FALSE); } catch (Exception $e) { $message = $e->getMessage() . "\n"; $message .= "\n"; $message .= "To get help about this action:\n"; $message .= "\n"; $message .= " {$this->command} help {$module} {$action}"; return $this->printError($message); } $result = parent::parse(); if (is_integer($result)) { $this->printError("test"); return $result; } $result["__arguments"] = $arguments; $result["__module"] = $module; $result["__action"] = $action; $result["__instance"] = $instance; $result["__method"] = $method; return $result; }
/** * Trigger the submit action via URL * * The url must be exactly {$pagepath}/submit where $pagepath is the location * of this form in the loops page structure. * * If not accessed by a POST request, the user will be redirected back to the form. * In this case, the confirmed state will also be reset and the form has to be confirmed * again. * * This url can be accessed directly with the input as POST data. However for this, the * no_confirm property has to be set to true. Otherwise the user will be redirected to the * form page. * * The session will also be cleared after successfully submitting the form leaving no user * input on next access. */ public function submitAction($parameter) { if ($parameter) { return; } $this->initFromSession(); if (!$this->request->isPost()) { if ($this->confirmed) { $this->back(); $this->saveToSession(); } return Misc::redirect($this); } if ($this->no_confirm) { if (!$this->confirm($this->request->post())) { return TRUE; } } elseif (!$this->confirmed) { return Misc::redirect($this); } $this->submitted = $this->submit(); if ($this->no_confirm) { $this->confirmed = $this->submitted; } if ($this->submitted) { $this->clearSession(); } return TRUE; }
<?php /** * This file is part of the loops framework. * * @author Lukas <*****@*****.**> * @license https://raw.githubusercontent.com/loopsframework/base/master/LICENSE * @link https://github.com/loopsframework/base */ use Loops\Misc; use Loops\Application\WebApplication; try { $root_dir = realpath(__DIR__ . "/.."); require_once "{$root_dir}/vendor/autoload.php"; $url = $_GET["_url"]; unset($_GET["_url"]); $app = new WebApplication("{$root_dir}/app/", $url); $app->run(); } catch (Exception $e) { Misc::displayException($e); }