/**
	 * Call to undefined method.
	 * @param  object
	 * @param  string  method name
	 * @param  array   arguments
	 * @return mixed
	 * @throws MemberAccessException
	 */
	public static function call($_this, $name, $args)
	{
		$class = new NClassReflection($_this);

		if ($name === '') {
			throw new MemberAccessException("Call to class '$class->name' method without name.");
		}

		// event functionality
		if ($class->hasEventProperty($name)) {
			if (is_array($list = $_this->$name) || $list instanceof Traversable) {
				foreach ($list as $handler) {
					callback($handler)->invokeArgs($args);
				}
			}
			return NULL;
		}

		// extension methods
		if ($cb = $class->getExtensionMethod($name)) {
			array_unshift($args, $_this);
			return $cb->invokeArgs($args);
		}

		throw new MemberAccessException("Call to undefined method $class->name::$name().");
	}
Exemple #2
0
	/**
	 * __call() implementation.
	 * @param  object
	 * @param  string
	 * @param  array
	 * @return mixed
	 * @throws MemberAccessException
	 */
	public static function call($_this, $name, $args)
	{
		$class = get_class($_this);
		$isProp = self::hasProperty($class, $name);

		if ($name === '') {
			throw new MemberAccessException("Call to class '$class' method without name.");

		} elseif ($isProp === 'event') { // calling event handlers
			if (is_array($_this->$name) || $_this->$name instanceof Traversable) {
				foreach ($_this->$name as $handler) {
					NCallback::create($handler)->invokeArgs($args);
				}
			} elseif ($_this->$name !== NULL) {
				throw new UnexpectedValueException("Property $class::$$name must be array or NULL, " . gettype($_this->$name) ." given.");
			}

		} elseif ($cb = NClassReflection::from($_this)->getExtensionMethod($name)) { // extension methods
			array_unshift($args, $_this);
			return $cb->invokeArgs($args);

		} else {
			throw new MemberAccessException("Call to undefined method $class::$name().");
		}
	}
Exemple #3
0
	/**
	 * Sets a variable in this session section.
	 * @param  string  name
	 * @param  mixed   value
	 * @return void
	 */
	public function __set($name, $value)
	{
		$this->start();
		$this->data[$name] = $value;
		if (is_object($value)) {
			$this->meta[$name]['V'] = NClassReflection::from($value)->getAnnotation('serializationVersion');
		}
	}
Exemple #4
0
	public function generateCode($className, $parentName)
	{
		foreach ($this->extensions as $extension) {
			$extension->beforeCompile();
			$this->container->addDependency(NClassReflection::from($extension)->getFileName());
		}

		$classes[] = $class = $this->container->generateClass($parentName);
		$class->setName($className)
			->addMethod('initialize');

		foreach ($this->extensions as $extension) {
			$extension->afterCompile($class);
		}

		$defs = $this->container->getDefinitions();
		ksort($defs);
		$list = array_keys($defs);
		foreach (array_reverse($defs, TRUE) as $name => $def) {
			if ($def->class === 'NDINestedAccessor' && ($found = preg_grep('#^'.$name.'\.#i', $list))) {
				$list = array_diff($list, $found);
				$def->class = $className . '_' . preg_replace('#\W+#', '_', $name);
				$class->documents = preg_replace("#\\S+(?= \\$$name\\z)#", $def->class, $class->documents);
				$classes[] = $accessor = new NPhpClassType($def->class);
				foreach ($found as $item) {
					if ($defs[$item]->internal) {
						continue;
					}
					$short = substr($item, strlen($name)  + 1);
					$accessor->addDocument($defs[$item]->shared
						? "@property {$defs[$item]->class} \$$short"
						: "@method {$defs[$item]->class} create" . ucfirst("$short()"));
				}
			}
		}

		return implode("\n\n\n", $classes);
	}
Exemple #5
0
	/**
	 * Returns array of persistent components.
	 * This default implementation detects components by class-level annotation @persistent(cmp1, cmp2).
	 * @return array
	 */
	public static function getPersistentComponents()
	{
		return (array) NClassReflection::from(func_get_arg(0))
			->getAnnotation('persistent');
	}
