/** * Constructor. * * @param string $message [optional] Exception message. Leave empty to autogenerate a message. Default: `""`. * @param integer $code [optional] Exception code. Default: `0`. * @param Exception $previous [optional] Previous exception. Default: `null`. */ public function __construct($message = '', $code = 0, Base_Exception $previous = null) { if (empty($message)) { $trace = Debugger::getPrettyTrace(debug_backtrace()); if (isset($trace[1])) { $message = 'Function "' . $trace[1]['function'] . '" defined in "' . $trace[1]['file'] . '" has not been fully implemented yet.'; } } parent::__construct($message, $code, $previous); }
/** * Constructor. * * @param string $expected Expected type. * @param mixed $actual Actual argument given. * @param int $number [optional] Argument number. * @param bool $hideCaller [optional] Should the function that has thrown this exception be hidden? Default: `false`. */ public function __construct($expected, $actual, $number = 1, $hideCaller = false) { $trace = Debugger::getPrettyTrace(debug_backtrace()); $type = Debugger::getType($actual); $type = $type === 'string' ? $type . ' ("' . StringUtils::truncate($actual, 50) . '")' : $type; if (!$hideCaller && isset($trace[1])) { $message = $trace[1]['function'] . ' expected argument ' . $number . ' to be ' . $expected . ', ' . $type . ' given.'; } else { $message = 'Expected argument ' . $number . ' to be ' . $expected . ', ' . $type . ' given.'; } parent::__construct($message); }
/** * When the found controller method wants to have the request injected, * this method will do it. * * @param ControllerWillRespond $event Event triggered before execution of controller. */ public function injectRequest(ControllerWillRespond $event) { $route = $this->router->getRoute($event->getControllerName()); // find the method's meta data $methods = $route->getMethods(); $i = ArrayUtils::search($methods, 'method', $event->getMethod()); if ($i === false) { return; } $method = $methods[$i]; $arguments = $event->getArguments(); foreach ($method['params'] as $i => $param) { if ($param['class'] && Debugger::isExtending($param['class'], Request::class, true) && !$arguments[$i] instanceof Request) { $arguments[$i] = $this->request; } } $event->setArguments($arguments); }
/** * Returns directory where this module is located. * * @return string */ public function getModuleDir() { if ($this->moduleDir) { return $this->moduleDir; } $this->moduleDir = dirname(Debugger::getClassFile($this)); return $this->moduleDir; }
public function testGetPrettyTrace() { $prettyTrace = Debugger::getPrettyTrace(debug_backtrace()); $this->assertInternalType('array', $prettyTrace); if (!empty($prettyTrace)) { foreach ($prettyTrace as $item) { $this->assertArrayHasKey('function', $item); $this->assertArrayHasKey('file', $item); $this->assertArrayHasKey('arguments', $item); } } }
/** * Returns all paretns of a class. * * @param string $class Class name. * * @return array */ public function getClassParents($class) { $class = (string) $class; return Debugger::getObjectAncestors($class); }
/** * Handles invoking magic methods `::findBy*` and `::findOneBy*`. * * @param string $method Called method name. * @param array $arguments Array of arguments the method was called with. * * @return array|object|null * * @throws \InvalidArgumentException If any of the arguments is invalid. * @throws \BadMethodCallException When couldn't resolve to a valid method. */ public function __call($method, array $arguments) { if (!isset($arguments[0])) { throw new \InvalidArgumentException(sprintf('Missing 1st argument for method ::%s', $method)); } $params = []; if (isset($arguments[1])) { if (!is_array($arguments[1])) { throw new \InvalidArgumentException(sprintf('2nd argument for method ::%s must be an array, %s given.', $method, Debugger::getType($arguments[1]))); } $params = $arguments[1]; } if (strpos($method, 'findBy') === 0) { $property = StringUtils::toSeparated(substr($method, 6), '_'); return $this->find([$property => $arguments[0]], $params); } if (strpos($method, 'findOneBy') === 0) { $property = StringUtils::toSeparated(substr($method, 9), '_'); return $this->findOne([$property => $arguments[0]], $params); } throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s', __CLASS__, $method)); }
/** * Returns the name of this kernel - its class name by default. * * @return string */ public function getName() { if (!$this->name) { $this->name = Debugger::getClass($this, true); } return $this->name; }
/** * Parses arguments of a method call. * * @param array $arguments Arguments. * * @return array */ private function parseCallArguments(array $arguments) { $args = []; foreach ($arguments as $argument) { if (is_object($argument)) { $args[] = '<comment>(object)</comment> ' . StringUtils::truncate(Debugger::getClass($argument), 32, '...', StringUtils::TRUNCATE_MIDDLE); } elseif (is_array($argument)) { $args[] = '<comment>(array)</comment> ' . StringUtils::truncate(json_encode($argument), 32, '...', StringUtils::TRUNCATE_MIDDLE); } elseif (is_string($argument)) { $args[] = sprintf("'%s'", StringUtils::truncate($argument, 32, '...', StringUtils::TRUNCATE_MIDDLE)); } else { $args[] = $argument; } } return implode(', ', $args); }
/** * Checks whether or not the data mapper supports the given class. * * All objects that can be managed by this data mapper MUST implement `ArraySerializableInterface`. * * @param string $class Class to be checked if it can be mapped with this data mapper. * * @return boolean */ public function supports($class) { return Debugger::isImplementing($class, ArraySerializableInterface::class); }
public function __construct($name, $object) { parent::__construct($name); $this->instance = $object; $this->class = Debugger::getType($object); }
/** * Registers a command. * * @param string $name Name of the command. * @param string $commandClass Class name of the command. */ public function addCommand($name, $commandClass) { // must extend AbstractCommand $abstractCommandClass = AbstractCommand::class; if (!Debugger::isExtending($commandClass, $abstractCommandClass)) { throw new InvalidCommandException('Command "' . $commandClass . '" must extend "' . $abstractCommandClass . '".'); } // name cannot be empty $name = trim($name); if (empty($name)) { throw new InvalidArgumentException('Command name cannot be empty for "' . $commandClass . '"!'); } // configure the command $console = $this; $consoleCommand = new ConsoleCommand($name); $consoleCommand->setDescription($commandClass::getDescription()); $consoleCommand->setHelp($commandClass::getHelp()); $consoleCommand->setCode(function (InputInterface $input, OutputInterface $output) use($console, $name) { $console->exec($name, $input, $output); }); // read some meta info about the command $commandReflection = new \ReflectionClass($commandClass); $arguments = array(); $argumentsDescriptions = $commandClass::getArguments(); try { $methodReflection = $commandReflection->getMethod('execute'); if (!$methodReflection->isPublic() || $methodReflection->isStatic()) { throw new InvalidCommandException('The "execute()" method for ommand "' . $commandClass . '" must be public and non-static.'); } // get the execute() method's arguments so we can translate them to CLI arguments $parametersReflection = $methodReflection->getParameters(); foreach ($parametersReflection as $param) { $optional = $param->isDefaultValueAvailable(); $paramName = $param->getName(); $arguments[] = array('name' => $paramName, 'optional' => $optional, 'default' => $optional ? $param->getDefaultValue() : null, 'description' => isset($argumentsDescriptions[$paramName]) ? $argumentsDescriptions[$paramName] : ''); } } catch (\ReflectionException $e) { throw new InvalidCommandException('Command "' . $commandClass . '" must implement public function "execute()"!'); } foreach ($arguments as $argument) { $consoleCommand->addArgument($argument['name'], $argument['optional'] ? InputArgument::OPTIONAL : InputArgument::REQUIRED, $argument['description'], $argument['default']); } // also register command's options $options = $commandClass::getOptions(); foreach ($options as $option => $optionInfo) { $value = isset($optionInfo['required']) && $optionInfo['required'] ? InputOption::VALUE_REQUIRED : (!isset($optionInfo['default']) || empty($optionInfo['default']) || $optionInfo['default'] === null ? InputOption::VALUE_NONE : InputOption::VALUE_OPTIONAL); $consoleCommand->addOption($option, isset($optionInfo['shortcut']) ? $optionInfo['shortcut'] : null, $value, isset($optionInfo['description']) ? $optionInfo['description'] : '', $value === InputOption::VALUE_REQUIRED || $value === InputOption::VALUE_NONE ? null : (isset($optionInfo['default']) ? $optionInfo['default'] : null)); } // register the command $this->commands[$name] = array('name' => $name, 'class' => $commandClass, 'command' => $consoleCommand, 'arguments' => $arguments, 'options' => $options); $this->consoleApplication->add($consoleCommand); }
/** * Returns (basic) information about all registered services. * * @return array */ public function dump() { $services = array(); foreach ($this->services as $name => $definition) { $info = array('name' => $name); $class = $definition->getClass(); if ($class) { $info['class'] = ltrim($this->parametersResolver->resolve($class), NS); } if ($definition instanceof ObjectService) { $info['class'] = Debugger::getClass($definition->getInstance()); } $services[$name] = $info; } foreach ($this->aliases as $alias => $target) { $services[$alias] = array('name' => $alias, 'alias' => $this->resolveServiceName($target)); } return $services; }
/** * Execute the given controller. * * @param string $name Name of the controller or route assigned to this controller. * @param string $class Class name of the controller. * @param string $method Method name to execute on the controller. * @param array $arguments [optional] Arguments to execute the controller with. * @return Response */ protected function renderController($name, $class, $method, array $arguments = array(), Request $request = null) { $eventManager = $this->container->get('event_manager'); $controller = new $class($this->container); $willRespondEvent = new ControllerWillRespond($name, $controller, $method, $arguments); $eventManager->trigger($willRespondEvent); $method = $willRespondEvent->getMethod(); $arguments = $willRespondEvent->getArguments(); $controllerResponse = new ControllerResponse(call_user_func_array(array($controller, $method), $arguments)); $eventManager->trigger(new ControllerDidRespond($controllerResponse, $name, $controller, $method, $arguments, $request)); $response = $controllerResponse->getResponse(); $this->logger->debug('Executed controller: "{name}"', array('name' => $name, 'function' => $class . '::' . $method, 'arguments' => $arguments, '_timer' => $this->container->get('splot.timer')->step('Matched route'))); // special case, if the response is a string then automatically convert it to HttpResponse if (is_string($response)) { $response = new Response($response); } if (!is_object($response) || !$response instanceof Response) { throw new InvalidReturnValueException('Executed controller method must return ' . Response::class . ' instance or a string, "' . Debugger::getType($response) . '" given.'); } return $response; }
/** * Attempts to find and verify a repository class for the given object class. * * @param string $objectClass Object class. * @param string $repositoryClass [optional] Suggested repository class, if any. * * @return string */ protected function findRepositoryClass($objectClass, $repositoryClass = null) { // figure out a repository class if none given if ($repositoryClass === null) { $repositoryClass = $objectClass . 'Repository'; if (!class_exists($repositoryClass)) { // return already and don't bother checking, as we know it return Repository::class; } } // verify the repository class if (!Debugger::isExtending($repositoryClass, Repository::class, true)) { throw new \RuntimeException(sprintf('An object repository class must extend %s, but %s given.', Repository::class, $repositoryClass)); } return $repositoryClass; }
/** * Performs application and its dependency injection container configuration by loading appropriate files * into the config and the container from the application dir and all the modules. * * @param AbstractApplication $application Application to be ran. * @param string $env [optional] Environment in which the application should be ran. Default: `dev`. * @param boolean $debug [optional] Should application be ran in debug mode? Default: `true`. */ protected function doConfigureApplication(AbstractApplication $application, $env = 'dev', $debug = true) { $container = $application->getContainer(); // load framework parameters and services definition from YML file $container->loadFromFile(__DIR__ . '/framework.yml'); // set parameters to be what the framework has been initialized with $container->setParameter('framework_dir', __DIR__); $container->setParameter('application_dir', dirname(Debugger::getClassFile($application))); $container->setParameter('env', $env); $container->setParameter('debug', $debug); $container->setParameter('not_debug', !$debug); // maybe application wants to provide some high-priority parameters as well? $container->loadFromArray(array('parameters' => $application->loadParameters($env, $debug))); // already register Whoops to handle errors, so it also works during config $container->get('whoops')->register(); // we're gonna stick to the config dir defined at this point $configDir = rtrim($container->getParameter('config_dir'), DS); // prepare the config, but make it reusable in the cached container as well // so we're gonna modify the definition to include existing files when needed $configDefinition = $container->getDefinition('config'); // doing it like this to make sure that env config file is loaded after the base $configFiles = array_merge(FilesystemUtils::glob($configDir . '/config.{yml,yaml,php}', GLOB_BRACE), FilesystemUtils::glob($configDir . '/config.' . $env . '.{yml,yaml,php}', GLOB_BRACE)); foreach ($configFiles as $file) { $configDefinition->addMethodCall('loadFromFile', array($file)); } // now that we have the config built, let's get it $config = $container->get('config'); // pass some necessary parameters from the config $container->setParameter('log_file', $config->get('log_file')); $container->setParameter('log_level', $config->get('log_level')); // configure modules one by one foreach ($application->getModules() as $module) { $this->configureModule($module, $application, $env, $debug); } // configure the application $application->configure(); }