Exemple #6
0
	/**
	 * Returns array of classes persistent parameters. They have public visibility and are non-static.
	 * This default implementation detects persistent parameters by annotation @persistent.
	 * @return array
	 */
	public static function getPersistentParams()
	{
		$rc = new NClassReflection(func_get_arg(0));
		$params = array();
		foreach ($rc->getProperties(ReflectionProperty::IS_PUBLIC) as $rp) {
			if (!$rp->isStatic() && $rp->hasAnnotation('persistent')) {
				$params[] = $rp->getName();
			}
		}
		return $params;
	}
Exemple #7
0
	/**
	 * Creates new instance using autowiring.
	 * @param  string  class
	 * @param  array   arguments
	 * @return object
	 * @throws InvalidArgumentException
	 */
	public function createInstance($class, array $args = array())
	{
		$rc = NClassReflection::from($class);
		if (!$rc->isInstantiable()) {
			throw new InvalidArgumentException("Class $class is not instantiable.");

		} elseif ($constructor = $rc->getConstructor()) {
			return $rc->newInstanceArgs(NDIHelpers::autowireArguments($constructor, $args, $this));

		} elseif ($args) {
			throw new InvalidArgumentException("Unable to pass arguments, class $class has no constructor.");
		}
		return new $class;
	}
	/**
	 * @param  string  presenter name
	 * @return string  class name
	 * @throws NInvalidPresenterException
	 */
	public function getPresenterClass(& $name)
	{
		if (isset($this->cache[$name])) {
			list($class, $name) = $this->cache[$name];
			return $class;
		}

		if (!is_string($name) || !NStrings::match($name, "#^[a-zA-Z\x7f-\xff][a-zA-Z0-9\x7f-\xff:]*$#")) {
			throw new NInvalidPresenterException("Presenter name must be alphanumeric string, '$name' is invalid.");
		}

		$class = $this->formatPresenterClass($name);

		if (!class_exists($class)) {
			// internal autoloading
			$file = $this->formatPresenterFile($name);
			if (is_file($file) && is_readable($file)) {
				NLimitedScope::load($file, TRUE);
			}

			if (!class_exists($class)) {
				throw new NInvalidPresenterException("Cannot load presenter '$name', class '$class' was not found in '$file'.");
			}
		}

		$reflection = new NClassReflection($class);
		$class = $reflection->getName();

		if (!$reflection->implementsInterface('IPresenter')) {
			throw new NInvalidPresenterException("Cannot load presenter '$name', class '$class' is not IPresenter implementor.");
		}

		if ($reflection->isAbstract()) {
			throw new NInvalidPresenterException("Cannot load presenter '$name', class '$class' is abstract.");
		}

		// canonicalize presenter name
		$realName = $this->unformatPresenterClass($class);
		if ($name !== $realName) {
			if ($this->caseSensitive) {
				throw new NInvalidPresenterException("Cannot load presenter '$name', case mismatch. Real name is '$realName'.");
			} else {
				$this->cache[$name] = array($class, $realName);
				$name = $realName;
			}
		} else {
			$this->cache[$name] = array($class, $realName);
		}

		return $class;
	}
	/**
	 * Returns annotations.
	 * @param  ReflectionClass|ReflectionMethod|ReflectionProperty
	 * @return array
	 */
	public static function getAll(Reflector $r)
	{
		if ($r instanceof ReflectionClass) {
			$type = $r->getName();
			$member = '';

		} elseif ($r instanceof ReflectionMethod) {
			$type = $r->getDeclaringClass()->getName();
			$member = $r->getName();

		} else {
			$type = $r->getDeclaringClass()->getName();
			$member = '$' . $r->getName();
		}

		if (!self::$useReflection) { // auto-expire cache
			$file = $r instanceof ReflectionClass ? $r->getFileName() : $r->getDeclaringClass()->getFileName(); // will be used later
			if ($file && isset(self::$timestamps[$file]) && self::$timestamps[$file] !== filemtime($file)) {
				unset(self::$cache[$type]);
			}
			unset(self::$timestamps[$file]);
		}

		if (isset(self::$cache[$type][$member])) { // is value cached?
			return self::$cache[$type][$member];
		}

		if (self::$useReflection === NULL) { // detects whether is reflection available
			self::$useReflection = (bool) NClassReflection::from(__CLASS__)->getDocComment();
		}

		if (self::$useReflection) {
			$annotations = self::parseComment($r->getDocComment());

		} else {
			if (!self::$cacheStorage) {
				// trigger_error('Set a cache storage for annotations parser via NAnnotationParser::setCacheStorage().', E_USER_WARNING);
				self::$cacheStorage = new NDevNullStorage;
			}
			$outerCache = new NCache(self::$cacheStorage, 'Nette.Reflection.Annotations');

			if (self::$cache === NULL) {
				self::$cache = (array) $outerCache->offsetGet('list');
				self::$timestamps = isset(self::$cache['*']) ? self::$cache['*'] : array();
			}

			if (!isset(self::$cache[$type]) && $file) {
				self::$cache['*'][$file] = filemtime($file);
				self::parseScript($file);
				$outerCache->save('list', self::$cache);
			}

			if (isset(self::$cache[$type][$member])) {
				$annotations = self::$cache[$type][$member];
			} else {
				$annotations = array();
			}
		}

		if ($r instanceof ReflectionMethod && !$r->isPrivate()
			&& (!$r->isConstructor() || !empty($annotations['inheritdoc'][0])))
		{
			try {
				$inherited = self::getAll(new ReflectionMethod(get_parent_class($type), $member));
			} catch (ReflectionException $e) {
				try {
					$inherited = self::getAll($r->getPrototype());
				} catch (ReflectionException $e) {
					$inherited = array();
				}
			}
			$annotations += array_intersect_key($inherited, array_flip(self::$inherited));
		}

		return self::$cache[$type][$member] = $annotations;
	}
Exemple #10
0
	private function getContainerProperty($name)
	{
		$prop = NClassReflection::from('NDIContainer')->getProperty($name);
		$prop->setAccessible(TRUE);
		return $prop->getValue($this->container);
	}
Exemple #11
0
	/**
	 * Checks object @serializationVersion label.
	 * @param  string
	 * @param  mixed
	 * @return bool
	 */
	private static function checkSerializationVersion($class, $value)
	{
		return NClassReflection::from($class)->getAnnotation('serializationVersion') === $value;
	}
Exemple #12
0
	/**
	 * Adding method to class.
	 * @param  string  method name
	 * @param  callable
	 * @return mixed
	 */
	public static function extensionMethod($name, $callback = NULL)
	{
		if (strpos($name, '::') === FALSE) {
			$class = get_called_class();
		} else {
			list($class, $name) = explode('::', $name);
		}
		$class = new NClassReflection($class);
		if ($callback === NULL) {
			return $class->getExtensionMethod($name);
		} else {
			$class->setExtensionMethod($name, $callback);
		}
	}
Exemple #13
0
	/**
	 * Starts and initializes session data.
	 * @throws InvalidStateException
	 * @return void
	 */
	public function start()
	{
		if (self::$started) {
			return;
		}

		$this->configure($this->options);

		NDebugger::tryError();
		session_start();
		if (NDebugger::catchError($e)) {
			@session_write_close(); // this is needed
			throw new InvalidStateException('session_start(): ' . $e->getMessage(), 0, $e);
		}

		self::$started = TRUE;

		/* structure:
			__NF: Counter, BrowserKey, Data, Meta, Time
				DATA: section->variable = data
				META: section->variable = Timestamp, Browser, Version
		*/

		unset($_SESSION['__NT'], $_SESSION['__NS'], $_SESSION['__NM']); // old unused structures

		// initialize structures
		$nf = & $_SESSION['__NF'];
		if (empty($nf)) { // new session
			$nf = array('C' => 0);
		} else {
			$nf['C']++;
		}

		// session regenerate every 30 minutes
		$nfTime = & $nf['Time'];
		$time = time();
		if ($time - $nfTime > self::REGENERATE_INTERVAL) {
			$nfTime = $time;
			$this->regenerationNeeded = TRUE;
		}

		// browser closing detection
		$browserKey = $this->request->getCookie('nette-browser');
		if (!$browserKey) {
			$browserKey = NStrings::random();
		}
		$browserClosed = !isset($nf['B']) || $nf['B'] !== $browserKey;
		$nf['B'] = $browserKey;

		// resend cookie
		$this->sendCookie();

		// process meta metadata
		if (isset($nf['META'])) {
			$now = time();
			// expire section variables
			foreach ($nf['META'] as $section => $metadata) {
				if (is_array($metadata)) {
					foreach ($metadata as $variable => $value) {
						if ((!empty($value['B']) && $browserClosed) || (!empty($value['T']) && $now > $value['T']) // whenBrowserIsClosed || Time
							|| ($variable !== '' && is_object($nf['DATA'][$section][$variable]) && (isset($value['V']) ? $value['V'] : NULL) // Version
								!== NClassReflection::from($nf['DATA'][$section][$variable])->getAnnotation('serializationVersion'))
						) {
							if ($variable === '') { // expire whole section
								unset($nf['META'][$section], $nf['DATA'][$section]);
								continue 2;
							}
							unset($nf['META'][$section][$variable], $nf['DATA'][$section][$variable]);
						}
					}
				}
			}
		}

		if ($this->regenerationNeeded) {
			session_regenerate_id(TRUE);
			$this->regenerationNeeded = FALSE;
		}

		register_shutdown_function(array($this, 'clean'));
	}
Exemple #14
0
	/**
	 * Starts and initializes session data.
	 * @throws InvalidStateException
	 * @return void
	 */
	public function start()
	{
		if (self::$started) {
			return;
		}

		$this->configure($this->options);

		$id = & $_COOKIE[session_name()];
		if (!is_string($id) || !preg_match('#^[0-9a-zA-Z,-]{22,128}\z#i', $id)) {
			unset($_COOKIE[session_name()]);
		}

		set_error_handler(create_function('$severity, $message', 'extract($GLOBALS[0]['.array_push($GLOBALS[0], array('error'=>& $error)).'-1], EXTR_REFS); // session_start returns FALSE on failure since PHP 5.3.0.
			if (($severity & error_reporting()) === $severity) {
				$error = $message;
				restore_error_handler();
			}
		'));
		session_start();
		if (!$error) {
			restore_error_handler();
		}
		$this->response->removeDuplicateCookies();
		if ($error && !session_id()) {
			@session_write_close(); // this is needed
			throw new InvalidStateException("session_start(): $error");
		}

		self::$started = TRUE;

		/* structure:
			__NF: Counter, BrowserKey, Data, Meta, Time
				DATA: section->variable = data
				META: section->variable = Timestamp, Browser, Version
		*/

		unset($_SESSION['__NT'], $_SESSION['__NS'], $_SESSION['__NM']); // old unused structures

		// initialize structures
		$nf = & $_SESSION['__NF'];
		@$nf['C']++;

		// regenerate empty session
		if (empty($nf['Time'])) {
			$nf['Time'] = time();
			$this->regenerated = TRUE;
		}

		// browser closing detection
		$browserKey = $this->request->getCookie('nette-browser');
		if (!$browserKey) {
			$browserKey = NStrings::random();
		}
		$browserClosed = !isset($nf['B']) || $nf['B'] !== $browserKey;
		$nf['B'] = $browserKey;

		// resend cookie
		$this->sendCookie();

		// process meta metadata
		if (isset($nf['META'])) {
			$now = time();
			// expire section variables
			foreach ($nf['META'] as $section => $metadata) {
				if (is_array($metadata)) {
					foreach ($metadata as $variable => $value) {
						if ((!empty($value['B']) && $browserClosed) || (!empty($value['T']) && $now > $value['T']) // whenBrowserIsClosed || Time
							|| (isset($nf['DATA'][$section][$variable]) && is_object($nf['DATA'][$section][$variable]) && (isset($value['V']) ? $value['V'] : NULL) // Version
								!= NClassReflection::from($nf['DATA'][$section][$variable])->getAnnotation('serializationVersion')) // intentionally !=
						) {
							if ($variable === '') { // expire whole section
								unset($nf['META'][$section], $nf['DATA'][$section]);
								continue 2;
							}
							unset($nf['META'][$section][$variable], $nf['DATA'][$section][$variable]);
						}
					}
				}
			}
		}

		if ($this->regenerated) {
			$this->regenerated = FALSE;
			$this->regenerateId();
		}

		register_shutdown_function(array($this, 'clean'));
	}
	/**
	 * Formats PHP code for class instantiating, function calling or property setting in PHP.
	 * @return string
	 * @internal
	 */
	public function formatStatement(NDIStatement $statement, $self = NULL)
	{
		$entity = $this->normalizeEntity($statement->entity);
		$arguments = (array) $statement->arguments;

		if (is_string($entity) && NStrings::contains($entity, '?')) { // PHP literal
			return $this->formatPhp($entity, $arguments, $self);

		} elseif ($service = $this->getServiceName($entity)) { // factory calling or service retrieving
			if ($this->definitions[$service]->shared) {
				if ($arguments) {
				throw new NServiceCreationException("Unable to call service '$entity'.");
			}
				return $this->formatPhp('$this->?', array($this->sanitizeName($service)));
			}
			$params = array();
			foreach ($this->definitions[$service]->parameters as $k => $v) {
				$params[] = preg_replace('#\w+$#', '\$$0', (is_int($k) ? $v : $k)) . (is_int($k) ? '' : ' = ' . NPhpHelpers::dump($v));
			}
			$rm = new ReflectionFunction(create_function(implode(', ', $params), ''));
			$arguments = NDIHelpers::autowireArguments($rm, $arguments, $this);
			return $this->formatPhp('$this->?(?*)', array('create' . ucfirst($service), $arguments), $self);

		} elseif ($entity === 'not') { // operator
			return $this->formatPhp('!?', array($arguments[0]));

		} elseif (is_string($entity)) { // class name
		    if ($constructor = NClassReflection::from($entity)->getConstructor()) {
				$this->addDependency($constructor->getFileName());
				$arguments = NDIHelpers::autowireArguments($constructor, $arguments, $this);
			} elseif ($arguments) {
				throw new NServiceCreationException("Unable to pass arguments, class $entity has no constructor.");
			}
			return $this->formatPhp("new $entity" . ($arguments ? '(?*)' : ''), array($arguments));

		} elseif (!NValidators::isList($entity) || count($entity) !== 2) {
			throw new InvalidStateException("Expected class, method or property, " . NPhpHelpers::dump($entity) . " given.");

		} elseif ($entity[0] === '') { // globalFunc
			return $this->formatPhp("$entity[1](?*)", array($arguments), $self);

		} elseif (NStrings::contains($entity[1], '$')) { // property setter
			if ($this->getServiceName($entity[0], $self)) {
				return $this->formatPhp('?->? = ?', array($entity[0], substr($entity[1], 1), $statement->arguments), $self);
			} else {
				return $this->formatPhp($entity[0] . '::$? = ?', array(substr($entity[1], 1), $statement->arguments), $self);
			}

		} elseif ($service = $this->getServiceName($entity[0], $self)) { // service method
			if ($this->definitions[$service]->class) {
				$arguments = $this->autowireArguments($this->definitions[$service]->class, $entity[1], $arguments);
			}
			return $this->formatPhp('?->?(?*)', array($entity[0], $entity[1], $arguments), $self);

		} else { // static method
			$arguments = $this->autowireArguments($entity[0], $entity[1], $arguments);
			return $this->formatPhp("$entity[0]::$entity[1](?*)", array($arguments), $self);
		}
	}