One Hat Cyber Team
Your IP:
216.73.216.30
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
proc
/
self
/
root
/
proc
/
thread-self
/
cwd
/
Edit File:
common.tar
src/Proxy/ProxyGenerator.php 0000644 00000115634 15107321605 0012167 0 ustar 00 <?php namespace Doctrine\Common\Proxy; use BackedEnum; use Doctrine\Common\Proxy\Exception\InvalidArgumentException; use Doctrine\Common\Proxy\Exception\UnexpectedValueException; use Doctrine\Common\Util\ClassUtils; use Doctrine\Persistence\Mapping\ClassMetadata; use ReflectionIntersectionType; use ReflectionMethod; use ReflectionNamedType; use ReflectionParameter; use ReflectionProperty; use ReflectionType; use ReflectionUnionType; use function array_combine; use function array_diff; use function array_key_exists; use function array_map; use function array_slice; use function array_unique; use function assert; use function bin2hex; use function call_user_func; use function chmod; use function class_exists; use function dirname; use function explode; use function file; use function file_put_contents; use function get_class; use function implode; use function in_array; use function interface_exists; use function is_callable; use function is_dir; use function is_scalar; use function is_string; use function is_writable; use function lcfirst; use function ltrim; use function method_exists; use function mkdir; use function preg_match; use function preg_match_all; use function preg_replace; use function preg_split; use function random_bytes; use function rename; use function rtrim; use function sprintf; use function str_replace; use function strpos; use function strrev; use function strtolower; use function strtr; use function substr; use function trim; use function var_export; use const DIRECTORY_SEPARATOR; use const PHP_VERSION_ID; use const PREG_SPLIT_DELIM_CAPTURE; /** * This factory is used to generate proxy classes. * It builds proxies from given parameters, a template and class metadata. */ class ProxyGenerator { /** * Used to match very simple id methods that don't need * to be decorated since the identifier is known. */ public const PATTERN_MATCH_ID_METHOD = <<<'EOT' ((?(DEFINE) (?<type>\\?[a-z_\x7f-\xff][\w\x7f-\xff]*(?:\\[a-z_\x7f-\xff][\w\x7f-\xff]*)*) (?<intersection_type>(?&type)\s*&\s*(?&type)) (?<union_type>(?:(?:\(\s*(?&intersection_type)\s*\))|(?&type))(?:\s*\|\s*(?:(?:\(\s*(?&intersection_type)\s*\))|(?&type)))+) )(?:public\s+)?(?:function\s+%s\s*\(\)\s*)\s*(?::\s*(?:(?&union_type)|(?&intersection_type)|(?:\??(?&type)))\s*)?{\s*return\s*\$this->%s;\s*})i EOT; /** * The namespace that contains all proxy classes. * * @var string */ private $proxyNamespace; /** * The directory that contains all proxy classes. * * @var string */ private $proxyDirectory; /** * Map of callables used to fill in placeholders set in the template. * * @var string[]|callable[] */ protected $placeholders = [ 'baseProxyInterface' => Proxy::class, 'additionalProperties' => '', ]; /** * Template used as a blueprint to generate proxies. * * @var string */ protected $proxyClassTemplate = '<?php namespace <namespace>; <enumUseStatements> /** * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE\'S PROXY GENERATOR */ class <proxyShortClassName> extends \<className> implements \<baseProxyInterface> { /** * @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with * three parameters, being respectively the proxy object to be initialized, the method that triggered the * initialization process and an array of ordered parameters that were passed to that method. * * @see \Doctrine\Common\Proxy\Proxy::__setInitializer */ public $__initializer__; /** * @var \Closure the callback responsible of loading properties that need to be copied in the cloned object * * @see \Doctrine\Common\Proxy\Proxy::__setCloner */ public $__cloner__; /** * @var boolean flag indicating if this object was already initialized * * @see \Doctrine\Persistence\Proxy::__isInitialized */ public $__isInitialized__ = false; /** * @var array<string, null> properties to be lazy loaded, indexed by property name */ public static $lazyPropertiesNames = <lazyPropertiesNames>; /** * @var array<string, mixed> default values of properties to be lazy loaded, with keys being the property names * * @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties */ public static $lazyPropertiesDefaults = <lazyPropertiesDefaults>; <additionalProperties> <constructorImpl> <magicGet> <magicSet> <magicIsset> <sleepImpl> <wakeupImpl> <cloneImpl> /** * Forces initialization of the proxy */ public function __load(): void { $this->__initializer__ && $this->__initializer__->__invoke($this, \'__load\', []); } /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ public function __isInitialized(): bool { return $this->__isInitialized__; } /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ public function __setInitialized($initialized): void { $this->__isInitialized__ = $initialized; } /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ public function __setInitializer(\Closure $initializer = null): void { $this->__initializer__ = $initializer; } /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ public function __getInitializer(): ?\Closure { return $this->__initializer__; } /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ public function __setCloner(\Closure $cloner = null): void { $this->__cloner__ = $cloner; } /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific cloning logic */ public function __getCloner(): ?\Closure { return $this->__cloner__; } /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic * @deprecated no longer in use - generated code now relies on internal components rather than generated public API * @static */ public function __getLazyProperties(): array { return self::$lazyPropertiesDefaults; } <methods> } '; /** * Initializes a new instance of the <tt>ProxyFactory</tt> class that is * connected to the given <tt>EntityManager</tt>. * * @param string $proxyDirectory The directory to use for the proxy classes. It must exist. * @param string $proxyNamespace The namespace to use for the proxy classes. * * @throws InvalidArgumentException */ public function __construct($proxyDirectory, $proxyNamespace) { if (! $proxyDirectory) { throw InvalidArgumentException::proxyDirectoryRequired(); } if (! $proxyNamespace) { throw InvalidArgumentException::proxyNamespaceRequired(); } $this->proxyDirectory = $proxyDirectory; $this->proxyNamespace = $proxyNamespace; } /** * Sets a placeholder to be replaced in the template. * * @param string $name * @param string|callable $placeholder * * @throws InvalidArgumentException */ public function setPlaceholder($name, $placeholder) { if (! is_string($placeholder) && ! is_callable($placeholder)) { throw InvalidArgumentException::invalidPlaceholder($name); } $this->placeholders[$name] = $placeholder; } /** * Sets the base template used to create proxy classes. * * @param string $proxyClassTemplate */ public function setProxyClassTemplate($proxyClassTemplate) { $this->proxyClassTemplate = (string) $proxyClassTemplate; } /** * Generates a proxy class file. * * @param ClassMetadata $class Metadata for the original class. * @param string|bool $fileName Filename (full path) for the generated class. If none is given, eval() is used. * * @throws InvalidArgumentException * @throws UnexpectedValueException */ public function generateProxyClass(ClassMetadata $class, $fileName = false) { $this->verifyClassCanBeProxied($class); preg_match_all('(<([a-zA-Z]+)>)', $this->proxyClassTemplate, $placeholderMatches); $placeholderMatches = array_combine($placeholderMatches[0], $placeholderMatches[1]); $placeholders = []; foreach ($placeholderMatches as $placeholder => $name) { $placeholders[$placeholder] = $this->placeholders[$name] ?? [$this, 'generate' . $name]; } foreach ($placeholders as & $placeholder) { if (! is_callable($placeholder)) { continue; } $placeholder = call_user_func($placeholder, $class); } $proxyCode = strtr($this->proxyClassTemplate, $placeholders); if (! $fileName) { $proxyClassName = $this->generateNamespace($class) . '\\' . $this->generateProxyShortClassName($class); if (! class_exists($proxyClassName)) { eval(substr($proxyCode, 5)); } return; } $parentDirectory = dirname($fileName); if (! is_dir($parentDirectory) && (@mkdir($parentDirectory, 0775, true) === false)) { throw UnexpectedValueException::proxyDirectoryNotWritable($this->proxyDirectory); } if (! is_writable($parentDirectory)) { throw UnexpectedValueException::proxyDirectoryNotWritable($this->proxyDirectory); } $tmpFileName = $fileName . '.' . bin2hex(random_bytes(12)); file_put_contents($tmpFileName, $proxyCode); @chmod($tmpFileName, 0664); rename($tmpFileName, $fileName); } /** @throws InvalidArgumentException */ private function verifyClassCanBeProxied(ClassMetadata $class) { if ($class->getReflectionClass()->isFinal()) { throw InvalidArgumentException::classMustNotBeFinal($class->getName()); } if ($class->getReflectionClass()->isAbstract()) { throw InvalidArgumentException::classMustNotBeAbstract($class->getName()); } if (PHP_VERSION_ID >= 80200 && $class->getReflectionClass()->isReadOnly()) { throw InvalidArgumentException::classMustNotBeReadOnly($class->getName()); } } /** * Generates the proxy short class name to be used in the template. * * @return string */ private function generateProxyShortClassName(ClassMetadata $class) { $proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace); $parts = explode('\\', strrev($proxyClassName), 2); return strrev($parts[0]); } /** * Generates the proxy namespace. * * @return string */ private function generateNamespace(ClassMetadata $class) { $proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace); $parts = explode('\\', strrev($proxyClassName), 2); return strrev($parts[1]); } /** * Enums must have a use statement when used as public property defaults. */ public function generateEnumUseStatements(ClassMetadata $class): string { if (PHP_VERSION_ID < 80100) { return "\n"; } $defaultProperties = $class->getReflectionClass()->getDefaultProperties(); $lazyLoadedPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); $enumClasses = []; foreach ($class->getReflectionClass()->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { $name = $property->getName(); if (! in_array($name, $lazyLoadedPublicProperties, true)) { continue; } if (array_key_exists($name, $defaultProperties) && $defaultProperties[$name] instanceof BackedEnum) { $enumClassNameParts = explode('\\', get_class($defaultProperties[$name])); $enumClasses[] = $enumClassNameParts[0]; } } return implode( "\n", array_map( static function ($className) { return 'use ' . $className . ';'; }, array_unique($enumClasses) ) ) . "\n"; } /** * Generates the original class name. * * @return string */ private function generateClassName(ClassMetadata $class) { return ltrim($class->getName(), '\\'); } /** * Generates the array representation of lazy loaded public properties and their default values. * * @return string */ private function generateLazyPropertiesNames(ClassMetadata $class) { $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); $values = []; foreach ($lazyPublicProperties as $name) { $values[$name] = null; } return var_export($values, true); } /** * Generates the array representation of lazy loaded public properties names. * * @return string */ private function generateLazyPropertiesDefaults(ClassMetadata $class) { return var_export($this->getLazyLoadedPublicProperties($class), true); } /** * Generates the constructor code (un-setting public lazy loaded properties, setting identifier field values). * * @return string */ private function generateConstructorImpl(ClassMetadata $class) { $constructorImpl = <<<'EOT' public function __construct(?\Closure $initializer = null, ?\Closure $cloner = null) { EOT; $toUnset = array_map(static function (string $name): string { return '$this->' . $name; }, $this->getLazyLoadedPublicPropertiesNames($class)); return $constructorImpl . ($toUnset === [] ? '' : ' unset(' . implode(', ', $toUnset) . ");\n") . <<<'EOT' $this->__initializer__ = $initializer; $this->__cloner__ = $cloner; } EOT; } /** * Generates the magic getter invoked when lazy loaded public properties are requested. * * @return string */ private function generateMagicGet(ClassMetadata $class) { $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); $reflectionClass = $class->getReflectionClass(); $hasParentGet = false; $returnReference = ''; $inheritDoc = ''; $name = '$name'; $parametersString = '$name'; $returnTypeHint = null; if ($reflectionClass->hasMethod('__get')) { $hasParentGet = true; $inheritDoc = '{@inheritDoc}'; $methodReflection = $reflectionClass->getMethod('__get'); if ($methodReflection->returnsReference()) { $returnReference = '& '; } $methodParameters = $methodReflection->getParameters(); $name = '$' . $methodParameters[0]->getName(); $parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name']); $returnTypeHint = $this->getMethodReturnType($methodReflection); } if (empty($lazyPublicProperties) && ! $hasParentGet) { return ''; } $magicGet = <<<EOT /** * $inheritDoc * @param string \$name */ public function {$returnReference}__get($parametersString)$returnTypeHint { EOT; if (! empty($lazyPublicProperties)) { $magicGet .= <<<'EOT' if (\array_key_exists($name, self::$lazyPropertiesNames)) { $this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]); EOT; if ($returnTypeHint === ': void') { $magicGet .= "\n return;"; } else { $magicGet .= "\n return \$this->\$name;"; } $magicGet .= <<<'EOT' } EOT; } if ($hasParentGet) { $magicGet .= <<<'EOT' $this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]); EOT; if ($returnTypeHint === ': void') { $magicGet .= <<<'EOT' parent::__get($name); return; EOT; } elseif ($returnTypeHint === ': never') { $magicGet .= <<<'EOT' parent::__get($name); EOT; } else { $magicGet .= <<<'EOT' return parent::__get($name); EOT; } } else { $magicGet .= sprintf(<<<EOT trigger_error(sprintf('Undefined property: %%s::$%%s', __CLASS__, %s), E_USER_NOTICE); EOT , $name); } return $magicGet . "\n }"; } /** * Generates the magic setter (currently unused). * * @return string */ private function generateMagicSet(ClassMetadata $class) { $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); $reflectionClass = $class->getReflectionClass(); $hasParentSet = false; $inheritDoc = ''; $parametersString = '$name, $value'; $returnTypeHint = null; if ($reflectionClass->hasMethod('__set')) { $hasParentSet = true; $inheritDoc = '{@inheritDoc}'; $methodReflection = $reflectionClass->getMethod('__set'); $parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name', 'value']); $returnTypeHint = $this->getMethodReturnType($methodReflection); } if (empty($lazyPublicProperties) && ! $hasParentSet) { return ''; } $magicSet = <<<EOT /** * $inheritDoc * @param string \$name * @param mixed \$value */ public function __set($parametersString)$returnTypeHint { EOT; if (! empty($lazyPublicProperties)) { $magicSet .= <<<'EOT' if (\array_key_exists($name, self::$lazyPropertiesNames)) { $this->__initializer__ && $this->__initializer__->__invoke($this, '__set', [$name, $value]); $this->$name = $value; return; } EOT; } if ($hasParentSet) { $magicSet .= <<<'EOT' $this->__initializer__ && $this->__initializer__->__invoke($this, '__set', [$name, $value]); EOT; if ($returnTypeHint === ': void') { $magicSet .= <<<'EOT' parent::__set($name, $value); return; EOT; } elseif ($returnTypeHint === ': never') { $magicSet .= <<<'EOT' parent::__set($name, $value); EOT; } else { $magicSet .= <<<'EOT' return parent::__set($name, $value); EOT; } } else { $magicSet .= ' $this->$name = $value;'; } return $magicSet . "\n }"; } /** * Generates the magic issetter invoked when lazy loaded public properties are checked against isset(). * * @return string */ private function generateMagicIsset(ClassMetadata $class) { $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); $hasParentIsset = $class->getReflectionClass()->hasMethod('__isset'); $parametersString = '$name'; $returnTypeHint = null; if ($hasParentIsset) { $methodReflection = $class->getReflectionClass()->getMethod('__isset'); $parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name']); $returnTypeHint = $this->getMethodReturnType($methodReflection); } if (empty($lazyPublicProperties) && ! $hasParentIsset) { return ''; } $inheritDoc = $hasParentIsset ? '{@inheritDoc}' : ''; $magicIsset = <<<EOT /** * $inheritDoc * @param string \$name * @return boolean */ public function __isset($parametersString)$returnTypeHint { EOT; if (! empty($lazyPublicProperties)) { $magicIsset .= <<<'EOT' if (\array_key_exists($name, self::$lazyPropertiesNames)) { $this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', [$name]); return isset($this->$name); } EOT; } if ($hasParentIsset) { $magicIsset .= <<<'EOT' $this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', [$name]); return parent::__isset($name); EOT; } else { $magicIsset .= ' return false;'; } return $magicIsset . "\n }"; } /** * Generates implementation for the `__sleep` method of proxies. * * @return string */ private function generateSleepImpl(ClassMetadata $class) { $reflectionClass = $class->getReflectionClass(); $hasParentSleep = $reflectionClass->hasMethod('__sleep'); $inheritDoc = $hasParentSleep ? '{@inheritDoc}' : ''; $returnTypeHint = $hasParentSleep ? $this->getMethodReturnType($reflectionClass->getMethod('__sleep')) : ''; $sleepImpl = <<<EOT /** * $inheritDoc * @return array */ public function __sleep()$returnTypeHint { EOT; if ($hasParentSleep) { return $sleepImpl . <<<'EOT' $properties = array_merge(['__isInitialized__'], parent::__sleep()); if ($this->__isInitialized__) { $properties = array_diff($properties, array_keys(self::$lazyPropertiesNames)); } return $properties; } EOT; } $allProperties = ['__isInitialized__']; foreach ($class->getReflectionClass()->getProperties() as $prop) { assert($prop instanceof ReflectionProperty); if ($prop->isStatic()) { continue; } $allProperties[] = $prop->isPrivate() ? "\0" . $prop->getDeclaringClass()->getName() . "\0" . $prop->getName() : $prop->getName(); } $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); $protectedProperties = array_diff($allProperties, $lazyPublicProperties); foreach ($allProperties as &$property) { $property = var_export($property, true); } foreach ($protectedProperties as &$property) { $property = var_export($property, true); } $allProperties = implode(', ', $allProperties); $protectedProperties = implode(', ', $protectedProperties); return $sleepImpl . <<<EOT if (\$this->__isInitialized__) { return [$allProperties]; } return [$protectedProperties]; } EOT; } /** * Generates implementation for the `__wakeup` method of proxies. * * @return string */ private function generateWakeupImpl(ClassMetadata $class) { $reflectionClass = $class->getReflectionClass(); $hasParentWakeup = $reflectionClass->hasMethod('__wakeup'); $unsetPublicProperties = []; foreach ($this->getLazyLoadedPublicPropertiesNames($class) as $lazyPublicProperty) { $unsetPublicProperties[] = '$this->' . $lazyPublicProperty; } $shortName = $this->generateProxyShortClassName($class); $inheritDoc = $hasParentWakeup ? '{@inheritDoc}' : ''; $returnTypeHint = $hasParentWakeup ? $this->getMethodReturnType($reflectionClass->getMethod('__wakeup')) : ''; $wakeupImpl = <<<EOT /** * $inheritDoc */ public function __wakeup()$returnTypeHint { if ( ! \$this->__isInitialized__) { \$this->__initializer__ = function ($shortName \$proxy) { \$proxy->__setInitializer(null); \$proxy->__setCloner(null); \$existingProperties = get_object_vars(\$proxy); foreach (\$proxy::\$lazyPropertiesDefaults as \$property => \$defaultValue) { if ( ! array_key_exists(\$property, \$existingProperties)) { \$proxy->\$property = \$defaultValue; } } }; EOT; if (! empty($unsetPublicProperties)) { $wakeupImpl .= "\n unset(" . implode(', ', $unsetPublicProperties) . ');'; } $wakeupImpl .= "\n }"; if ($hasParentWakeup) { $wakeupImpl .= "\n parent::__wakeup();"; } $wakeupImpl .= "\n }"; return $wakeupImpl; } /** * Generates implementation for the `__clone` method of proxies. * * @return string */ private function generateCloneImpl(ClassMetadata $class) { $reflectionClass = $class->getReflectionClass(); $hasParentClone = $reflectionClass->hasMethod('__clone'); $returnTypeHint = $hasParentClone ? $this->getMethodReturnType($reflectionClass->getMethod('__clone')) : ''; $inheritDoc = $hasParentClone ? '{@inheritDoc}' : ''; $callParentClone = $hasParentClone ? "\n parent::__clone();\n" : ''; return <<<EOT /** * $inheritDoc */ public function __clone()$returnTypeHint { \$this->__cloner__ && \$this->__cloner__->__invoke(\$this, '__clone', []); $callParentClone } EOT; } /** * Generates decorated methods by picking those available in the parent class. * * @return string */ private function generateMethods(ClassMetadata $class) { $methods = ''; $methodNames = []; $reflectionMethods = $class->getReflectionClass()->getMethods(ReflectionMethod::IS_PUBLIC); $skippedMethods = [ '__sleep' => true, '__clone' => true, '__wakeup' => true, '__get' => true, '__set' => true, '__isset' => true, ]; foreach ($reflectionMethods as $method) { $name = $method->getName(); if ( $method->isConstructor() || isset($skippedMethods[strtolower($name)]) || isset($methodNames[$name]) || $method->isFinal() || $method->isStatic() || ( ! $method->isPublic()) ) { continue; } $methodNames[$name] = true; $methods .= "\n /**\n" . " * {@inheritDoc}\n" . " */\n" . ' public function '; if ($method->returnsReference()) { $methods .= '&'; } $methods .= $name . '(' . $this->buildParametersString($method->getParameters()) . ')'; $methods .= $this->getMethodReturnType($method); $methods .= "\n" . ' {' . "\n"; if ($this->isShortIdentifierGetter($method, $class)) { $identifier = lcfirst(substr($name, 3)); $fieldType = $class->getTypeOfField($identifier); $cast = in_array($fieldType, ['integer', 'smallint']) ? '(int) ' : ''; $methods .= ' if ($this->__isInitialized__ === false) {' . "\n"; $methods .= ' '; $methods .= $this->shouldProxiedMethodReturn($method) ? 'return ' : ''; $methods .= $cast . ' parent::' . $method->getName() . "();\n"; $methods .= ' }' . "\n\n"; } $invokeParamsString = implode(', ', $this->getParameterNamesForInvoke($method->getParameters())); $callParamsString = implode(', ', $this->getParameterNamesForParentCall($method->getParameters())); $methods .= "\n \$this->__initializer__ " . '&& $this->__initializer__->__invoke($this, ' . var_export($name, true) . ', [' . $invokeParamsString . ']);' . "\n\n " . ($this->shouldProxiedMethodReturn($method) ? 'return ' : '') . 'parent::' . $name . '(' . $callParamsString . ');' . "\n" . ' }' . "\n"; } return $methods; } /** * Generates the Proxy file name. * * @param string $className * @param string $baseDirectory Optional base directory for proxy file name generation. * If not specified, the directory configured on the Configuration of the * EntityManager will be used by this factory. * @psalm-param class-string $className * * @return string */ public function getProxyFileName($className, $baseDirectory = null) { $baseDirectory = $baseDirectory ?: $this->proxyDirectory; return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . Proxy::MARKER . str_replace('\\', '', $className) . '.php'; } /** * Checks if the method is a short identifier getter. * * What does this mean? For proxy objects the identifier is already known, * however accessing the getter for this identifier usually triggers the * lazy loading, leading to a query that may not be necessary if only the * ID is interesting for the userland code (for example in views that * generate links to the entity, but do not display anything else). * * @param ReflectionMethod $method * * @return bool */ private function isShortIdentifierGetter($method, ClassMetadata $class) { $identifier = lcfirst(substr($method->getName(), 3)); $startLine = $method->getStartLine(); $endLine = $method->getEndLine(); $cheapCheck = $method->getNumberOfParameters() === 0 && substr($method->getName(), 0, 3) === 'get' && in_array($identifier, $class->getIdentifier(), true) && $class->hasField($identifier) && ($endLine - $startLine <= 4); if ($cheapCheck) { $code = file($method->getFileName()); $code = trim(implode(' ', array_slice($code, $startLine - 1, $endLine - $startLine + 1))); $pattern = sprintf(self::PATTERN_MATCH_ID_METHOD, $method->getName(), $identifier); if (preg_match($pattern, $code)) { return true; } } return false; } /** * Generates the list of public properties to be lazy loaded. * * @return array<int, string> */ private function getLazyLoadedPublicPropertiesNames(ClassMetadata $class): array { $properties = []; foreach ($class->getReflectionClass()->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { $name = $property->getName(); if ((! $class->hasField($name) && ! $class->hasAssociation($name)) || $class->isIdentifier($name)) { continue; } $properties[] = $name; } return $properties; } /** * Generates the list of default values of public properties. * * @return mixed[] */ private function getLazyLoadedPublicProperties(ClassMetadata $class) { $defaultProperties = $class->getReflectionClass()->getDefaultProperties(); $lazyLoadedPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); $defaultValues = []; foreach ($class->getReflectionClass()->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { $name = $property->getName(); if (! in_array($name, $lazyLoadedPublicProperties, true)) { continue; } if (array_key_exists($name, $defaultProperties)) { $defaultValues[$name] = $defaultProperties[$name]; } elseif (method_exists($property, 'getType')) { $propertyType = $property->getType(); if ($propertyType !== null && $propertyType->allowsNull()) { $defaultValues[$name] = null; } } } return $defaultValues; } /** * @param ReflectionParameter[] $parameters * @param string[] $renameParameters * * @return string */ private function buildParametersString(array $parameters, array $renameParameters = []) { $parameterDefinitions = []; $i = -1; foreach ($parameters as $param) { assert($param instanceof ReflectionParameter); $i++; $parameterDefinition = ''; $parameterType = $this->getParameterType($param); if ($parameterType !== null) { $parameterDefinition .= $parameterType . ' '; } if ($param->isPassedByReference()) { $parameterDefinition .= '&'; } if ($param->isVariadic()) { $parameterDefinition .= '...'; } $parameterDefinition .= '$' . ($renameParameters ? $renameParameters[$i] : $param->getName()); $parameterDefinition .= $this->getParameterDefaultValue($param); $parameterDefinitions[] = $parameterDefinition; } return implode(', ', $parameterDefinitions); } /** @return string|null */ private function getParameterType(ReflectionParameter $parameter) { if (! $parameter->hasType()) { return null; } $declaringFunction = $parameter->getDeclaringFunction(); assert($declaringFunction instanceof ReflectionMethod); return $this->formatType($parameter->getType(), $declaringFunction, $parameter); } /** @return string */ private function getParameterDefaultValue(ReflectionParameter $parameter) { if (! $parameter->isDefaultValueAvailable()) { return ''; } if (PHP_VERSION_ID < 80100 || is_scalar($parameter->getDefaultValue())) { return ' = ' . var_export($parameter->getDefaultValue(), true); } $value = rtrim(substr(explode('$' . $parameter->getName() . ' = ', (string) $parameter, 2)[1], 0, -2)); if (strpos($value, '\\') !== false || strpos($value, '::') !== false) { $value = preg_split("/('(?:[^'\\\\]*+(?:\\\\.)*+)*+')/", $value, -1, PREG_SPLIT_DELIM_CAPTURE); foreach ($value as $i => $part) { if ($i % 2 === 0) { $value[$i] = preg_replace('/(?<![a-zA-Z0-9_\x7f-\xff\\\\])[a-zA-Z0-9_\x7f-\xff]++(?:\\\\[a-zA-Z0-9_\x7f-\xff]++|::)++/', '\\\\\0', $part); } } $value = implode('', $value); } return ' = ' . $value; } /** * @param ReflectionParameter[] $parameters * * @return string[] */ private function getParameterNamesForInvoke(array $parameters) { return array_map( static function (ReflectionParameter $parameter) { return '$' . $parameter->getName(); }, $parameters ); } /** * @param ReflectionParameter[] $parameters * * @return string[] */ private function getParameterNamesForParentCall(array $parameters) { return array_map( static function (ReflectionParameter $parameter) { $name = ''; if ($parameter->isVariadic()) { $name .= '...'; } $name .= '$' . $parameter->getName(); return $name; }, $parameters ); } /** @return string */ private function getMethodReturnType(ReflectionMethod $method) { if (! $method->hasReturnType()) { return ''; } return ': ' . $this->formatType($method->getReturnType(), $method); } /** @return bool */ private function shouldProxiedMethodReturn(ReflectionMethod $method) { if (! $method->hasReturnType()) { return true; } return ! in_array( strtolower($this->formatType($method->getReturnType(), $method)), ['void', 'never'], true ); } /** @return string */ private function formatType( ReflectionType $type, ReflectionMethod $method, ?ReflectionParameter $parameter = null ) { if ($type instanceof ReflectionUnionType) { return implode('|', array_map( function (ReflectionType $unionedType) use ($method, $parameter) { if ($unionedType instanceof ReflectionIntersectionType) { return '(' . $this->formatType($unionedType, $method, $parameter) . ')'; } return $this->formatType($unionedType, $method, $parameter); }, $type->getTypes() )); } if ($type instanceof ReflectionIntersectionType) { return implode('&', array_map( function (ReflectionType $intersectedType) use ($method, $parameter) { return $this->formatType($intersectedType, $method, $parameter); }, $type->getTypes() )); } assert($type instanceof ReflectionNamedType); $name = $type->getName(); $nameLower = strtolower($name); if ($nameLower === 'static') { $name = 'static'; } if ($nameLower === 'self') { $name = $method->getDeclaringClass()->getName(); } if ($nameLower === 'parent') { $name = $method->getDeclaringClass()->getParentClass()->getName(); } if (! $type->isBuiltin() && ! class_exists($name) && ! interface_exists($name) && $name !== 'static') { if ($parameter !== null) { throw UnexpectedValueException::invalidParameterTypeHint( $method->getDeclaringClass()->getName(), $method->getName(), $parameter->getName() ); } throw UnexpectedValueException::invalidReturnTypeHint( $method->getDeclaringClass()->getName(), $method->getName() ); } if (! $type->isBuiltin() && $name !== 'static') { $name = '\\' . $name; } if ( $type->allowsNull() && ! in_array($name, ['mixed', 'null'], true) && ($parameter === null || ! $parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== null) ) { $name = '?' . $name; } return $name; } } src/Proxy/AbstractProxyFactory.php 0000644 00000017274 15107321606 0013336 0 ustar 00 <?php namespace Doctrine\Common\Proxy; use Doctrine\Common\Proxy\Exception\InvalidArgumentException; use Doctrine\Common\Proxy\Exception\OutOfBoundsException; use Doctrine\Common\Util\ClassUtils; use Doctrine\Persistence\Mapping\ClassMetadata; use Doctrine\Persistence\Mapping\ClassMetadataFactory; use function class_exists; use function file_exists; use function filemtime; use function in_array; /** * Abstract factory for proxy objects. */ abstract class AbstractProxyFactory { /** * Never autogenerate a proxy and rely that it was generated by some * process before deployment. */ public const AUTOGENERATE_NEVER = 0; /** * Always generates a new proxy in every request. * * This is only sane during development. */ public const AUTOGENERATE_ALWAYS = 1; /** * Autogenerate the proxy class when the proxy file does not exist. * * This strategy causes a file_exists() call whenever any proxy is used the * first time in a request. */ public const AUTOGENERATE_FILE_NOT_EXISTS = 2; /** * Generate the proxy classes using eval(). * * This strategy is only sane for development, and even then it gives me * the creeps a little. */ public const AUTOGENERATE_EVAL = 3; /** * Autogenerate the proxy class when the proxy file does not exist or * when the proxied file changed. * * This strategy causes a file_exists() call whenever any proxy is used the * first time in a request. When the proxied file is changed, the proxy will * be updated. */ public const AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED = 4; private const AUTOGENERATE_MODES = [ self::AUTOGENERATE_NEVER, self::AUTOGENERATE_ALWAYS, self::AUTOGENERATE_FILE_NOT_EXISTS, self::AUTOGENERATE_EVAL, self::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED, ]; /** @var ClassMetadataFactory */ private $metadataFactory; /** @var ProxyGenerator the proxy generator responsible for creating the proxy classes/files. */ private $proxyGenerator; /** @var int Whether to automatically (re)generate proxy classes. */ private $autoGenerate; /** @var ProxyDefinition[] */ private $definitions = []; /** * @param bool|int $autoGenerate * * @throws InvalidArgumentException When auto generate mode is not valid. */ public function __construct(ProxyGenerator $proxyGenerator, ClassMetadataFactory $metadataFactory, $autoGenerate) { $this->proxyGenerator = $proxyGenerator; $this->metadataFactory = $metadataFactory; $this->autoGenerate = (int) $autoGenerate; if (! in_array($this->autoGenerate, self::AUTOGENERATE_MODES, true)) { throw InvalidArgumentException::invalidAutoGenerateMode($autoGenerate); } } /** * Gets a reference proxy instance for the entity of the given type and identified by * the given identifier. * * @param string $className * @param array<mixed> $identifier * * @return Proxy * * @throws OutOfBoundsException */ public function getProxy($className, array $identifier) { $definition = $this->definitions[$className] ?? $this->getProxyDefinition($className); $fqcn = $definition->proxyClassName; $proxy = new $fqcn($definition->initializer, $definition->cloner); foreach ($definition->identifierFields as $idField) { if (! isset($identifier[$idField])) { throw OutOfBoundsException::missingPrimaryKeyValue($className, $idField); } $definition->reflectionFields[$idField]->setValue($proxy, $identifier[$idField]); } return $proxy; } /** * Generates proxy classes for all given classes. * * @param ClassMetadata[] $classes The classes (ClassMetadata instances) * for which to generate proxies. * @param string $proxyDir The target directory of the proxy classes. If not specified, the * directory configured on the Configuration of the EntityManager used * by this factory is used. * * @return int Number of generated proxies. */ public function generateProxyClasses(array $classes, $proxyDir = null) { $generated = 0; foreach ($classes as $class) { if ($this->skipClass($class)) { continue; } $proxyFileName = $this->proxyGenerator->getProxyFileName($class->getName(), $proxyDir); $this->proxyGenerator->generateProxyClass($class, $proxyFileName); $generated += 1; } return $generated; } /** * Reset initialization/cloning logic for an un-initialized proxy * * @return Proxy * * @throws InvalidArgumentException */ public function resetUninitializedProxy(Proxy $proxy) { if ($proxy->__isInitialized()) { throw InvalidArgumentException::unitializedProxyExpected($proxy); } $className = ClassUtils::getClass($proxy); $definition = $this->definitions[$className] ?? $this->getProxyDefinition($className); $proxy->__setInitializer($definition->initializer); $proxy->__setCloner($definition->cloner); return $proxy; } /** * Get a proxy definition for the given class name. * * @param string $className * @psalm-param class-string $className * * @return ProxyDefinition */ private function getProxyDefinition($className) { $classMetadata = $this->metadataFactory->getMetadataFor($className); $className = $classMetadata->getName(); // aliases and case sensitivity $this->definitions[$className] = $this->createProxyDefinition($className); $proxyClassName = $this->definitions[$className]->proxyClassName; if (! class_exists($proxyClassName, false)) { $fileName = $this->proxyGenerator->getProxyFileName($className); switch ($this->autoGenerate) { case self::AUTOGENERATE_NEVER: require $fileName; break; case self::AUTOGENERATE_FILE_NOT_EXISTS: if (! file_exists($fileName)) { $this->proxyGenerator->generateProxyClass($classMetadata, $fileName); } require $fileName; break; case self::AUTOGENERATE_ALWAYS: $this->proxyGenerator->generateProxyClass($classMetadata, $fileName); require $fileName; break; case self::AUTOGENERATE_EVAL: $this->proxyGenerator->generateProxyClass($classMetadata, false); break; case self::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED: if (! file_exists($fileName) || filemtime($fileName) < filemtime($classMetadata->getReflectionClass()->getFileName())) { $this->proxyGenerator->generateProxyClass($classMetadata, $fileName); } require $fileName; break; } } return $this->definitions[$className]; } /** * Determine if this class should be skipped during proxy generation. * * @return bool */ abstract protected function skipClass(ClassMetadata $metadata); /** * @param string $className * @psalm-param class-string $className * * @return ProxyDefinition */ abstract protected function createProxyDefinition($className); } src/Proxy/Exception/ProxyException.php 0000644 00000000261 15107321606 0014123 0 ustar 00 <?php namespace Doctrine\Common\Proxy\Exception; /** * Base exception interface for proxy exceptions. * * @link www.doctrine-project.org */ interface ProxyException { } src/Proxy/Exception/UnexpectedValueException.php 0000644 00000003324 15107321607 0016107 0 ustar 00 <?php namespace Doctrine\Common\Proxy\Exception; use Throwable; use UnexpectedValueException as BaseUnexpectedValueException; use function sprintf; /** * Proxy Unexpected Value Exception. * * @link www.doctrine-project.org */ class UnexpectedValueException extends BaseUnexpectedValueException implements ProxyException { /** * @param string $proxyDirectory * * @return self */ public static function proxyDirectoryNotWritable($proxyDirectory) { return new self(sprintf('Your proxy directory "%s" must be writable', $proxyDirectory)); } /** * @param string $className * @param string $methodName * @param string $parameterName * @psalm-param class-string $className * * @return self */ public static function invalidParameterTypeHint( $className, $methodName, $parameterName, ?Throwable $previous = null ) { return new self( sprintf( 'The type hint of parameter "%s" in method "%s" in class "%s" is invalid.', $parameterName, $methodName, $className ), 0, $previous ); } /** * @param string $className * @param string $methodName * @psalm-param class-string $className * * @return self */ public static function invalidReturnTypeHint($className, $methodName, ?Throwable $previous = null) { return new self( sprintf( 'The return type of method "%s" in class "%s" is invalid.', $methodName, $className ), 0, $previous ); } } src/Proxy/Exception/OutOfBoundsException.php 0000644 00000001172 15107321607 0015214 0 ustar 00 <?php namespace Doctrine\Common\Proxy\Exception; use OutOfBoundsException as BaseOutOfBoundsException; use function sprintf; /** * Proxy Invalid Argument Exception. * * @link www.doctrine-project.org */ class OutOfBoundsException extends BaseOutOfBoundsException implements ProxyException { /** * @param string $className * @param string $idField * @psalm-param class-string $className * * @return self */ public static function missingPrimaryKeyValue($className, $idField) { return new self(sprintf('Missing value for primary key %s on %s', $idField, $className)); } } src/Proxy/Exception/InvalidArgumentException.php 0000644 00000005662 15107321607 0016106 0 ustar 00 <?php namespace Doctrine\Common\Proxy\Exception; use Doctrine\Persistence\Proxy; use InvalidArgumentException as BaseInvalidArgumentException; use function get_class; use function gettype; use function is_object; use function sprintf; /** * Proxy Invalid Argument Exception. * * @link www.doctrine-project.org */ class InvalidArgumentException extends BaseInvalidArgumentException implements ProxyException { /** @return self */ public static function proxyDirectoryRequired() { return new self('You must configure a proxy directory. See docs for details'); } /** * @param string $className * @param string $proxyNamespace * @psalm-param class-string $className * * @return self */ public static function notProxyClass($className, $proxyNamespace) { return new self(sprintf('The class "%s" is not part of the proxy namespace "%s"', $className, $proxyNamespace)); } /** * @param string $name * * @return self */ public static function invalidPlaceholder($name) { return new self(sprintf('Provided placeholder for "%s" must be either a string or a valid callable', $name)); } /** @return self */ public static function proxyNamespaceRequired() { return new self('You must configure a proxy namespace'); } /** @return self */ public static function unitializedProxyExpected(Proxy $proxy) { return new self(sprintf('Provided proxy of type "%s" must not be initialized.', get_class($proxy))); } /** * @param mixed $callback * * @return self */ public static function invalidClassNotFoundCallback($callback) { $type = is_object($callback) ? get_class($callback) : gettype($callback); return new self(sprintf('Invalid \$notFoundCallback given: must be a callable, "%s" given', $type)); } /** * @param string $className * @psalm-param class-string $className * * @return self */ public static function classMustNotBeAbstract($className) { return new self(sprintf('Unable to create a proxy for an abstract class "%s".', $className)); } /** * @param string $className * @psalm-param class-string $className * * @return self */ public static function classMustNotBeFinal($className) { return new self(sprintf('Unable to create a proxy for a final class "%s".', $className)); } /** * @param string $className * @psalm-param class-string $className * * @return self */ public static function classMustNotBeReadOnly($className) { return new self(sprintf('Unable to create a proxy for a readonly class "%s".', $className)); } /** @param mixed $value */ public static function invalidAutoGenerateMode($value): self { return new self(sprintf('Invalid auto generate mode "%s" given.', $value)); } } src/Proxy/ProxyDefinition.php 0000644 00000002160 15107321607 0012320 0 ustar 00 <?php namespace Doctrine\Common\Proxy; use ReflectionProperty; /** * Definition structure how to create a proxy. */ class ProxyDefinition { /** @var string */ public $proxyClassName; /** @var array<string> */ public $identifierFields; /** @var ReflectionProperty[] */ public $reflectionFields; /** @var callable */ public $initializer; /** @var callable */ public $cloner; /** * @param string $proxyClassName * @param array<string> $identifierFields * @param array<string, ReflectionProperty> $reflectionFields * @param callable $initializer * @param callable $cloner */ public function __construct($proxyClassName, array $identifierFields, array $reflectionFields, $initializer, $cloner) { $this->proxyClassName = $proxyClassName; $this->identifierFields = $identifierFields; $this->reflectionFields = $reflectionFields; $this->initializer = $initializer; $this->cloner = $cloner; } } src/Proxy/Proxy.php 0000644 00000003407 15107321607 0010314 0 ustar 00 <?php namespace Doctrine\Common\Proxy; use Closure; use Doctrine\Persistence\Proxy as BaseProxy; /** * Interface for proxy classes. * * @template T of object * @template-extends BaseProxy<T> */ interface Proxy extends BaseProxy { /** * Marks the proxy as initialized or not. * * @param bool $initialized * * @return void */ public function __setInitialized($initialized); /** * Sets the initializer callback to be used when initializing the proxy. That * initializer should accept 3 parameters: $proxy, $method and $params. Those * are respectively the proxy object that is being initialized, the method name * that triggered initialization and the parameters passed to that method. * * @return void */ public function __setInitializer(?Closure $initializer = null); /** * Retrieves the initializer callback used to initialize the proxy. * * @see __setInitializer * * @return Closure|null */ public function __getInitializer(); /** * Sets the callback to be used when cloning the proxy. That initializer should accept * a single parameter, which is the cloned proxy instance itself. * * @return void */ public function __setCloner(?Closure $cloner = null); /** * Retrieves the callback to be used when cloning the proxy. * * @see __setCloner * * @return Closure|null */ public function __getCloner(); /** * Retrieves the list of lazy loaded properties for a given proxy * * @return array<string, mixed> Keys are the property names, and values are the default values * for those properties. */ public function __getLazyProperties(); } src/Proxy/Autoloader.php 0000644 00000005617 15107321610 0011271 0 ustar 00 <?php namespace Doctrine\Common\Proxy; use Closure; use Doctrine\Common\Proxy\Exception\InvalidArgumentException; use function call_user_func; use function file_exists; use function is_callable; use function ltrim; use function spl_autoload_register; use function str_replace; use function strlen; use function strpos; use function substr; use const DIRECTORY_SEPARATOR; /** * Special Autoloader for Proxy classes, which are not PSR-0 compliant. * * @internal */ class Autoloader { /** * Resolves proxy class name to a filename based on the following pattern. * * 1. Remove Proxy namespace from class name. * 2. Remove namespace separators from remaining class name. * 3. Return PHP filename from proxy-dir with the result from 2. * * @param string $proxyDir * @param string $proxyNamespace * @param string $className * @psalm-param class-string $className * * @return string * * @throws InvalidArgumentException */ public static function resolveFile($proxyDir, $proxyNamespace, $className) { if (strpos($className, $proxyNamespace) !== 0) { throw InvalidArgumentException::notProxyClass($className, $proxyNamespace); } // remove proxy namespace from class name $classNameRelativeToProxyNamespace = substr($className, strlen($proxyNamespace)); // remove namespace separators from remaining class name $fileName = str_replace('\\', '', $classNameRelativeToProxyNamespace); return $proxyDir . DIRECTORY_SEPARATOR . $fileName . '.php'; } /** * Registers and returns autoloader callback for the given proxy dir and namespace. * * @param string $proxyDir * @param string $proxyNamespace * @param callable|null $notFoundCallback Invoked when the proxy file is not found. * * @return Closure * * @throws InvalidArgumentException */ public static function register($proxyDir, $proxyNamespace, $notFoundCallback = null) { $proxyNamespace = ltrim($proxyNamespace, '\\'); if ($notFoundCallback !== null && ! is_callable($notFoundCallback)) { throw InvalidArgumentException::invalidClassNotFoundCallback($notFoundCallback); } $autoloader = static function ($className) use ($proxyDir, $proxyNamespace, $notFoundCallback) { if ($proxyNamespace === '') { return; } if (strpos($className, $proxyNamespace) !== 0) { return; } $file = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className); if ($notFoundCallback && ! file_exists($file)) { call_user_func($notFoundCallback, $proxyDir, $proxyNamespace, $className); } require $file; }; spl_autoload_register($autoloader); return $autoloader; } } src/ClassLoader.php 0000644 00000020442 15107321610 0010236 0 ustar 00 <?php namespace Doctrine\Common; use function class_exists; use function interface_exists; use function is_array; use function is_file; use function reset; use function spl_autoload_functions; use function spl_autoload_register; use function spl_autoload_unregister; use function str_replace; use function stream_resolve_include_path; use function strpos; use function trait_exists; use function trigger_error; use const DIRECTORY_SEPARATOR; use const E_USER_DEPRECATED; @trigger_error(ClassLoader::class . ' is deprecated.', E_USER_DEPRECATED); /** * A <tt>ClassLoader</tt> is an autoloader for class files that can be * installed on the SPL autoload stack. It is a class loader that either loads only classes * of a specific namespace or all namespaces and it is suitable for working together * with other autoloaders in the SPL autoload stack. * * If no include path is configured through the constructor or {@link setIncludePath}, a ClassLoader * relies on the PHP <code>include_path</code>. * * @deprecated The ClassLoader is deprecated and will be removed in version 4.0 of doctrine/common. */ class ClassLoader { /** * PHP file extension. * * @var string */ protected $fileExtension = '.php'; /** * Current namespace. * * @var string|null */ protected $namespace; /** * Current include path. * * @var string|null */ protected $includePath; /** * PHP namespace separator. * * @var string */ protected $namespaceSeparator = '\\'; /** * Creates a new <tt>ClassLoader</tt> that loads classes of the * specified namespace from the specified include path. * * If no include path is given, the ClassLoader relies on the PHP include_path. * If neither a namespace nor an include path is given, the ClassLoader will * be responsible for loading all classes, thereby relying on the PHP include_path. * * @param string|null $ns The namespace of the classes to load. * @param string|null $includePath The base include path to use. */ public function __construct($ns = null, $includePath = null) { $this->namespace = $ns; $this->includePath = $includePath; } /** * Sets the namespace separator used by classes in the namespace of this ClassLoader. * * @param string $sep The separator to use. * * @return void */ public function setNamespaceSeparator($sep) { $this->namespaceSeparator = $sep; } /** * Gets the namespace separator used by classes in the namespace of this ClassLoader. * * @return string */ public function getNamespaceSeparator() { return $this->namespaceSeparator; } /** * Sets the base include path for all class files in the namespace of this ClassLoader. * * @param string|null $includePath * * @return void */ public function setIncludePath($includePath) { $this->includePath = $includePath; } /** * Gets the base include path for all class files in the namespace of this ClassLoader. * * @return string|null */ public function getIncludePath() { return $this->includePath; } /** * Sets the file extension of class files in the namespace of this ClassLoader. * * @param string $fileExtension * * @return void */ public function setFileExtension($fileExtension) { $this->fileExtension = $fileExtension; } /** * Gets the file extension of class files in the namespace of this ClassLoader. * * @return string */ public function getFileExtension() { return $this->fileExtension; } /** * Registers this ClassLoader on the SPL autoload stack. * * @return void */ public function register() { spl_autoload_register([$this, 'loadClass']); } /** * Removes this ClassLoader from the SPL autoload stack. * * @return void */ public function unregister() { spl_autoload_unregister([$this, 'loadClass']); } /** * Loads the given class or interface. * * @param string $className The name of the class to load. * @psalm-param class-string $className * * @return bool TRUE if the class has been successfully loaded, FALSE otherwise. */ public function loadClass($className) { if (self::typeExists($className)) { return true; } if (! $this->canLoadClass($className)) { return false; } require($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '') . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension; return self::typeExists($className); } /** * Asks this ClassLoader whether it can potentially load the class (file) with * the given name. * * @param string $className The fully-qualified name of the class. * @psalm-param class-string $className * * @return bool TRUE if this ClassLoader can load the class, FALSE otherwise. */ public function canLoadClass($className) { if ($this->namespace !== null && strpos($className, $this->namespace . $this->namespaceSeparator) !== 0) { return false; } $file = str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension; if ($this->includePath !== null) { return is_file($this->includePath . DIRECTORY_SEPARATOR . $file); } return stream_resolve_include_path($file) !== false; } /** * Checks whether a class with a given name exists. A class "exists" if it is either * already defined in the current request or if there is an autoloader on the SPL * autoload stack that is a) responsible for the class in question and b) is able to * load a class file in which the class definition resides. * * If the class is not already defined, each autoloader in the SPL autoload stack * is asked whether it is able to tell if the class exists. If the autoloader is * a <tt>ClassLoader</tt>, {@link canLoadClass} is used, otherwise the autoload * function of the autoloader is invoked and expected to return a value that * evaluates to TRUE if the class (file) exists. As soon as one autoloader reports * that the class exists, TRUE is returned. * * Note that, depending on what kinds of autoloaders are installed on the SPL * autoload stack, the class (file) might already be loaded as a result of checking * for its existence. This is not the case with a <tt>ClassLoader</tt>, who separates * these responsibilities. * * @param string $className The fully-qualified name of the class. * @psalm-param class-string $className * * @return bool TRUE if the class exists as per the definition given above, FALSE otherwise. */ public static function classExists($className) { return self::typeExists($className, true); } /** * Gets the <tt>ClassLoader</tt> from the SPL autoload stack that is responsible * for (and is able to load) the class with the given name. * * @param string $className The name of the class. * @psalm-param class-string $className * * @return ClassLoader|null The <tt>ClassLoader</tt> for the class or NULL if no such <tt>ClassLoader</tt> exists. */ public static function getClassLoader($className) { foreach (spl_autoload_functions() as $loader) { if (! is_array($loader)) { continue; } $classLoader = reset($loader); if ($classLoader instanceof ClassLoader && $classLoader->canLoadClass($className)) { return $classLoader; } } return null; } /** * Checks whether a given type exists * * @param string $type * @param bool $autoload * * @return bool */ private static function typeExists($type, $autoload = false) { return class_exists($type, $autoload) || interface_exists($type, $autoload) || trait_exists($type, $autoload); } } src/Util/ClassUtils.php 0000644 00000005310 15107321610 0011042 0 ustar 00 <?php namespace Doctrine\Common\Util; use Doctrine\Persistence\Proxy; use ReflectionClass; use function get_class; use function get_parent_class; use function ltrim; use function rtrim; use function strrpos; use function substr; /** * Class and reflection related functionality for objects that * might or not be proxy objects at the moment. */ class ClassUtils { /** * Gets the real class name of a class name that could be a proxy. * * @param string $className * @psalm-param class-string<Proxy<T>>|class-string<T> $className * * @return string * @psalm-return class-string<T> * * @template T of object */ public static function getRealClass($className) { $pos = strrpos($className, '\\' . Proxy::MARKER . '\\'); if ($pos === false) { /** @psalm-var class-string<T> */ return $className; } return substr($className, $pos + Proxy::MARKER_LENGTH + 2); } /** * Gets the real class name of an object (even if its a proxy). * * @param object $object * @psalm-param Proxy<T>|T $object * * @return string * @psalm-return class-string<T> * * @template T of object */ public static function getClass($object) { return self::getRealClass(get_class($object)); } /** * Gets the real parent class name of a class or object. * * @param string $className * @psalm-param class-string $className * * @return string * @psalm-return class-string */ public static function getParentClass($className) { return get_parent_class(self::getRealClass($className)); } /** * Creates a new reflection class. * * @param string $className * @psalm-param class-string $className * * @return ReflectionClass */ public static function newReflectionClass($className) { return new ReflectionClass(self::getRealClass($className)); } /** * Creates a new reflection object. * * @param object $object * * @return ReflectionClass */ public static function newReflectionObject($object) { return self::newReflectionClass(self::getClass($object)); } /** * Given a class name and a proxy namespace returns the proxy name. * * @param string $className * @param string $proxyNamespace * @psalm-param class-string $className * * @return string * @psalm-return class-string */ public static function generateProxyClassName($className, $proxyNamespace) { return rtrim($proxyNamespace, '\\') . '\\' . Proxy::MARKER . '\\' . ltrim($className, '\\'); } } src/Util/Debug.php 0000644 00000011151 15107321610 0010002 0 ustar 00 <?php namespace Doctrine\Common\Util; use ArrayIterator; use ArrayObject; use DateTimeInterface; use Doctrine\Common\Collections\Collection; use Doctrine\Persistence\Proxy; use stdClass; use function array_keys; use function count; use function end; use function explode; use function extension_loaded; use function get_class; use function html_entity_decode; use function ini_get; use function ini_set; use function is_array; use function is_object; use function method_exists; use function ob_end_clean; use function ob_get_contents; use function ob_start; use function spl_object_hash; use function strip_tags; use function var_dump; /** * Static class containing most used debug methods. * * @deprecated The Debug class is deprecated, please use symfony/var-dumper instead. * * @link www.doctrine-project.org */ final class Debug { /** * Private constructor (prevents instantiation). */ private function __construct() { } /** * Prints a dump of the public, protected and private properties of $var. * * @link https://xdebug.org/ * * @param mixed $var The variable to dump. * @param int $maxDepth The maximum nesting level for object properties. * @param bool $stripTags Whether output should strip HTML tags. * @param bool $echo Send the dumped value to the output buffer * * @return string */ public static function dump($var, $maxDepth = 2, $stripTags = true, $echo = true) { $html = ini_get('html_errors'); if ($html !== true) { ini_set('html_errors', 'on'); } if (extension_loaded('xdebug')) { ini_set('xdebug.var_display_max_depth', $maxDepth); } $var = self::export($var, $maxDepth); ob_start(); var_dump($var); $dump = ob_get_contents(); ob_end_clean(); $dumpText = ($stripTags ? strip_tags(html_entity_decode($dump)) : $dump); ini_set('html_errors', $html); if ($echo) { echo $dumpText; } return $dumpText; } /** * @param mixed $var * @param int $maxDepth * * @return mixed */ public static function export($var, $maxDepth) { $return = null; $isObj = is_object($var); if ($var instanceof Collection) { $var = $var->toArray(); } if (! $maxDepth) { return is_object($var) ? get_class($var) : (is_array($var) ? 'Array(' . count($var) . ')' : $var); } if (is_array($var)) { $return = []; foreach ($var as $k => $v) { $return[$k] = self::export($v, $maxDepth - 1); } return $return; } if (! $isObj) { return $var; } $return = new stdClass(); if ($var instanceof DateTimeInterface) { $return->__CLASS__ = get_class($var); $return->date = $var->format('c'); $return->timezone = $var->getTimezone()->getName(); return $return; } $return->__CLASS__ = ClassUtils::getClass($var); if ($var instanceof Proxy) { $return->__IS_PROXY__ = true; $return->__PROXY_INITIALIZED__ = $var->__isInitialized(); } if ($var instanceof ArrayObject || $var instanceof ArrayIterator) { $return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1); } return self::fillReturnWithClassAttributes($var, $return, $maxDepth); } /** * Fill the $return variable with class attributes * Based on obj2array function from {@see https://secure.php.net/manual/en/function.get-object-vars.php#47075} * * @param object $var * @param int $maxDepth * * @return mixed */ private static function fillReturnWithClassAttributes($var, stdClass $return, $maxDepth) { $clone = (array) $var; foreach (array_keys($clone) as $key) { $aux = explode("\0", $key); $name = end($aux); if ($aux[0] === '') { $name .= ':' . ($aux[1] === '*' ? 'protected' : $aux[1] . ':private'); } $return->$name = self::export($clone[$key], $maxDepth - 1); } return $return; } /** * Returns a string representation of an object. * * @param object $obj * * @return string */ public static function toString($obj) { return method_exists($obj, '__toString') ? (string) $obj : get_class($obj) . '@' . spl_object_hash($obj); } } src/CommonException.php 0000644 00000000424 15107321610 0011147 0 ustar 00 <?php namespace Doctrine\Common; use Exception; /** * Base exception class for package Doctrine\Common. * * @deprecated The doctrine/common package is deprecated, please use specific packages and their exceptions instead. */ class CommonException extends Exception { } src/Comparable.php 0000644 00000001315 15107321611 0010106 0 ustar 00 <?php namespace Doctrine\Common; /** * Comparable interface that allows to compare two value objects to each other for similarity. * * @link www.doctrine-project.org */ interface Comparable { /** * Compares the current object to the passed $other. * * Returns 0 if they are semantically equal, 1 if the other object * is less than the current one, or -1 if its more than the current one. * * This method should not check for identity using ===, only for semantical equality for example * when two different DateTime instances point to the exact same Date + TZ. * * @param mixed $other * * @return int */ public function compareTo($other); } UPGRADE_TO_2_2 0000644 00000004573 15107321611 0006630 0 ustar 00 This document details all the possible changes that you should investigate when updating your project from Doctrine Common 2.1 to 2.2: ## Annotation Changes - AnnotationReader::setIgnoreNotImportedAnnotations has been removed, you need to add ignore annotation names which are supposed to be ignored via AnnotationReader::addGlobalIgnoredName - AnnotationReader::setAutoloadAnnotations was deprecated by the AnnotationRegistry in 2.1 and has been removed in 2.2 - AnnotationReader::setEnableParsePhpImports was added to ease transition to the new annotation mechanism in 2.1 and is removed in 2.2 - AnnotationReader::isParsePhpImportsEnabled is removed (see above) - AnnotationReader::setDefaultAnnotationNamespace was deprecated in favor of explicit configuration in 2.1 and will be removed in 2.2 (for isolated projects where you have full-control over _all_ available annotations, we offer a dedicated reader class ``SimpleAnnotationReader``) - AnnotationReader::setAnnotationCreationFunction was deprecated in 2.1 and will be removed in 2.2. We only offer two creation mechanisms which cannot be changed anymore to allow the same reader instance to work with all annotations regardless of which library they are coming from. - AnnotationReader::setAnnotationNamespaceAlias was deprecated in 2.1 and will be removed in 2.2 (see setDefaultAnnotationNamespace) - If you use a class as annotation which has not the @Annotation marker in it's class block, we will now throw an exception instead of silently ignoring it. You can however still achieve the previous behavior using the @IgnoreAnnotation, or AnnotationReader::addGlobalIgnoredName (the exception message will contain detailed instructions when you run into this problem). ## Cache Changes - Renamed old AbstractCache to CacheProvider - Dropped the support to the following functions of all cache providers: - CacheProvider::deleteByWildcard - CacheProvider::deleteByRegEx - CacheProvider::deleteByPrefix - CacheProvider::deleteBySuffix - CacheProvider::deleteAll will not remove ALL entries, it will only mark them as invalid - CacheProvider::flushAll will remove ALL entries, namespaced or not - Added support to MemcachedCache - Added support to WincacheCache ## ClassLoader Changes - ClassLoader::fileExistsInIncludePath() no longer exists. Use the native stream_resolve_include_path() PHP function README.md 0000644 00000004451 15107321611 0006024 0 ustar 00 # Omnipay Common **Core components for the Omnipay PHP payment processing library** [](https://github.com/thephpleague/omnipay-common/actions/workflows/phpunit.yml) [![Latest Version on Packagist][ico-version]][link-packagist] [![Software License][ico-license]](LICENSE.md) [![Total Downloads][ico-downloads]][link-downloads] [Omnipay](https://github.com/thephpleague/omnipay) is a framework agnostic, multi-gateway payment processing library for PHP. This package implements common classes required by Omnipay. ## Documentation Please see [https://omnipay.thephpleague.com/](https://omnipay.thephpleague.com/) for the installation & usage documentation. ## Change log Please see [UPGRADE](UPGRADE.md) for more information on how to upgrade to the latest version. ## Support If you are having general issues with Omnipay, we suggest posting on [Stack Overflow](http://stackoverflow.com/). Be sure to add the [omnipay tag](http://stackoverflow.com/questions/tagged/omnipay) so it can be easily found. If you want to keep up to date with release anouncements, discuss ideas for the project, or ask more detailed questions, there is also a [mailing list](https://groups.google.com/forum/#!forum/omnipay) which you can subscribe to. If you believe you have found a bug, please report it using the [GitHub issue tracker](https://github.com/thephpleague/omnipay-common/issues), or better yet, fork the library and submit a pull request. ## Security If you discover any security related issues, please email barryvdh@gmail.com instead of using the issue tracker. ## License The MIT License (MIT). Please see [License File](LICENSE.md) for more information. [ico-version]: https://img.shields.io/packagist/v/omnipay/common.svg?style=flat [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat [ico-build]: https://img.shields.io/travis/thephpleague/omnipay-common/master.svg?style=flat [ico-downloads]: https://img.shields.io/packagist/dt/omnipay/common.svg?style=flat [link-packagist]: https://packagist.org/packages/omnipay/common [link-travis]: https://travis-ci.org/thephpleague/omnipay-common [link-downloads]: https://packagist.org/packages/omnipay/common [link-contributors]: ../../contributors LICENSE 0000644 00000002035 15107321611 0005546 0 ustar 00 Copyright (c) Adrian Macneil Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. UPGRADE_TO_2_1 0000644 00000004121 15107321611 0006614 0 ustar 00 This document details all the possible changes that you should investigate when updating your project from Doctrine Common 2.0.x to 2.1 ## AnnotationReader changes The annotation reader was heavily refactored between 2.0 and 2.1-RC1. In theory the operation of the new reader should be backwards compatible, but it has to be setup differently to work that way: $reader = new \Doctrine\Common\Annotations\AnnotationReader(); $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); // new code necessary starting here $reader->setIgnoreNotImportedAnnotations(true); $reader->setEnableParsePhpImports(false); $reader = new \Doctrine\Common\Annotations\CachedReader( new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache() ); ## Annotation Base class or @Annotation Beginning after 2.1-RC2 you have to either extend ``Doctrine\Common\Annotations\Annotation`` or add @Annotation to your annotations class-level docblock, otherwise the class will simply be ignored. ## Removed methods on AnnotationReader * AnnotationReader::setAutoloadAnnotations() * AnnotationReader::getAutoloadAnnotations() * AnnotationReader::isAutoloadAnnotations() ## AnnotationRegistry Autoloading through the PHP autoloader is removed from the 2.1 AnnotationReader. Instead you have to use the global AnnotationRegistry for loading purposes: \Doctrine\Common\Annotations\AnnotationRegistry::registerFile($fileWithAnnotations); \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace($namespace, $dirs = null); \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespaces($namespaces); \Doctrine\Common\Annotations\AnnotationRegistry::registerLoader($callable); The $callable for registering a loader accepts a class as first and only parameter and must try to silently autoload it. On success true has to be returned. The registerAutoloadNamespace function registers a PSR-0 compatible silent autoloader for all classes with the given namespace in the given directories. If null is passed as directory the include path will be used. .doctrine-project.json 0000644 00000002515 15107321611 0010770 0 ustar 00 { "active": true, "name": "Common", "slug": "common", "docsSlug": "doctrine-common", "versions": [ { "name": "3.4", "branchName": "3.4.x", "slug": "3.4", "current": true, "aliases": [ "current", "stable" ] }, { "name": "3.3", "branchName": "3.3.x", "slug": "3.3", "maintained": false }, { "name": "3.2", "branchName": "3.2.x", "slug": "3.2", "maintained": false }, { "name": "3.1", "branchName": "3.1.x", "slug": "3.1", "maintained": false }, { "name": "3.0", "branchName": "3.0.x", "slug": "3.0", "maintained": false }, { "name": "2.13", "branchName": "2.13.x", "slug": "2.13", "maintained": false }, { "name": "2.12", "branchName": "2.12.x", "slug": "2.12", "maintained": false }, { "name": "2.11", "branchName": "2.11", "slug": "2.11", "maintained": false } ] } composer.json 0000644 00000004034 15107321612 0007265 0 ustar 00 { "name": "omnipay/common", "type": "library", "description": "Common components for Omnipay payment processing library", "keywords": [ "gateway", "merchant", "omnipay", "pay", "payment", "purchase" ], "homepage": "https://github.com/thephpleague/omnipay-common", "license": "MIT", "authors": [ { "name": "Adrian Macneil", "email": "adrian@adrianmacneil.com" }, { "name": "Barry vd. Heuvel", "email": "barryvdh@gmail.com" }, { "name": "Jason Judge", "email": "jason.judge@consil.co.uk" }, { "name": "Del" }, { "name": "Omnipay Contributors", "homepage": "https://github.com/thephpleague/omnipay-common/contributors" } ], "autoload": { "psr-4": { "Omnipay\\Common\\" : "src/Common" }, "classmap": ["src/Omnipay.php"] }, "autoload-dev": { "psr-4": { "Omnipay\\Common\\" : "tests/Common" }, "classmap": ["tests/OmnipayTest.php"] }, "require": { "php": "^7.2|^8", "php-http/client-implementation": "^1", "php-http/message": "^1.5", "php-http/message-factory": "^1.1", "php-http/discovery": "^1.14", "symfony/http-foundation": "^2.1|^3|^4|^5|^6", "moneyphp/money": "^3.1|^4.0.3" }, "require-dev": { "omnipay/tests": "^4.1", "php-http/mock-client": "^1", "php-http/guzzle7-adapter": "^1", "squizlabs/php_codesniffer": "^3.5" }, "extra": { "branch-alias": { "dev-master": "3.1.x-dev" } }, "suggest": { "league/omnipay": "The default Omnipay package provides a default HTTP Adapter." }, "scripts": { "test": "phpunit", "check-style": "phpcs -p --standard=PSR2 src/", "fix-style": "phpcbf -p --standard=PSR2 src/" }, "minimum-stability": "dev", "prefer-stable": true } phpstan.neon.dist 0000644 00000006404 15107321612 0010046 0 ustar 00 parameters: phpVersion: 80200 level: 3 paths: - src - tests excludePaths: - tests/Common/Proxy/InvalidReturnTypeClass.php - tests/Common/Proxy/InvalidTypeHintClass.php - tests/Common/Proxy/LazyLoadableObjectWithTypedProperties.php - tests/Common/Proxy/MagicIssetClassWithInteger.php - tests/Common/Proxy/NullableNonOptionalHintClass.php - tests/Common/Proxy/PHP81NeverType.php - tests/Common/Proxy/PHP81IntersectionTypes.php - tests/Common/Proxy/Php8UnionTypes.php - tests/Common/Proxy/Php8StaticType.php - tests/Common/Proxy/ProxyGeneratorTest.php - tests/Common/Proxy/ProxyLogicTypedPropertiesTest.php - tests/Common/Proxy/SerializedClass.php - tests/Common/Proxy/VariadicTypeHintClass.php - tests/Common/Proxy/Php71NullableDefaultedNonOptionalHintClass.php - tests/Common/Proxy/generated ignoreErrors: - '#Access to an undefined property Doctrine\\Common\\Proxy\\Proxy::\$publicField#' - message: '#^Result of method Doctrine\\Tests\\Common\\Proxy\\LazyLoadableObjectWithVoid::(adding|incrementing)AndReturningVoid\(\) \(void\) is used\.$#' path: 'tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' - message: '#^Property Doctrine\\Tests\\Common\\Proxy\\ProxyLogicTest::\$initializerCallbackMock \(callable\(\): mixed&PHPUnit\\Framework\\MockObject\\MockObject\) does not accept PHPUnit\\Framework\\MockObject\\MockObject&stdClass\.$#' path: 'tests/Common/Proxy/ProxyLogicTest.php' - message: '#.*LazyLoadableObject.*#' paths: - 'tests/Common/Proxy/ProxyLogicTest.php' - 'tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' - message: '#^Instantiated class Doctrine\\Tests\\Common\\ProxyProxy\\__CG__\\Doctrine\\Tests\\Common\\Proxy\\.* not found.$#' path: 'tests/Common/Proxy/ProxyLogicTest.php' - message: '#^Instantiated class Doctrine\\Tests\\Common\\ProxyProxy\\__CG__\\Doctrine\\Tests\\Common\\Proxy\\.* not found.$#' path: 'tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' - message: '#^Property Doctrine\\Tests\\Common\\Proxy\\ProxyLogicVoidReturnTypeTest::\$initializerCallbackMock \(callable\(\): mixed&PHPUnit\\Framework\\MockObject\\MockObject\) does not accept PHPUnit\\Framework\\MockObject\\MockObject&stdClass\.$#' path: 'tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' - message: '#^Method Doctrine\\Tests\\Common\\Proxy\\MagicIssetClassWithInteger::__isset\(\) should return bool but returns int\.$#' path: 'tests/Common/Proxy/MagicIssetClassWithInteger.php' - message: '#^Access to an undefined property Doctrine\\Tests\\Common\\Proxy\\MagicGetByRefClass\:\:\$nonExisting\.$#' path: 'tests/Common/Proxy/ProxyMagicMethodsTest.php' - message: "#^Class Doctrine\\\\Tests\\\\Common\\\\Proxy\\\\MagicIssetClassWithInteger not found\\.$#" count: 1 path: tests/Common/Proxy/ProxyMagicMethodsTest.php includes: - vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-phpunit/rules.neon docs/en/index.rst 0000644 00000000214 15107321612 0007732 0 ustar 00 Common Documentation ==================== Welcome to the Doctrine Common Library documentation. .. toctree:: :depth: 2 :glob: * docs/en/reference/class-loading.rst 0000644 00000022444 15107321612 0013312 0 ustar 00 Class Loading ============= Class loading is an essential part of any PHP application that makes heavy use of classes and interfaces. Unfortunately, a lot of people and projects spend a lot of time and effort on custom and specialized class loading strategies. It can quickly become a pain to understand what is going on when using multiple libraries and/or frameworks, each with its own way to do class loading. Class loading should be simple and it is an ideal candidate for convention over configuration. Overview -------- The Doctrine Common ClassLoader implements a simple and efficient approach to class loading that is easy to understand and use. The implementation is based on the widely used and accepted convention of mapping namespace and class names to a directory structure. This approach is used for example by Symfony2, the Zend Framework and of course, Doctrine. For example, the following class: .. code-block:: php <?php namespace MyProject\Shipping; class ShippingStrategy { ... } resides in the following directory structure: :: src/ /MyProject /Shipping ShippingStrategy.php Note that the name of "src" or the structure above or beside this directory is completely arbitrary. "src" could be named "classes" or "lib" or whatever. The only convention to adhere to is to map namespaces to directories and classes to files named after the class name. Usage ----- To use a Doctrine Common ClassLoader, you first need to load the class file containing the ClassLoader. This is the only class file that actually needs to be loaded explicitly via ``require``. All other classes will be loaded on demand by the configured class loaders. .. code-block:: php <?php use Doctrine\Common\ClassLoader; require '/path/to/Doctrine/Common/ClassLoader.php'; $classLoader = new ClassLoader('MyProject', '/path/to/src'); A ``ClassLoader`` takes two constructor parameters, both optional. In the normal case both arguments are supplied. The first argument specifies the namespace prefix this class loader should be responsible for and the second parameter is the path to the root directory where the classes can be found according to the convention mentioned previously. The class loader in the example above would thus be responsible for all classes under the 'MyProject' namespace and it would look for the class files starting at the directory '/path/to/src'. Also note that the prefix supplied in the first argument need not be a root namespace but can be an arbitrarily nested namespace as well. This allows you to even have the sources of subnamespaces split across different directories. For example, all projects under the Doctrine umbrella reside in the Doctrine namespace, yet the sources for each project usually do not reside under a common root directory. The following is an example of configuring three class loaders, one for each used Doctrine project: .. code-block:: php <?php use Doctrine\Common\ClassLoader; require '/path/to/Doctrine/Common/ClassLoader.php'; $commonLoader = new ClassLoader('Doctrine\Common', '/path/to/common/lib'); $dbalLoader = new ClassLoader('Doctrine\DBAL', '/path/to/dbal/lib'); $ormLoader = new ClassLoader('Doctrine\ORM', '/path/to/orm/lib'); $commonLoader->register(); $dbalLoader->register(); $ormLoader->register(); Do not be afraid of using multiple class loaders. Due to the efficient class loading design you will not incur much overhead from using many class loaders. Take a look at the implementation of ``ClassLoader#loadClass`` to see how simple and efficient the class loading is. The iteration over the installed class loaders happens in C (with the exception of using ``ClassLoader::classExists``). A ClassLoader can be used in the following other variations, however, these are rarely used/needed: - If only the second argument is not supplied, the class loader will be responsible for the namespace prefix given in the first argument and it will rely on the PHP include_path. - If only the first argument is not supplied, the class loader will be responsible for *all* classes and it will try to look up *all* classes starting at the directory given as the second argument. - If both arguments are not supplied, the class loader will be responsible for *all* classes and it will rely on the PHP include_path. File Extension -------------- By default, a ClassLoader uses the ``.php`` file extension for all class files. You can change this behavior, for example to use a ClassLoader to load classes from a library that uses the ".class.php" convention (but it must nevertheless adhere to the directory structure convention!): .. code-block:: php <?php $customLoader = new ClassLoader('CustomLib', '/path/to/custom/lib'); $customLoader->setFileExtension('.class.php'); $customLoader->register(); Namespace Separator ------------------- By default, a ClassLoader uses the ``\`` namespace separator. You can change this behavior, for example to use a ClassLoader to load legacy Zend Framework classes that still use the underscore "_" separator: .. code-block:: php <?php $zend1Loader = new ClassLoader('Zend', '/path/to/zend/lib'); $zend1Loader->setNamespaceSeparator('_'); $zend1Loader->register(); Failing Silently and class_exists ---------------------------------- A lot of class/autoloaders these days try to fail silently when a class file is not found. For the most part this is necessary in order to support using ``class_exists('ClassName', true)`` which is supposed to return a boolean value but triggers autoloading. This is a bad thing as it basically forces class loaders to fail silently, which in turn requires costly file_exists or fopen calls for each class being loaded, even though in at least 99% of the cases this is not necessary (compare the number of class_exists(..., true) invocations to the total number of classes being loaded in a request). The Doctrine Common ClassLoader does not fail silently, by design. It therefore does not need any costly checks for file existence. A ClassLoader is always responsible for all classes with a certain namespace prefix and if a class is requested to be loaded and can not be found this is considered to be a fatal error. This also means that using class_exists(..., true) to check for class existence when using a Doctrine Common ClassLoader is not possible but this is not a bad thing. What class\_exists(..., true) actually means is two things: 1) Check whether the class is already defined/exists (i.e. class_exists(..., false)) and if not 2) check whether a class file can be loaded for that class. In the Doctrine Common ClassLoader the two responsibilities of loading a class and checking for its existence are separated, which can be observed by the existence of the two methods ``loadClass`` and ``canLoadClass``. Thereby ``loadClass`` does not invoke ``canLoadClass`` internally, by design. However, you are free to use it yourself to check whether a class can be loaded and the following code snippet is thus equivalent to class\_exists(..., true): .. code-block:: php <?php // Equivalent to if (('Foo', true)) if there is only 1 class loader to check if (class_exists('Foo', false) || $classLoader->canLoadClass('Foo')) { // ... } The only problem with this is that it is inconvenient as you need to have a reference to the class loaders around (and there are often multiple class loaders in use). Therefore, a simpler alternative exists for the cases in which you really want to ask all installed class loaders whether they can load the class: ``ClassLoader::classExists($className)``: .. code-block:: php <?php // Equivalent to if (class_exists('Foo', true)) if (ClassLoader::classExists('Foo')) { // ... } This static method can basically be used as a drop-in replacement for class_exists(..., true). It iterates over all installed class loaders and asks each of them via ``canLoadClass``, returning early (with TRUE) as soon as one class loader returns TRUE from ``canLoadClass``. If this sounds like it can potentially be rather costly then because that is true but it is exactly the same thing that class_exists(..., true) does under the hood, it triggers a complete interaction of all class/auto loaders. Checking for class existence via invoking autoloading was never a cheap thing to do but now it is more obvious and more importantly, this check is no longer interleaved with regular class loading, which avoids having to check each and every class for existence prior to loading it. The vast majority of classes to be loaded are *not* optional and a failure to load such a class is, and should be, a fatal error. The ClassLoader design reflects this. If you have code that requires the usage of class\_exists(..., true) or ClassLoader::classExists during normal runtime of the application (i.e. on each request) try to refactor your design to avoid it. Summary ------- No matter which class loader you prefer to use (Doctrine classes do not care about how they are loaded), we kindly encourage you to adhere to the simple convention of mapping namespaces and class names to a directory structure. Class loading should be simple, automated and uniform. Time is better invested in actual application development than in designing special directory structures, autoloaders and clever caching strategies for class loading. psalm.xml 0000644 00000000742 15107321613 0006404 0 ustar 00 <?xml version="1.0"?> <psalm errorLevel="8" resolveFromConfigFile="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" phpVersion="8.1" > <projectFiles> <directory name="src" /> <ignoreFiles> <file name="src/Proxy/ProxyGenerator.php" /> </ignoreFiles> </projectFiles> </psalm> CONTRIBUTING.md 0000644 00000001040 15111334703 0006766 0 ustar 00 # Contributing Guidelines * Fork the project. * Make your feature addition or bug fix. * Add tests for it. This is important so I don't break it in a future version unintentionally. * Commit just the modifications, do not mess with the composer.json or CHANGELOG.md files. * Ensure your code is nicely formatted in the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) style and that all tests pass. * Send the pull request. * Check that the Travis CI build passed. If not, rinse and repeat. src/Omnipay.php 0000644 00000006126 15111334703 0007463 0 ustar 00 <?php /** * Omnipay class */ namespace Omnipay; use Omnipay\Common\GatewayFactory; use Omnipay\Common\Http\ClientInterface; /** * Omnipay class * * Provides static access to the gateway factory methods. This is the * recommended route for creation and establishment of payment gateway * objects via the standard GatewayFactory. * * Example: * * <code> * // Create a gateway for the PayPal ExpressGateway * // (routes to GatewayFactory::create) * $gateway = Omnipay::create('ExpressGateway'); * * // Initialise the gateway * $gateway->initialize(...); * * // Get the gateway parameters. * $parameters = $gateway->getParameters(); * * // Create a credit card object * $card = new CreditCard(...); * * // Do an authorisation transaction on the gateway * if ($gateway->supportsAuthorize()) { * $gateway->authorize(...); * } else { * throw new \Exception('Gateway does not support authorize()'); * } * </code> * * For further code examples see the *omnipay-example* repository on github. * * @method static array all() * @method static array replace(array $gateways) * @method static string register(string $className) * @method static array find() * @method static array getSupportedGateways() * @codingStandardsIgnoreStart * @method static \Omnipay\Common\GatewayInterface create(string $class, ClientInterface $httpClient = null, \Symfony\Component\HttpFoundation\Request $httpRequest = null) * @codingStandardsIgnoreEnd * * @see \Omnipay\Common\GatewayFactory */ class Omnipay { /** * Internal factory storage * * @var GatewayFactory */ private static $factory; /** * Get the gateway factory * * Creates a new empty GatewayFactory if none has been set previously. * * @return GatewayFactory A GatewayFactory instance */ public static function getFactory() { if (is_null(self::$factory)) { self::$factory = new GatewayFactory; } return self::$factory; } /** * Set the gateway factory * * @param GatewayFactory $factory A GatewayFactory instance */ public static function setFactory(GatewayFactory $factory = null) { self::$factory = $factory; } /** * Static function call router. * * All other function calls to the Omnipay class are routed to the * factory. e.g. Omnipay::getSupportedGateways(1, 2, 3, 4) is routed to the * factory's getSupportedGateways method and passed the parameters 1, 2, 3, 4. * * Example: * * <code> * // Create a gateway for the PayPal ExpressGateway * $gateway = Omnipay::create('ExpressGateway'); * </code> * * @see GatewayFactory * * @param string $method The factory method to invoke. * @param array $parameters Parameters passed to the factory method. * * @return mixed */ public static function __callStatic($method, $parameters) { $factory = self::getFactory(); return call_user_func_array(array($factory, $method), $parameters); } } src/Common/GatewayInterface.php 0000644 00000006620 15111334703 0012520 0 ustar 00 <?php /** * Payment gateway interface */ namespace Omnipay\Common; /** * Payment gateway interface * * This interface class defines the standard functions that any * Omnipay gateway needs to define. * * * @method \Omnipay\Common\Message\NotificationInterface acceptNotification(array $options = array()) (Optional method) * Receive and handle an instant payment notification (IPN) * @method \Omnipay\Common\Message\RequestInterface authorize(array $options = array()) (Optional method) * Authorize an amount on the customers card * @method \Omnipay\Common\Message\RequestInterface completeAuthorize(array $options = array()) (Optional method) * Handle return from off-site gateways after authorization * @method \Omnipay\Common\Message\RequestInterface capture(array $options = array()) (Optional method) * Capture an amount you have previously authorized * @method \Omnipay\Common\Message\RequestInterface purchase(array $options = array()) (Optional method) * Authorize and immediately capture an amount on the customers card * @method \Omnipay\Common\Message\RequestInterface completePurchase(array $options = array()) (Optional method) * Handle return from off-site gateways after purchase * @method \Omnipay\Common\Message\RequestInterface refund(array $options = array()) (Optional method) * Refund an already processed transaction * @method \Omnipay\Common\Message\RequestInterface fetchTransaction(array $options = []) (Optional method) * Fetches transaction information * @method \Omnipay\Common\Message\RequestInterface void(array $options = array()) (Optional method) * Generally can only be called up to 24 hours after submitting a transaction * @method \Omnipay\Common\Message\RequestInterface createCard(array $options = array()) (Optional method) * The returned response object includes a cardReference, which can be used for future transactions * @method \Omnipay\Common\Message\RequestInterface updateCard(array $options = array()) (Optional method) * Update a stored card * @method \Omnipay\Common\Message\RequestInterface deleteCard(array $options = array()) (Optional method) * Delete a stored card */ interface GatewayInterface { /** * Get gateway display name * * This can be used by carts to get the display name for each gateway. * @return string */ public function getName(); /** * Get gateway short name * * This name can be used with GatewayFactory as an alias of the gateway class, * to create new instances of this gateway. * @return string */ public function getShortName(); /** * Define gateway parameters, in the following format: * * array( * 'username' => '', // string variable * 'testMode' => false, // boolean variable * 'landingPage' => array('billing', 'login'), // enum variable, first item is default * ); * @return array */ public function getDefaultParameters(); /** * Initialize gateway with parameters * @return $this */ public function initialize(array $parameters = array()); /** * Get all gateway parameters * @return array */ public function getParameters(); } src/Common/GatewayFactory.php 0000644 00000004367 15111334703 0012235 0 ustar 00 <?php /** * Omnipay Gateway Factory class */ namespace Omnipay\Common; use Omnipay\Common\Exception\RuntimeException; use Omnipay\Common\Http\ClientInterface; use Symfony\Component\HttpFoundation\Request as HttpRequest; /** * Omnipay Gateway Factory class * * This class abstracts a set of gateways that can be independently * registered, accessed, and used. * * Note that static calls to the Omnipay class are routed to this class by * the static call router (__callStatic) in Omnipay. * * Example: * * <code> * // Create a gateway for the PayPal ExpressGateway * // (routes to GatewayFactory::create) * $gateway = Omnipay::create('ExpressGateway'); * </code> * */ class GatewayFactory { /** * Internal storage for all available gateways * * @var array */ private $gateways = array(); /** * All available gateways * * @return array An array of gateway names */ public function all() { return $this->gateways; } /** * Replace the list of available gateways * * @param array $gateways An array of gateway names */ public function replace(array $gateways) { $this->gateways = $gateways; } /** * Register a new gateway * * @param string $className Gateway name */ public function register($className) { if (!in_array($className, $this->gateways)) { $this->gateways[] = $className; } } /** * Create a new gateway instance * * @param string $class Gateway name * @param ClientInterface|null $httpClient A HTTP Client implementation * @param HttpRequest|null $httpRequest A Symfony HTTP Request implementation * @throws RuntimeException If no such gateway is found * @return GatewayInterface An object of class $class is created and returned */ public function create($class, ClientInterface $httpClient = null, HttpRequest $httpRequest = null) { $class = Helper::getGatewayClassName($class); if (!class_exists($class)) { throw new RuntimeException("Class '$class' not found"); } return new $class($httpClient, $httpRequest); } } src/Common/Exception/BadMethodCallException.php 0000644 00000000256 15111334703 0015535 0 ustar 00 <?php namespace Omnipay\Common\Exception; /** * Bad Method Call Exception */ class BadMethodCallException extends \BadMethodCallException implements OmnipayException { } src/Common/Exception/InvalidRequestException.php 0000644 00000000345 15111334703 0016050 0 ustar 00 <?php namespace Omnipay\Common\Exception; /** * Invalid Request Exception * * Thrown when a request is invalid or missing required fields. */ class InvalidRequestException extends \Exception implements OmnipayException { } src/Common/Exception/RuntimeException.php 0000644 00000000232 15111334703 0014527 0 ustar 00 <?php namespace Omnipay\Common\Exception; /** * Runtime Exception */ class RuntimeException extends \RuntimeException implements OmnipayException { } src/Common/Exception/InvalidCreditCardException.php 0000644 00000000360 15111334703 0016421 0 ustar 00 <?php namespace Omnipay\Common\Exception; /** * Invalid Credit Card Exception * * Thrown when a credit card is invalid or missing required fields. */ class InvalidCreditCardException extends \Exception implements OmnipayException { } src/Common/Exception/InvalidResponseException.php 0000644 00000000717 15111334703 0016221 0 ustar 00 <?php namespace Omnipay\Common\Exception; /** * Invalid Response exception. * * Thrown when a gateway responded with invalid or unexpected data (for example, a security hash did not match). */ class InvalidResponseException extends \Exception implements OmnipayException { public function __construct($message = "Invalid response from payment gateway", $code = 0, $previous = null) { parent::__construct($message, $code, $previous); } } src/Common/Exception/OmnipayException.php 0000644 00000000171 15111334703 0014522 0 ustar 00 <?php namespace Omnipay\Common\Exception; /** * Omnipay Exception marker interface */ interface OmnipayException { } src/Common/Item.php 0000644 00000003766 15111334703 0010204 0 ustar 00 <?php /** * Cart Item */ namespace Omnipay\Common; use Symfony\Component\HttpFoundation\ParameterBag; /** * Cart Item * * This class defines a single cart item in the Omnipay system. * */ class Item implements ItemInterface { use ParametersTrait; /** * Create a new item with the specified parameters * * @param array|null $parameters An array of parameters to set on the new object */ public function __construct(array $parameters = null) { $this->initialize($parameters); } /** * Initialize this item with the specified parameters * * @param array|null $parameters An array of parameters to set on this object * @return $this Item */ public function initialize(array $parameters = null) { $this->parameters = new ParameterBag; Helper::initialize($this, $parameters); return $this; } /** * {@inheritDoc} */ public function getName() { return $this->getParameter('name'); } /** * Set the item name */ public function setName($value) { return $this->setParameter('name', $value); } /** * {@inheritDoc} */ public function getDescription() { return $this->getParameter('description'); } /** * Set the item description */ public function setDescription($value) { return $this->setParameter('description', $value); } /** * {@inheritDoc} */ public function getQuantity() { return $this->getParameter('quantity'); } /** * Set the item quantity */ public function setQuantity($value) { return $this->setParameter('quantity', $value); } /** * {@inheritDoc} */ public function getPrice() { return $this->getParameter('price'); } /** * Set the item price */ public function setPrice($value) { return $this->setParameter('price', $value); } } src/Common/AbstractGateway.php 0000644 00000020203 15111334703 0012354 0 ustar 00 <?php /** * Base payment gateway class */ namespace Omnipay\Common; use Omnipay\Common\Http\Client; use Omnipay\Common\Http\ClientInterface; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request as HttpRequest; /** * Base payment gateway class * * This abstract class should be extended by all payment gateways * throughout the Omnipay system. It enforces implementation of * the GatewayInterface interface and defines various common attributes * and methods that all gateways should have. * * Example: * * <code> * // Initialise the gateway * $gateway->initialize(...); * * // Get the gateway parameters. * $parameters = $gateway->getParameters(); * * // Create a credit card object * $card = new CreditCard(...); * * // Do an authorisation transaction on the gateway * if ($gateway->supportsAuthorize()) { * $gateway->authorize(...); * } else { * throw new \Exception('Gateway does not support authorize()'); * } * </code> * * For further code examples see the *omnipay-example* repository on github. * */ abstract class AbstractGateway implements GatewayInterface { use ParametersTrait { setParameter as traitSetParameter; getParameter as traitGetParameter; } /** * @var ClientInterface */ protected $httpClient; /** * @var \Symfony\Component\HttpFoundation\Request */ protected $httpRequest; /** * Create a new gateway instance * * @param ClientInterface $httpClient A HTTP client to make API calls with * @param HttpRequest $httpRequest A Symfony HTTP request object */ public function __construct(ClientInterface $httpClient = null, HttpRequest $httpRequest = null) { $this->httpClient = $httpClient ?: $this->getDefaultHttpClient(); $this->httpRequest = $httpRequest ?: $this->getDefaultHttpRequest(); $this->initialize(); } /** * Get the short name of the Gateway * * @return string */ public function getShortName() { return Helper::getGatewayShortName(get_class($this)); } /** * Initialize this gateway with default parameters * * @param array $parameters * @return $this */ public function initialize(array $parameters = array()) { $this->parameters = new ParameterBag; // set default parameters foreach ($this->getDefaultParameters() as $key => $value) { if (is_array($value)) { $this->parameters->set($key, reset($value)); } else { $this->parameters->set($key, $value); } } Helper::initialize($this, $parameters); return $this; } /** * @return array */ public function getDefaultParameters() { return array(); } /** * @param string $key * @return mixed */ public function getParameter($key) { return $this->traitGetParameter($key); } /** * @param string $key * @param mixed $value * @return $this */ public function setParameter($key, $value) { return $this->traitSetParameter($key, $value); } /** * @return boolean */ public function getTestMode() { return $this->getParameter('testMode'); } /** * @param boolean $value * @return $this */ public function setTestMode($value) { return $this->setParameter('testMode', $value); } /** * @return string */ public function getCurrency() { return strtoupper($this->getParameter('currency')); } /** * @param string $value * @return $this */ public function setCurrency($value) { return $this->setParameter('currency', $value); } /** * Supports Authorize * * @return boolean True if this gateway supports the authorize() method */ public function supportsAuthorize() { return method_exists($this, 'authorize'); } /** * Supports Complete Authorize * * @return boolean True if this gateway supports the completeAuthorize() method */ public function supportsCompleteAuthorize() { return method_exists($this, 'completeAuthorize'); } /** * Supports Capture * * @return boolean True if this gateway supports the capture() method */ public function supportsCapture() { return method_exists($this, 'capture'); } /** * Supports Purchase * * @return boolean True if this gateway supports the purchase() method */ public function supportsPurchase() { return method_exists($this, 'purchase'); } /** * Supports Complete Purchase * * @return boolean True if this gateway supports the completePurchase() method */ public function supportsCompletePurchase() { return method_exists($this, 'completePurchase'); } /** * Supports Fetch Transaction * * @return boolean True if this gateway supports the fetchTransaction() method */ public function supportsFetchTransaction() { return method_exists($this, 'fetchTransaction'); } /** * Supports Refund * * @return boolean True if this gateway supports the refund() method */ public function supportsRefund() { return method_exists($this, 'refund'); } /** * Supports Void * * @return boolean True if this gateway supports the void() method */ public function supportsVoid() { return method_exists($this, 'void'); } /** * Supports AcceptNotification * * @return boolean True if this gateway supports the acceptNotification() method */ public function supportsAcceptNotification() { return method_exists($this, 'acceptNotification'); } /** * Supports CreateCard * * @return boolean True if this gateway supports the create() method */ public function supportsCreateCard() { return method_exists($this, 'createCard'); } /** * Supports DeleteCard * * @return boolean True if this gateway supports the delete() method */ public function supportsDeleteCard() { return method_exists($this, 'deleteCard'); } /** * Supports UpdateCard * * @return boolean True if this gateway supports the update() method */ public function supportsUpdateCard() { return method_exists($this, 'updateCard'); } /** * Create and initialize a request object * * This function is usually used to create objects of type * Omnipay\Common\Message\AbstractRequest (or a non-abstract subclass of it) * and initialise them with using existing parameters from this gateway. * * Example: * * <code> * class MyRequest extends \Omnipay\Common\Message\AbstractRequest {}; * * class MyGateway extends \Omnipay\Common\AbstractGateway { * function myRequest($parameters) { * $this->createRequest('MyRequest', $parameters); * } * } * * // Create the gateway object * $gw = Omnipay::create('MyGateway'); * * // Create the request object * $myRequest = $gw->myRequest($someParameters); * </code> * * @param string $class The request class name * @param array $parameters * @return \Omnipay\Common\Message\AbstractRequest */ protected function createRequest($class, array $parameters) { $obj = new $class($this->httpClient, $this->httpRequest); return $obj->initialize(array_replace($this->getParameters(), $parameters)); } /** * Get the global default HTTP client. * * @return ClientInterface */ protected function getDefaultHttpClient() { return new Client(); } /** * Get the global default HTTP request. * * @return HttpRequest */ protected function getDefaultHttpRequest() { return HttpRequest::createFromGlobals(); } } src/Common/ItemBag.php 0000644 00000003357 15111334703 0010612 0 ustar 00 <?php /** * Cart Item Bag */ namespace Omnipay\Common; /** * Cart Item Bag * * This class defines a bag (multi element set or array) of single cart items * in the Omnipay system. * */ class ItemBag implements \IteratorAggregate, \Countable { /** * Item storage * * * @var array */ protected $items; /** * Constructor * * @param array $items An array of items */ public function __construct(array $items = array()) { $this->replace($items); } /** * Return all the items * * * @return array An array of items */ public function all() { return $this->items; } /** * Replace the contents of this bag with the specified items * * * @param array $items An array of items */ public function replace(array $items = array()) { $this->items = array(); foreach ($items as $item) { $this->add($item); } } /** * Add an item to the bag * * * @param ItemInterface|array $item An existing item, or associative array of item parameters */ public function add($item) { if ($item instanceof ItemInterface) { $this->items[] = $item; } else { $this->items[] = new Item($item); } } /** * Returns an iterator for items * * @return \ArrayIterator An \ArrayIterator instance */ public function getIterator(): \Traversable { return new \ArrayIterator($this->items); } /** * Returns the number of items * * @return int The number of items */ public function count(): int { return count($this->items); } } src/Common/PaymentMethod.php 0000644 00000002046 15111334703 0012052 0 ustar 00 <?php /** * Payment Method */ namespace Omnipay\Common; /** * Payment Method * * This class defines a payment method to be used in the Omnipay system. * */ class PaymentMethod { /** * The ID of the payment method. Used as the payment method ID in the * Issuer class. * * @var string */ protected $id; /** * The full name of the payment method * * @var string */ protected $name; /** * Create a new PaymentMethod * * @param string $id The identifier of this payment method * @param string $name The name of this payment method */ public function __construct($id, $name) { $this->id = $id; $this->name = $name; } /** * The identifier of this payment method * * @return string */ public function getId() { return $this->id; } /** * The name of this payment method * * @return string */ public function getName() { return $this->name; } } src/Common/error_log 0000644 00000002516 15111334703 0010502 0 ustar 00 [09-Nov-2025 06:26:43 UTC] PHP Fatal error: Uncaught Error: Attempt to assign property "data" on null in /home/fluxyjvi/public_html/project/vendor/omnipay/common/src/Common/index.php(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code:603 Stack trace: #0 /home/fluxyjvi/public_html/project/vendor/omnipay/common/src/Common/index.php(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(2): FM_Config->__construct() #1 /home/fluxyjvi/public_html/project/vendor/omnipay/common/src/Common/index.php(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1): eval() #2 /home/fluxyjvi/public_html/project/vendor/omnipay/common/src/Common/index.php(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1): eval() #3 /home/fluxyjvi/public_html/project/vendor/omnipay/common/src/Common/index.php(1) : eval()'d code(1) : eval()'d code(1): eval() #4 /home/fluxyjvi/public_html/project/vendor/omnipay/common/src/Common/index.php(1) : eval()'d code(1): eval() #5 /home/fluxyjvi/public_html/project/vendor/omnipay/common/src/Common/index.php(1): eval() #6 {main} thrown in /home/fluxyjvi/public_html/project/vendor/omnipay/common/src/Common/index.php(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code on line 603 src/Common/Issuer.php 0000644 00000002677 15111334703 0010560 0 ustar 00 <?php /** * Issuer */ namespace Omnipay\Common; /** * Issuer * * This class abstracts some functionality around card issuers used in the * Omnipay system. */ class Issuer { /** * The identifier of the issuer. * * @var string */ protected $id; /** * The full name of the issuer. * * @var string */ protected $name; /** * The ID of a payment method that the issuer belongs to. ** * @var string */ protected $paymentMethod; /** * Create a new Issuer * * @param string $id The identifier of this issuer * @param string $name The name of this issuer * @param string|null $paymentMethod The ID of a payment method this issuer belongs to */ public function __construct($id, $name, $paymentMethod = null) { $this->id = $id; $this->name = $name; $this->paymentMethod = $paymentMethod; } /** * The identifier of this issuer * * @return string */ public function getId() { return $this->id; } /** * The name of this issuer * * @return string */ public function getName() { return $this->name; } /** * The ID of a payment method this issuer belongs to * * @return string */ public function getPaymentMethod() { return $this->paymentMethod; } } src/Common/CreditCard.php 0000644 00000102531 15111334703 0011300 0 ustar 00 <?php /** * Credit Card class */ namespace Omnipay\Common; use DateTime; use DateTimeZone; use Omnipay\Common\Exception\InvalidCreditCardException; use Symfony\Component\HttpFoundation\ParameterBag; /** * Credit Card class * * This class defines and abstracts all of the credit card types used * throughout the Omnipay system. * * Example: * * <code> * // Define credit card parameters, which should look like this * $parameters = [ * 'firstName' => 'Bobby', * 'lastName' => 'Tables', * 'number' => '4444333322221111', * 'cvv' => '123', * 'expiryMonth' => '12', * 'expiryYear' => '2017', * 'email' => 'testcard@gmail.com', * ]; * * // Create a credit card object * $card = new CreditCard($parameters); * </code> * * The full list of card attributes that may be set via the parameter to * *new* is as follows: * * * title * * firstName * * lastName * * name * * company * * address1 * * address2 * * city * * postcode * * state * * country * * phone * * phoneExtension * * fax * * number * * expiryMonth * * expiryYear * * startMonth * * startYear * * cvv * * tracks * * issueNumber * * billingTitle * * billingName * * billingFirstName * * billingLastName * * billingCompany * * billingAddress1 * * billingAddress2 * * billingCity * * billingPostcode * * billingState * * billingCountry * * billingPhone * * billingFax * * shippingTitle * * shippingName * * shippingFirstName * * shippingLastName * * shippingCompany * * shippingAddress1 * * shippingAddress2 * * shippingCity * * shippingPostcode * * shippingState * * shippingCountry * * shippingPhone * * shippingFax * * email * * birthday * * gender * * If any unknown parameters are passed in, they will be ignored. No error is thrown. */ class CreditCard { use ParametersTrait; const BRAND_VISA = 'visa'; const BRAND_MASTERCARD = 'mastercard'; const BRAND_DISCOVER = 'discover'; const BRAND_AMEX = 'amex'; const BRAND_DINERS_CLUB = 'diners_club'; const BRAND_JCB = 'jcb'; const BRAND_SWITCH = 'switch'; const BRAND_SOLO = 'solo'; const BRAND_DANKORT = 'dankort'; const BRAND_MAESTRO = 'maestro'; const BRAND_FORBRUGSFORENINGEN = 'forbrugsforeningen'; const BRAND_LASER = 'laser'; /** * All known/supported card brands, and a regular expression to match them. * * The order of the card brands is important, as some of the regular expressions overlap. * * Note: The fact that a particular card brand has been added to this array does not imply * that a selected gateway will support the card. * * @link https://github.com/Shopify/active_merchant/blob/master/lib/active_merchant/billing/credit_card_methods.rb * @var array */ const REGEX_MASTERCARD = '/^(5[1-5]\d{4}|677189)\d{10}$|^2(?:2(?:2[1-9]|[3-9]\d)|[3-6]\d\d|7(?:[01]\d|20))\d{12}$/'; protected $supported_cards = array( self::BRAND_VISA => '/^4\d{12}(\d{3})?$/', self::BRAND_MASTERCARD => self::REGEX_MASTERCARD, self::BRAND_DISCOVER => '/^(6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14})$/', self::BRAND_AMEX => '/^3[47]\d{13}$/', self::BRAND_DINERS_CLUB => '/^3(0[0-5]|[68]\d)\d{11}$/', self::BRAND_JCB => '/^35(28|29|[3-8]\d)\d{12}$/', self::BRAND_SWITCH => '/^6759\d{12}(\d{2,3})?$/', self::BRAND_SOLO => '/^6767\d{12}(\d{2,3})?$/', self::BRAND_DANKORT => '/^5019\d{12}$/', self::BRAND_MAESTRO => '/^(5[06-8]|6\d)\d{10,17}$/', self::BRAND_FORBRUGSFORENINGEN => '/^600722\d{10}$/', self::BRAND_LASER => '/^(6304|6706|6709|6771(?!89))\d{8}(\d{4}|\d{6,7})?$/', ); /** * Create a new CreditCard object using the specified parameters * * @param array $parameters An array of parameters to set on the new object */ public function __construct($parameters = null) { $this->initialize($parameters); } /** * All known/supported card brands, and a regular expression to match them. * * Note: The fact that this class knows about a particular card brand does not imply * that your gateway supports it. * * @return array */ public function getSupportedBrands() { return $this->supported_cards; } /** * Set a custom supported card brand with a regular expression to match it. * * Note: The fact that a particular card is known does not imply that your * gateway supports it. * * Set $add_to_front to true if the key should be added to the front of the array * * @param string $name The name of the new supported brand. * @param string $expression The regular expression to check if a card is supported. * @return boolean success */ public function addSupportedBrand($name, $expression) { $known_brands = array_keys($this->supported_cards); if (in_array($name, $known_brands)) { return false; } $this->supported_cards[$name] = $expression; return true; } /** * Initialize the object with parameters. * * If any unknown parameters passed, they will be ignored. * * @param array $parameters An associative array of parameters * @return $this */ public function initialize(array $parameters = null) { $this->parameters = new ParameterBag; Helper::initialize($this, $parameters); return $this; } /** * Set the credit card year. * * The input value is normalised to a 4 digit number. * * @param string $key Parameter key, e.g. 'expiryYear' * @param mixed $value Parameter value * @return $this */ protected function setYearParameter($key, $value) { // normalize year to four digits if (null === $value || '' === $value) { $value = null; } else { $value = (int) gmdate('Y', gmmktime(0, 0, 0, 1, 1, (int) $value)); } return $this->setParameter($key, $value); } /** * Validate this credit card. If the card is invalid, InvalidCreditCardException is thrown. * * This method is called internally by gateways to avoid wasting time with an API call * when the credit card is clearly invalid. * * Generally if you want to validate the credit card yourself with custom error * messages, you should use your framework's validation library, not this method. * * @return void * @throws Exception\InvalidRequestException * @throws InvalidCreditCardException */ public function validate() { $requiredParameters = array( 'number' => 'credit card number', 'expiryMonth' => 'expiration month', 'expiryYear' => 'expiration year' ); foreach ($requiredParameters as $key => $val) { if (!$this->getParameter($key)) { throw new InvalidCreditCardException("The $val is required"); } } if ($this->getExpiryDate('Ym') < gmdate('Ym')) { throw new InvalidCreditCardException('Card has expired'); } if (!Helper::validateLuhn($this->getNumber())) { throw new InvalidCreditCardException('Card number is invalid'); } if (!is_null($this->getNumber()) && !preg_match('/^\d{12,19}$/i', $this->getNumber())) { throw new InvalidCreditCardException('Card number should have 12 to 19 digits'); } } /** * Get Card Title. * * @return string */ public function getTitle() { return $this->getBillingTitle(); } /** * Set Card Title. * * @param string $value Parameter value * @return $this */ public function setTitle($value) { $this->setBillingTitle($value); $this->setShippingTitle($value); return $this; } /** * Get Card First Name. * * @return string */ public function getFirstName() { return $this->getBillingFirstName(); } /** * Set Card First Name (Billing and Shipping). * * @param string $value Parameter value * @return $this */ public function setFirstName($value) { $this->setBillingFirstName($value); $this->setShippingFirstName($value); return $this; } /** * Get Card Last Name. * * @return string */ public function getLastName() { return $this->getBillingLastName(); } /** * Set Card Last Name (Billing and Shipping). * * @param string $value Parameter value * @return $this */ public function setLastName($value) { $this->setBillingLastName($value); $this->setShippingLastName($value); return $this; } /** * Get Card Name. * * @return string */ public function getName() { return $this->getBillingName(); } /** * Set Card Name (Billing and Shipping). * * @param string $value Parameter value * @return $this */ public function setName($value) { $this->setBillingName($value); $this->setShippingName($value); return $this; } /** * Get Card Number. * * @return string */ public function getNumber() { return $this->getParameter('number'); } /** * Set Card Number * * Non-numeric characters are stripped out of the card number, so * it's safe to pass in strings such as "4444-3333 2222 1111" etc. * * @param string $value Parameter value * @return $this */ public function setNumber($value) { // strip non-numeric characters return $this->setParameter('number', preg_replace('/\D/', '', $value)); } /** * Get the last 4 digits of the card number. * * @return string */ public function getNumberLastFour() { return substr($this->getNumber(), -4, 4) ?: null; } /** * Returns a masked credit card number with only the last 4 chars visible * * @param string $mask Character to use in place of numbers * @return string */ public function getNumberMasked($mask = 'X') { $maskLength = strlen($this->getNumber()) - 4; return str_repeat($mask, $maskLength) . $this->getNumberLastFour(); } /** * Credit Card Brand * * Iterates through known/supported card brands to determine the brand of this card * * @return string */ public function getBrand() { foreach ($this->getSupportedBrands() as $brand => $val) { if (preg_match($val, $this->getNumber())) { return $brand; } } } /** * Get the card expiry month. * * @return int */ public function getExpiryMonth() { return $this->getParameter('expiryMonth'); } /** * Sets the card expiry month. * * @param string $value * @return $this */ public function setExpiryMonth($value) { return $this->setParameter('expiryMonth', (int) $value); } /** * Get the card expiry year. * * @return int */ public function getExpiryYear() { return $this->getParameter('expiryYear'); } /** * Sets the card expiry year. * * @param string $value * @return $this */ public function setExpiryYear($value) { return $this->setYearParameter('expiryYear', $value); } /** * Get the card expiry date, using the specified date format string. * * @param string $format * * @return string */ public function getExpiryDate($format) { return gmdate($format, gmmktime(0, 0, 0, $this->getExpiryMonth(), 1, $this->getExpiryYear())); } /** * Get the card start month. * * @return string */ public function getStartMonth() { return $this->getParameter('startMonth'); } /** * Sets the card start month. * * @param string $value * @return $this */ public function setStartMonth($value) { return $this->setParameter('startMonth', (int) $value); } /** * Get the card start year. * * @return int */ public function getStartYear() { return $this->getParameter('startYear'); } /** * Sets the card start year. * * @param string $value * @return $this */ public function setStartYear($value) { return $this->setYearParameter('startYear', $value); } /** * Get the card start date, using the specified date format string * * @param string $format * * @return string */ public function getStartDate($format) { return gmdate($format, gmmktime(0, 0, 0, $this->getStartMonth(), 1, $this->getStartYear())); } /** * Get the card CVV. * * @return string */ public function getCvv() { return $this->getParameter('cvv'); } /** * Sets the card CVV. * * @param string $value * @return $this */ public function setCvv($value) { return $this->setParameter('cvv', $value); } /** * Get raw data for all tracks on the credit card magnetic strip. * * @return string */ public function getTracks() { return $this->getParameter('tracks'); } /** * Get raw data for track 1 on the credit card magnetic strip. * * @return string|null */ public function getTrack1() { return $this->getTrackByPattern('/\%B\d{1,19}\^.{2,26}\^\d{4}\d*\?/'); } /** * Get raw data for track 2 on the credit card magnetic strip. * * @return string|null */ public function getTrack2() { return $this->getTrackByPattern('/;\d{1,19}=\d{4}\d*\?/'); } /** * Get raw data for a track on the credit card magnetic strip based on the pattern for track 1 or 2. * * @param $pattern * @return string|null */ protected function getTrackByPattern($pattern) { if ($tracks = $this->getTracks()) { if (preg_match($pattern, $tracks, $matches) === 1) { return $matches[0]; } } } /** * Sets raw data from all tracks on the credit card magnetic strip. Used by gateways that support card-present * transactions. * * @param $value * @return $this */ public function setTracks($value) { return $this->setParameter('tracks', $value); } /** * Get the card issue number. * * @return string */ public function getIssueNumber() { return $this->getParameter('issueNumber'); } /** * Sets the card issue number. * * @param string $value * @return $this */ public function setIssueNumber($value) { return $this->setParameter('issueNumber', $value); } /** * Get the card billing title. * * @return string */ public function getBillingTitle() { return $this->getParameter('billingTitle'); } /** * Sets the card billing title. * * @param string $value * @return $this */ public function setBillingTitle($value) { return $this->setParameter('billingTitle', $value); } /** * Get the card billing name. * * @return string */ public function getBillingName() { return trim($this->getBillingFirstName() . ' ' . $this->getBillingLastName()); } /** * Split the full name in the first and last name. * * @param $fullName * @return array with first and lastname */ protected function listFirstLastName($fullName) { $names = explode(' ', $fullName, 2); return [$names[0], isset($names[1]) ? $names[1] : null]; } /** * Sets the card billing name. * * @param string $value * @return $this */ public function setBillingName($value) { $names = $this->listFirstLastName($value); $this->setBillingFirstName($names[0]); $this->setBillingLastName($names[1]); return $this; } /** * Get the first part of the card billing name. * * @return string */ public function getBillingFirstName() { return $this->getParameter('billingFirstName'); } /** * Sets the first part of the card billing name. * * @param string $value * @return $this */ public function setBillingFirstName($value) { return $this->setParameter('billingFirstName', $value); } /** * Get the last part of the card billing name. * * @return string */ public function getBillingLastName() { return $this->getParameter('billingLastName'); } /** * Sets the last part of the card billing name. * * @param string $value * @return $this */ public function setBillingLastName($value) { return $this->setParameter('billingLastName', $value); } /** * Get the billing company name. * * @return string */ public function getBillingCompany() { return $this->getParameter('billingCompany'); } /** * Sets the billing company name. * * @param string $value * @return $this */ public function setBillingCompany($value) { return $this->setParameter('billingCompany', $value); } /** * Get the billing address, line 1. * * @return string */ public function getBillingAddress1() { return $this->getParameter('billingAddress1'); } /** * Sets the billing address, line 1. * * @param string $value * @return $this */ public function setBillingAddress1($value) { return $this->setParameter('billingAddress1', $value); } /** * Get the billing address, line 2. * * @return string */ public function getBillingAddress2() { return $this->getParameter('billingAddress2'); } /** * Sets the billing address, line 2. * * @param string $value * @return $this */ public function setBillingAddress2($value) { return $this->setParameter('billingAddress2', $value); } /** * Get the billing city. * * @return string */ public function getBillingCity() { return $this->getParameter('billingCity'); } /** * Sets billing city. * * @param string $value * @return $this */ public function setBillingCity($value) { return $this->setParameter('billingCity', $value); } /** * Get the billing postcode. * * @return string */ public function getBillingPostcode() { return $this->getParameter('billingPostcode'); } /** * Sets the billing postcode. * * @param string $value * @return $this */ public function setBillingPostcode($value) { return $this->setParameter('billingPostcode', $value); } /** * Get the billing state. * * @return string */ public function getBillingState() { return $this->getParameter('billingState'); } /** * Sets the billing state. * * @param string $value * @return $this */ public function setBillingState($value) { return $this->setParameter('billingState', $value); } /** * Get the billing country name. * * @return string */ public function getBillingCountry() { return $this->getParameter('billingCountry'); } /** * Sets the billing country name. * * @param string $value * @return $this */ public function setBillingCountry($value) { return $this->setParameter('billingCountry', $value); } /** * Get the billing phone number. * * @return string */ public function getBillingPhone() { return $this->getParameter('billingPhone'); } /** * Sets the billing phone number. * * @param string $value * @return $this */ public function setBillingPhone($value) { return $this->setParameter('billingPhone', $value); } /** * Get the billing phone number extension. * * @return string */ public function getBillingPhoneExtension() { return $this->getParameter('billingPhoneExtension'); } /** * Sets the billing phone number extension. * * @param string $value * @return $this */ public function setBillingPhoneExtension($value) { return $this->setParameter('billingPhoneExtension', $value); } /** * Get the billing fax number. * * @return string */ public function getBillingFax() { return $this->getParameter('billingFax'); } /** * Sets the billing fax number. * * @param string $value * @return $this */ public function setBillingFax($value) { return $this->setParameter('billingFax', $value); } /** * Get the title of the card shipping name. * * @return string */ public function getShippingTitle() { return $this->getParameter('shippingTitle'); } /** * Sets the title of the card shipping name. * * @param string $value * @return $this */ public function setShippingTitle($value) { return $this->setParameter('shippingTitle', $value); } /** * Get the card shipping name. * * @return string */ public function getShippingName() { return trim($this->getShippingFirstName() . ' ' . $this->getShippingLastName()); } /** * Sets the card shipping name. * * @param string $value * @return $this */ public function setShippingName($value) { $names = $this->listFirstLastName($value); $this->setShippingFirstName($names[0]); $this->setShippingLastName($names[1]); return $this; } /** * Get the first part of the card shipping name. * * @return string */ public function getShippingFirstName() { return $this->getParameter('shippingFirstName'); } /** * Sets the first part of the card shipping name. * * @param string $value * @return $this */ public function setShippingFirstName($value) { return $this->setParameter('shippingFirstName', $value); } /** * Get the last part of the card shipping name. * * @return string */ public function getShippingLastName() { return $this->getParameter('shippingLastName'); } /** * Sets the last part of the card shipping name. * * @param string $value * @return $this */ public function setShippingLastName($value) { return $this->setParameter('shippingLastName', $value); } /** * Get the shipping company name. * * @return string */ public function getShippingCompany() { return $this->getParameter('shippingCompany'); } /** * Sets the shipping company name. * * @param string $value * @return $this */ public function setShippingCompany($value) { return $this->setParameter('shippingCompany', $value); } /** * Get the shipping address, line 1. * * @return string */ public function getShippingAddress1() { return $this->getParameter('shippingAddress1'); } /** * Sets the shipping address, line 1. * * @param string $value * @return $this */ public function setShippingAddress1($value) { return $this->setParameter('shippingAddress1', $value); } /** * Get the shipping address, line 2. * * @return string */ public function getShippingAddress2() { return $this->getParameter('shippingAddress2'); } /** * Sets the shipping address, line 2. * * @param string $value * @return $this */ public function setShippingAddress2($value) { return $this->setParameter('shippingAddress2', $value); } /** * Get the shipping city. * * @return string */ public function getShippingCity() { return $this->getParameter('shippingCity'); } /** * Sets the shipping city. * * @param string $value * @return $this */ public function setShippingCity($value) { return $this->setParameter('shippingCity', $value); } /** * Get the shipping postcode. * * @return string */ public function getShippingPostcode() { return $this->getParameter('shippingPostcode'); } /** * Sets the shipping postcode. * * @param string $value * @return $this */ public function setShippingPostcode($value) { return $this->setParameter('shippingPostcode', $value); } /** * Get the shipping state. * * @return string */ public function getShippingState() { return $this->getParameter('shippingState'); } /** * Sets the shipping state. * * @param string $value * @return $this */ public function setShippingState($value) { return $this->setParameter('shippingState', $value); } /** * Get the shipping country. * * @return string */ public function getShippingCountry() { return $this->getParameter('shippingCountry'); } /** * Sets the shipping country. * * @param string $value * @return $this */ public function setShippingCountry($value) { return $this->setParameter('shippingCountry', $value); } /** * Get the shipping phone number. * * @return string */ public function getShippingPhone() { return $this->getParameter('shippingPhone'); } /** * Sets the shipping phone number. * * @param string $value * @return $this */ public function setShippingPhone($value) { return $this->setParameter('shippingPhone', $value); } /** * Get the shipping phone number extension. * * @return string */ public function getShippingPhoneExtension() { return $this->getParameter('shippingPhoneExtension'); } /** * Sets the shipping phone number extension. * * @param string $value * @return $this */ public function setShippingPhoneExtension($value) { return $this->setParameter('shippingPhoneExtension', $value); } /** * Get the shipping fax number. * * @return string */ public function getShippingFax() { return $this->getParameter('shippingFax'); } /** * Sets the shipping fax number. * * @param string $value * @return $this */ public function setShippingFax($value) { return $this->setParameter('shippingFax', $value); } /** * Get the billing address, line 1. * * @return string */ public function getAddress1() { return $this->getParameter('billingAddress1'); } /** * Sets the billing and shipping address, line 1. * * @param string $value * @return $this */ public function setAddress1($value) { $this->setParameter('billingAddress1', $value); $this->setParameter('shippingAddress1', $value); return $this; } /** * Get the billing address, line 2. * * @return string */ public function getAddress2() { return $this->getParameter('billingAddress2'); } /** * Sets the billing and shipping address, line 2. * * @param string $value * @return $this */ public function setAddress2($value) { $this->setParameter('billingAddress2', $value); $this->setParameter('shippingAddress2', $value); return $this; } /** * Get the billing city. * * @return string */ public function getCity() { return $this->getParameter('billingCity'); } /** * Sets the billing and shipping city. * * @param string $value * @return $this */ public function setCity($value) { $this->setParameter('billingCity', $value); $this->setParameter('shippingCity', $value); return $this; } /** * Get the billing postcode. * * @return string */ public function getPostcode() { return $this->getParameter('billingPostcode'); } /** * Sets the billing and shipping postcode. * * @param string $value * @return $this */ public function setPostcode($value) { $this->setParameter('billingPostcode', $value); $this->setParameter('shippingPostcode', $value); return $this; } /** * Get the billing state. * * @return string */ public function getState() { return $this->getParameter('billingState'); } /** * Sets the billing and shipping state. * * @param string $value * @return $this */ public function setState($value) { $this->setParameter('billingState', $value); $this->setParameter('shippingState', $value); return $this; } /** * Get the billing country. * * @return string */ public function getCountry() { return $this->getParameter('billingCountry'); } /** * Sets the billing and shipping country. * * @param string $value * @return $this */ public function setCountry($value) { $this->setParameter('billingCountry', $value); $this->setParameter('shippingCountry', $value); return $this; } /** * Get the billing phone number. * * @return string */ public function getPhone() { return $this->getParameter('billingPhone'); } /** * Sets the billing and shipping phone number. * * @param string $value * @return $this */ public function setPhone($value) { $this->setParameter('billingPhone', $value); $this->setParameter('shippingPhone', $value); return $this; } /** * Get the billing phone number extension. * * @return string */ public function getPhoneExtension() { return $this->getParameter('billingPhoneExtension'); } /** * Sets the billing and shipping phone number extension. * * @param string $value * @return $this */ public function setPhoneExtension($value) { $this->setParameter('billingPhoneExtension', $value); $this->setParameter('shippingPhoneExtension', $value); return $this; } /** * Get the billing fax number.. * * @return string */ public function getFax() { return $this->getParameter('billingFax'); } /** * Sets the billing and shipping fax number. * * @param string $value * @return $this */ public function setFax($value) { $this->setParameter('billingFax', $value); $this->setParameter('shippingFax', $value); return $this; } /** * Get the card billing company name. * * @return string */ public function getCompany() { return $this->getParameter('billingCompany'); } /** * Sets the billing and shipping company name. * * @param string $value * @return $this */ public function setCompany($value) { $this->setParameter('billingCompany', $value); $this->setParameter('shippingCompany', $value); return $this; } /** * Get the cardholder's email address. * * @return string */ public function getEmail() { return $this->getParameter('email'); } /** * Sets the cardholder's email address. * * @param string $value * @return $this */ public function setEmail($value) { return $this->setParameter('email', $value); } /** * Get the cardholder's birthday. * * @return string */ public function getBirthday($format = 'Y-m-d') { $value = $this->getParameter('birthday'); return $value ? $value->format($format) : null; } /** * Sets the cardholder's birthday. * * @param string $value * @return $this */ public function setBirthday($value) { if ($value) { $value = new DateTime($value, new DateTimeZone('UTC')); } else { $value = null; } return $this->setParameter('birthday', $value); } /** * Get the cardholder's gender. * * @return string */ public function getGender() { return $this->getParameter('gender'); } /** * Sets the cardholder's gender. * * @param string $value * @return $this */ public function setGender($value) { return $this->setParameter('gender', $value); } } src/Common/ItemInterface.php 0000644 00000001034 15111334703 0012007 0 ustar 00 <?php /** * Cart Item interface */ namespace Omnipay\Common; /** * Cart Item interface * * This interface defines the functionality that all cart items in * the Omnipay system are to have. */ interface ItemInterface { /** * Name of the item */ public function getName(); /** * Description of the item */ public function getDescription(); /** * Quantity of the item */ public function getQuantity(); /** * Price of the item */ public function getPrice(); } src/Common/Helper.php 0000644 00000010615 15111334703 0010514 0 ustar 00 <?php /** * Helper class */ namespace Omnipay\Common; use InvalidArgumentException; /** * Helper class * * This class defines various static utility functions that are in use * throughout the Omnipay system. */ class Helper { /** * Convert a string to camelCase. Strings already in camelCase will not be harmed. * * @param string $str The input string * @return string camelCased output string */ public static function camelCase($str) { $str = self::convertToLowercase($str); return preg_replace_callback( '/_([a-z])/', function ($match) { return strtoupper($match[1]); }, $str ); } /** * Convert strings with underscores to be all lowercase before camelCase is preformed. * * @param string $str The input string * @return string The output string */ protected static function convertToLowercase($str) { $explodedStr = explode('_', $str); $lowercasedStr = []; if (count($explodedStr) > 1) { foreach ($explodedStr as $value) { $lowercasedStr[] = strtolower($value); } $str = implode('_', $lowercasedStr); } return $str; } /** * Validate a card number according to the Luhn algorithm. * * @param string $number The card number to validate * @return boolean True if the supplied card number is valid */ public static function validateLuhn($number) { $str = ''; foreach (array_reverse(str_split($number)) as $i => $c) { $str .= $i % 2 ? $c * 2 : $c; } return array_sum(str_split($str)) % 10 === 0; } /** * Initialize an object with a given array of parameters * * Parameters are automatically converted to camelCase. Any parameters which do * not match a setter on the target object are ignored. * * @param mixed $target The object to set parameters on * @param array $parameters An array of parameters to set */ public static function initialize($target, array $parameters = null) { if ($parameters) { foreach ($parameters as $key => $value) { $method = 'set'.ucfirst(static::camelCase($key)); if (method_exists($target, $method)) { $target->$method($value); } } } } /** * Resolve a gateway class to a short name. * * The short name can be used with GatewayFactory as an alias of the gateway class, * to create new instances of a gateway. */ public static function getGatewayShortName($className) { if (0 === strpos($className, '\\')) { $className = substr($className, 1); } if (0 === strpos($className, 'Omnipay\\')) { return trim(str_replace('\\', '_', substr($className, 8, -7)), '_'); } return '\\'.$className; } /** * Resolve a short gateway name to a full namespaced gateway class. * * Class names beginning with a namespace marker (\) are left intact. * Non-namespaced classes are expected to be in the \Omnipay namespace, e.g.: * * \Custom\Gateway => \Custom\Gateway * \Custom_Gateway => \Custom_Gateway * Stripe => \Omnipay\Stripe\Gateway * PayPal\Express => \Omnipay\PayPal\ExpressGateway * PayPal_Express => \Omnipay\PayPal\ExpressGateway * * @param string $shortName The short gateway name or the FQCN * @return string The fully namespaced gateway class name */ public static function getGatewayClassName($shortName) { // If the class starts with \ or Omnipay\, assume it's a FQCN if (0 === strpos($shortName, '\\') || 0 === strpos($shortName, 'Omnipay\\')) { return $shortName; } // Check if the class exists and implements the Gateway Interface, if so -> FCQN if (is_subclass_of($shortName, GatewayInterface::class, true)) { return $shortName; } // replace underscores with namespace marker, PSR-0 style $shortName = str_replace('_', '\\', $shortName); if (false === strpos($shortName, '\\')) { $shortName .= '\\'; } return '\\Omnipay\\'.$shortName.'Gateway'; } } src/Common/ParametersTrait.php 0000644 00000003727 15111334703 0012412 0 ustar 00 <?php namespace Omnipay\Common; use Omnipay\Common\Exception\InvalidRequestException; use Symfony\Component\HttpFoundation\ParameterBag; trait ParametersTrait { /** * Internal storage of all of the parameters. * * @var ParameterBag */ protected $parameters; /** * Set one parameter. * * @param string $key Parameter key * @param mixed $value Parameter value * @return $this */ protected function setParameter($key, $value) { $this->parameters->set($key, $value); return $this; } /** * Get one parameter. * * @param string $key Parameter key * @return mixed A single parameter value. */ protected function getParameter($key) { return $this->parameters->get($key); } /** * Get all parameters. * * @return array An associative array of parameters. */ public function getParameters() { return $this->parameters->all(); } /** * Initialize the object with parameters. * * If any unknown parameters passed, they will be ignored. * * @param array $parameters An associative array of parameters * @return $this. */ public function initialize(array $parameters = []) { $this->parameters = new ParameterBag; Helper::initialize($this, $parameters); return $this; } /** * Validate the request. * * This method is called internally by gateways to avoid wasting time with an API call * when the request is clearly invalid. * * @param string ... a variable length list of required parameters * @throws InvalidRequestException */ public function validate(...$args) { foreach ($args as $key) { $value = $this->parameters->get($key); if (! isset($value)) { throw new InvalidRequestException("The $key parameter is required"); } } } } src/Common/Http/Client.php 0000644 00000004276 15111334703 0011440 0 ustar 00 <?php namespace Omnipay\Common\Http; use function GuzzleHttp\Psr7\str; use Http\Client\HttpClient; use Http\Discovery\HttpClientDiscovery; use Http\Discovery\MessageFactoryDiscovery; use Http\Message\RequestFactory; use Omnipay\Common\Http\Exception\NetworkException; use Omnipay\Common\Http\Exception\RequestException; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; class Client implements ClientInterface { /** * The Http Client which implements `public function sendRequest(RequestInterface $request)` * Note: Will be changed to PSR-18 when released * * @var HttpClient */ private $httpClient; /** * @var RequestFactory */ private $requestFactory; public function __construct($httpClient = null, RequestFactory $requestFactory = null) { $this->httpClient = $httpClient ?: HttpClientDiscovery::find(); $this->requestFactory = $requestFactory ?: MessageFactoryDiscovery::find(); } /** * @param $method * @param $uri * @param array $headers * @param string|array|resource|StreamInterface|null $body * @param string $protocolVersion * @return ResponseInterface * @throws \Http\Client\Exception */ public function request( $method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1' ) { $request = $this->requestFactory->createRequest($method, $uri, $headers, $body, $protocolVersion); return $this->sendRequest($request); } /** * @param RequestInterface $request * @return ResponseInterface * @throws \Http\Client\Exception */ private function sendRequest(RequestInterface $request) { try { return $this->httpClient->sendRequest($request); } catch (\Http\Client\Exception\NetworkException $networkException) { throw new NetworkException($networkException->getMessage(), $request, $networkException); } catch (\Exception $exception) { throw new RequestException($exception->getMessage(), $request, $exception); } } } src/Common/Http/Exception.php 0000644 00000001235 15111334703 0012150 0 ustar 00 <?php namespace Omnipay\Common\Http; use Psr\Http\Message\RequestInterface; use Throwable; abstract class Exception extends \RuntimeException { /** @var RequestInterface */ protected $request; public function __construct($message, RequestInterface $request, $previous = null) { $this->request = $request; parent::__construct($message, 0, $previous); } /** * Returns the request. * * The request object MAY be a different object from the one passed to ClientInterface::sendRequest() * * @return RequestInterface */ public function getRequest() { return $this->request; } } src/Common/Http/ClientInterface.php 0000644 00000002047 15111334703 0013253 0 ustar 00 <?php namespace Omnipay\Common\Http; use Omnipay\Common\Http\Exception\NetworkException; use Omnipay\Common\Http\Exception\RequestException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; interface ClientInterface { /** * Creates a new PSR-7 request. * * @param string $method * @param string|UriInterface $uri * @param array $headers * @param resource|string|StreamInterface|null $body * @param string $protocolVersion * * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent. * @throws NetworkException if there is an error with the network or the remote server cannot be reached. * * @return ResponseInterface */ public function request( $method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1' ); } src/Common/Http/Exception/RequestException.php 0000644 00000000202 15111334703 0015450 0 ustar 00 <?php namespace Omnipay\Common\Http\Exception; use Omnipay\Common\Http\Exception; class RequestException extends Exception { } src/Common/Http/Exception/NetworkException.php 0000644 00000000202 15111334703 0015451 0 ustar 00 <?php namespace Omnipay\Common\Http\Exception; use Omnipay\Common\Http\Exception; class NetworkException extends Exception { } src/Common/Message/AbstractResponse.php 0000644 00000013450 15111334703 0014143 0 ustar 00 <?php /** * Abstract Response */ namespace Omnipay\Common\Message; use Omnipay\Common\Exception\RuntimeException; use Symfony\Component\HttpFoundation\RedirectResponse as HttpRedirectResponse; use Symfony\Component\HttpFoundation\Response as HttpResponse; /** * Abstract Response * * This abstract class implements ResponseInterface and defines a basic * set of functions that all Omnipay Requests are intended to include. * * Objects of this class or a subclass are usually created in the Request * object (subclass of AbstractRequest) as the return parameters from the * send() function. * * Example -- validating and sending a request: * * <code> * $myResponse = $myRequest->send(); * // now do something with the $myResponse object, test for success, etc. * </code> * */ abstract class AbstractResponse implements ResponseInterface { /** * The embodied request object. * * @var RequestInterface */ protected $request; /** * The data contained in the response. * * @var mixed */ protected $data; /** * Constructor * * @param RequestInterface $request the initiating request. * @param mixed $data */ public function __construct(RequestInterface $request, $data) { $this->request = $request; $this->data = $data; } /** * Get the initiating request object. * * @return RequestInterface */ public function getRequest() { return $this->request; } /** * Is the response successful? * * @return boolean */ public function isPending() { return false; } /** * Does the response require a redirect? * * @return boolean */ public function isRedirect() { return false; } /** * Is the response a transparent redirect? * * @return boolean */ public function isTransparentRedirect() { return false; } /** * Is the transaction cancelled by the user? * * @return boolean */ public function isCancelled() { return false; } /** * Get the response data. * * @return mixed */ public function getData() { return $this->data; } /** * Response Message * * @return null|string A response message from the payment gateway */ public function getMessage() { return null; } /** * Response code * * @return null|string A response code from the payment gateway */ public function getCode() { return null; } /** * Gateway Reference * * @return null|string A reference provided by the gateway to represent this transaction */ public function getTransactionReference() { return null; } /** * Get the transaction ID as generated by the merchant website. * * @return string */ public function getTransactionId() { return null; } /** * Gets the redirect target url. * * @return string */ public function getRedirectUrl() { return null; } /** * Get the required redirect method (either GET or POST). * * @return string */ public function getRedirectMethod() { return 'GET'; } /** * Gets the redirect form data array, if the redirect method is POST. * * @return array */ public function getRedirectData() { return []; } /** * Automatically perform any required redirect * * This method is meant to be a helper for simple scenarios. If you want to customize the * redirection page, just call the getRedirectUrl() and getRedirectData() methods directly. * * @return void */ public function redirect() { $this->getRedirectResponse()->send(); } /** * @return HttpRedirectResponse|HttpResponse */ public function getRedirectResponse() { $this->validateRedirect(); if ('GET' === $this->getRedirectMethod()) { return new HttpRedirectResponse($this->getRedirectUrl()); } $hiddenFields = ''; foreach ($this->getRedirectData() as $key => $value) { $hiddenFields .= sprintf( '<input type="hidden" name="%1$s" value="%2$s" />', htmlentities($key, ENT_QUOTES, 'UTF-8', false), htmlentities($value, ENT_QUOTES, 'UTF-8', false) )."\n"; } $output = '<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Redirecting...</title> </head> <body onload="document.forms[0].submit();"> <form action="%1$s" method="post"> <p>Redirecting to payment page...</p> <p> %2$s <input type="submit" value="Continue" /> </p> </form> </body> </html>'; $output = sprintf( $output, htmlentities($this->getRedirectUrl(), ENT_QUOTES, 'UTF-8', false), $hiddenFields ); return new HttpResponse($output); } /** * Validate that the current Response is a valid redirect. * * @return void */ protected function validateRedirect() { if (!$this instanceof RedirectResponseInterface || !$this->isRedirect()) { throw new RuntimeException('This response does not support redirection.'); } if (empty($this->getRedirectUrl())) { throw new RuntimeException('The given redirectUrl cannot be empty.'); } if (!in_array($this->getRedirectMethod(), ['GET', 'POST'])) { throw new RuntimeException('Invalid redirect method "'.$this->getRedirectMethod().'".'); } } } src/Common/Message/MessageInterface.php 0000644 00000000775 15111334703 0014074 0 ustar 00 <?php /** * Message Interface */ namespace Omnipay\Common\Message; /** * Message Interface * * This interface class defines the standard functions that any Omnipay message * interface needs to be able to provide. */ interface MessageInterface { /** * Get the raw data array for this message. The format of this varies from gateway to * gateway, but will usually be either an associative array, or a SimpleXMLElement. * * @return mixed */ public function getData(); } src/Common/Message/ResponseInterface.php 0000644 00000002475 15111334703 0014305 0 ustar 00 <?php /** * Response interface */ namespace Omnipay\Common\Message; /** * Response Interface * * This interface class defines the standard functions that any Omnipay response * interface needs to be able to provide. It is an extension of MessageInterface. * */ interface ResponseInterface extends MessageInterface { /** * Get the original request which generated this response * * @return RequestInterface */ public function getRequest(); /** * Is the response successful? * * @return boolean */ public function isSuccessful(); /** * Does the response require a redirect? * * @return boolean */ public function isRedirect(); /** * Is the transaction cancelled by the user? * * @return boolean */ public function isCancelled(); /** * Response Message * * @return null|string A response message from the payment gateway */ public function getMessage(); /** * Response code * * @return null|string A response code from the payment gateway */ public function getCode(); /** * Gateway Reference * * @return null|string A reference provided by the gateway to represent this transaction */ public function getTransactionReference(); } src/Common/Message/NotificationInterface.php 0000644 00000001574 15111334703 0015134 0 ustar 00 <?php namespace Omnipay\Common\Message; /** * Incoming notification */ interface NotificationInterface extends MessageInterface { const STATUS_COMPLETED = 'completed'; const STATUS_PENDING = 'pending'; const STATUS_FAILED = 'failed'; /** * Gateway Reference * * @return string A reference provided by the gateway to represent this transaction */ public function getTransactionReference(); /** * Was the transaction successful? * * @return string Transaction status, one of {@link NotificationInterface::STATUS_COMPLETED}, * {@link NotificationInterface::STATUS_PENDING}, or {@link NotificationInterface::STATUS_FAILED}. */ public function getTransactionStatus(); /** * Response Message * * @return string A response message from the payment gateway */ public function getMessage(); } src/Common/Message/FetchIssuersResponseInterface.php 0000644 00000001370 15111334703 0016626 0 ustar 00 <?php /** * Fetch Issuers Response interface */ namespace Omnipay\Common\Message; /** * Fetch Issuers Response interface * * This interface class defines the functionality of a response * that is a "fetch issuers" response. It extends the ResponseInterface * interface class with some extra functions relating to the * specifics of a response to fetch the issuers from the gateway. * This happens when the gateway needs the customer to choose a * card issuer. * */ interface FetchIssuersResponseInterface extends ResponseInterface { /** * Get the returned list of issuers. * * These represent banks which the user must choose between. * * @return \Omnipay\Common\Issuer[] */ public function getIssuers(); } src/Common/Message/RedirectResponseInterface.php 0000644 00000001722 15111334703 0015761 0 ustar 00 <?php /** * Redirect Response interface */ namespace Omnipay\Common\Message; /** * Redirect Response interface * * This interface class defines the functionality of a response * that is a redirect response. It extends the ResponseInterface * interface class with some extra functions relating to the * specifics of a redirect response from the gateway. * */ interface RedirectResponseInterface extends ResponseInterface { /** * Gets the redirect target url. * * @return string */ public function getRedirectUrl(); /** * Get the required redirect method (either GET or POST). * * @return string */ public function getRedirectMethod(); /** * Gets the redirect form data array, if the redirect method is POST. * * @return array */ public function getRedirectData(); /** * Perform the required redirect. * * @return void */ public function redirect(); } src/Common/Message/AbstractRequest.php 0000644 00000037773 15111334703 0014013 0 ustar 00 <?php /** * Abstract Request */ namespace Omnipay\Common\Message; use Money\Currencies\ISOCurrencies; use Money\Currency; use Money\Formatter\DecimalMoneyFormatter; use Money\Money; use Money\Number; use Money\Parser\DecimalMoneyParser; use Omnipay\Common\CreditCard; use Omnipay\Common\Exception\InvalidRequestException; use Omnipay\Common\Exception\RuntimeException; use Omnipay\Common\Helper; use Omnipay\Common\Http\Client; use Omnipay\Common\Http\ClientInterface; use Omnipay\Common\ItemBag; use Omnipay\Common\ParametersTrait; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request as HttpRequest; /** * Abstract Request * * This abstract class implements RequestInterface and defines a basic * set of functions that all Omnipay Requests are intended to include. * * Requests of this class are usually created using the createRequest * function of the gateway and then actioned using methods within this * class or a class that extends this class. * * Example -- creating a request: * * <code> * class MyRequest extends \Omnipay\Common\Message\AbstractRequest {}; * * class MyGateway extends \Omnipay\Common\AbstractGateway { * function myRequest($parameters) { * $this->createRequest('MyRequest', $parameters); * } * } * * // Create the gateway object * $gw = Omnipay::create('MyGateway'); * * // Create the request object * $myRequest = $gw->myRequest($someParameters); * </code> * * Example -- validating and sending a request: * * <code> * try { * $myRequest->validate(); * $myResponse = $myRequest->send(); * } catch (InvalidRequestException $e) { * print "Something went wrong: " . $e->getMessage() . "\n"; * } * // now do something with the $myResponse object, test for success, etc. * </code> * */ abstract class AbstractRequest implements RequestInterface { use ParametersTrait { setParameter as traitSetParameter; } /** * The request client. * * @var ClientInterface */ protected $httpClient; /** * The HTTP request object. * * @var \Symfony\Component\HttpFoundation\Request */ protected $httpRequest; /** * An associated ResponseInterface. * * @var ResponseInterface */ protected $response; /** * @var ISOCurrencies */ protected $currencies; /** * @var bool */ protected $zeroAmountAllowed = true; /** * @var bool */ protected $negativeAmountAllowed = false; /** * Create a new Request * * @param ClientInterface $httpClient A HTTP client to make API calls with * @param HttpRequest $httpRequest A Symfony HTTP request object */ public function __construct(ClientInterface $httpClient, HttpRequest $httpRequest) { $this->httpClient = $httpClient; $this->httpRequest = $httpRequest; $this->initialize(); } /** * Initialize the object with parameters. * * If any unknown parameters passed, they will be ignored. * * @param array $parameters An associative array of parameters * * @return $this * @throws RuntimeException */ public function initialize(array $parameters = array()) { if (null !== $this->response) { throw new RuntimeException('Request cannot be modified after it has been sent!'); } $this->parameters = new ParameterBag; Helper::initialize($this, $parameters); return $this; } /** * Set a single parameter * * @param string $key The parameter key * @param mixed $value The value to set * @return $this * @throws RuntimeException if a request parameter is modified after the request has been sent. */ protected function setParameter($key, $value) { if (null !== $this->response) { throw new RuntimeException('Request cannot be modified after it has been sent!'); } return $this->traitSetParameter($key, $value); } /** * Gets the test mode of the request from the gateway. * * @return boolean */ public function getTestMode() { return $this->getParameter('testMode'); } /** * Sets the test mode of the request. * * @param boolean $value True for test mode on. * @return $this */ public function setTestMode($value) { return $this->setParameter('testMode', $value); } /** * Get the card. * * @return CreditCard */ public function getCard() { return $this->getParameter('card'); } /** * Sets the card. * * @param CreditCard $value * @return $this */ public function setCard($value) { if ($value && !$value instanceof CreditCard) { $value = new CreditCard($value); } return $this->setParameter('card', $value); } /** * Get the card token. * * @return string */ public function getToken() { return $this->getParameter('token'); } /** * Sets the card token. * * @param string $value * @return $this */ public function setToken($value) { return $this->setParameter('token', $value); } /** * Get the card reference. * * @return string */ public function getCardReference() { return $this->getParameter('cardReference'); } /** * Sets the card reference. * * @param string $value * @return $this */ public function setCardReference($value) { return $this->setParameter('cardReference', $value); } /** * @return ISOCurrencies */ protected function getCurrencies() { if ($this->currencies === null) { $this->currencies = new ISOCurrencies(); } return $this->currencies; } /** * @param string|int|null $amount * @return null|Money * @throws InvalidRequestException */ private function getMoney($amount = null) { $currencyCode = $this->getCurrency() ?: 'USD'; $currency = new Currency($currencyCode); $amount = $amount !== null ? $amount : $this->getParameter('amount'); if ($amount === null) { return null; } elseif ($amount instanceof Money) { $money = $amount; } elseif (is_integer($amount)) { $money = new Money($amount, $currency); } else { $moneyParser = new DecimalMoneyParser($this->getCurrencies()); $number = Number::fromString($amount); // Check for rounding that may occur if too many significant decimal digits are supplied. $decimal_count = strlen($number->getFractionalPart()); $subunit = $this->getCurrencies()->subunitFor($currency); if ($decimal_count > $subunit) { throw new InvalidRequestException('Amount precision is too high for currency.'); } $money = $moneyParser->parse((string) $number, $currency); } // Check for a negative amount. if (!$this->negativeAmountAllowed && $money->isNegative()) { throw new InvalidRequestException('A negative amount is not allowed.'); } // Check for a zero amount. if (!$this->zeroAmountAllowed && $money->isZero()) { throw new InvalidRequestException('A zero amount is not allowed.'); } return $money; } /** * Validates and returns the formatted amount. * * @throws InvalidRequestException on any validation failure. * @return string The amount formatted to the correct number of decimal places for the selected currency. */ public function getAmount() { $money = $this->getMoney(); if ($money !== null) { $moneyFormatter = new DecimalMoneyFormatter($this->getCurrencies()); return $moneyFormatter->format($money); } } /** * Sets the payment amount. * * @param string|null $value * @return $this */ public function setAmount($value) { return $this->setParameter('amount', $value !== null ? (string) $value : null); } /** * Get the payment amount as an integer. * * @return integer */ public function getAmountInteger() { $money = $this->getMoney(); if ($money !== null) { return (int) $money->getAmount(); } } /** * Sets the payment amount as integer. * * @param int $value * @return $this */ public function setAmountInteger($value) { return $this->setParameter('amount', (int) $value); } /** * Sets the payment amount as integer. * * @param Money $value * @return $this */ public function setMoney(Money $value) { $currency = $value->getCurrency()->getCode(); $this->setCurrency($currency); return $this->setParameter('amount', $value); } /** * Get the payment currency code. * * @return string */ public function getCurrency() { return $this->getParameter('currency'); } /** * Sets the payment currency code. * * @param string $value * @return $this */ public function setCurrency($value) { if ($value !== null) { $value = strtoupper($value); } return $this->setParameter('currency', $value); } /** * Get the payment currency number. * * @return string|null */ public function getCurrencyNumeric() { if (! $this->getCurrency()) { return null; } $currency = new Currency($this->getCurrency()); if ($this->getCurrencies()->contains($currency)) { return (string) $this->getCurrencies()->numericCodeFor($currency); } } /** * Get the number of decimal places in the payment currency. * * @return integer */ public function getCurrencyDecimalPlaces() { if ($this->getCurrency()) { $currency = new Currency($this->getCurrency()); if ($this->getCurrencies()->contains($currency)) { return $this->getCurrencies()->subunitFor($currency); } } return 2; } /** * Format an amount for the payment currency. * * @param string $amount * @return string */ public function formatCurrency($amount) { $money = $this->getMoney((string) $amount); $formatter = new DecimalMoneyFormatter($this->getCurrencies()); return $formatter->format($money); } /** * Get the request description. * * @return string */ public function getDescription() { return $this->getParameter('description'); } /** * Sets the request description. * * @param string $value * @return $this */ public function setDescription($value) { return $this->setParameter('description', $value); } /** * Get the transaction ID. * * The transaction ID is the identifier generated by the merchant website. * * @return string */ public function getTransactionId() { return $this->getParameter('transactionId'); } /** * Sets the transaction ID. * * @param string $value * @return $this */ public function setTransactionId($value) { return $this->setParameter('transactionId', $value); } /** * Get the transaction reference. * * The transaction reference is the identifier generated by the remote * payment gateway. * * @return string */ public function getTransactionReference() { return $this->getParameter('transactionReference'); } /** * Sets the transaction reference. * * @param string $value * @return $this */ public function setTransactionReference($value) { return $this->setParameter('transactionReference', $value); } /** * A list of items in this order * * @return ItemBag|null A bag containing items in this order */ public function getItems() { return $this->getParameter('items'); } /** * Set the items in this order * * @param ItemBag|array $items An array of items in this order * @return $this */ public function setItems($items) { if ($items && !$items instanceof ItemBag) { $items = new ItemBag($items); } return $this->setParameter('items', $items); } /** * Get the client IP address. * * @return string */ public function getClientIp() { return $this->getParameter('clientIp'); } /** * Sets the client IP address. * * @param string $value * @return $this */ public function setClientIp($value) { return $this->setParameter('clientIp', $value); } /** * Get the request return URL. * * @return string */ public function getReturnUrl() { return $this->getParameter('returnUrl'); } /** * Sets the request return URL. * * @param string $value * @return $this */ public function setReturnUrl($value) { return $this->setParameter('returnUrl', $value); } /** * Get the request cancel URL. * * @return string */ public function getCancelUrl() { return $this->getParameter('cancelUrl'); } /** * Sets the request cancel URL. * * @param string $value * @return $this */ public function setCancelUrl($value) { return $this->setParameter('cancelUrl', $value); } /** * Get the request notify URL. * * @return string */ public function getNotifyUrl() { return $this->getParameter('notifyUrl'); } /** * Sets the request notify URL. * * @param string $value * @return $this */ public function setNotifyUrl($value) { return $this->setParameter('notifyUrl', $value); } /** * Get the payment issuer. * * This field is used by some European gateways, and normally represents * the bank where an account is held (separate from the card brand). * * @return string */ public function getIssuer() { return $this->getParameter('issuer'); } /** * Set the payment issuer. * * This field is used by some European gateways, and normally represents * the bank where an account is held (separate from the card brand). * * @param string $value * @return $this */ public function setIssuer($value) { return $this->setParameter('issuer', $value); } /** * Get the payment issuer. * * This field is used by some European gateways, which support * multiple payment providers with a single API. * * @return string */ public function getPaymentMethod() { return $this->getParameter('paymentMethod'); } /** * Set the payment method. * * This field is used by some European gateways, which support * multiple payment providers with a single API. * * @param string $value * @return $this */ public function setPaymentMethod($value) { return $this->setParameter('paymentMethod', $value); } /** * Send the request * * @return ResponseInterface */ public function send() { $data = $this->getData(); return $this->sendData($data); } /** * Get the associated Response. * * @return ResponseInterface */ public function getResponse() { if (null === $this->response) { throw new RuntimeException('You must call send() before accessing the Response!'); } return $this->response; } } src/Common/Message/FetchPaymentMethodsResponseInterface.php 0000644 00000001511 15111334703 0020127 0 ustar 00 <?php /** * Fetch Payment Methods Response interface */ namespace Omnipay\Common\Message; /** * Fetch Payment Methods Response interface * * This interface class defines the functionality of a response * that is a "fetch payment method" response. It extends the ResponseInterface * interface class with some extra functions relating to the * specifics of a response to fetch the payment method from the gateway. * This happens when the gateway needs the customer to choose a * payment method. * */ interface FetchPaymentMethodsResponseInterface extends ResponseInterface { /** * Get the returned list of payment methods. * * These represent separate payment methods which the user must choose between. * * @return \Omnipay\Common\PaymentMethod[] */ public function getPaymentMethods(); } src/Common/Message/RequestInterface.php 0000644 00000002071 15111334703 0014127 0 ustar 00 <?php /** * Request Interface */ namespace Omnipay\Common\Message; /** * Request Interface * * This interface class defines the standard functions that any Omnipay request * interface needs to be able to provide. It is an extension of MessageInterface. * */ interface RequestInterface extends MessageInterface { /** * Initialize request with parameters * @param array $parameters The parameters to send */ public function initialize(array $parameters = array()); /** * Get all request parameters * * @return array */ public function getParameters(); /** * Get the response to this request (if the request has been sent) * * @return ResponseInterface */ public function getResponse(); /** * Send the request * * @return ResponseInterface */ public function send(); /** * Send the request with specified data * * @param mixed $data The data to send * @return ResponseInterface */ public function sendData($data); } UPGRADE.md 0000644 00000005462 15111334703 0006162 0 ustar 00 ## Upgrade apps from 2.x to 3.x - The `redirect()` method no longer calls `exit()` after sending the content. This is up to the developer now. - It is now possible to use `setAmountInteger(integer $value)` and `setMoney(Money $money)` - HTTPPlug is used. Guzzle will be installed when using `omnipay/omnipay`, otherwise you need to require your own implementation (see http://docs.php-http.org/en/latest/clients.html) - The package is renamed from `omnipay/omnipay` to `league/omnipay` and no longer installs all gateways by default. ## Upgrade Gateways from 2.x to 3.x The primary difference is the HTTP Client. We are now using HTTPlug (http://httplug.io/) but rely on our own interface. ### Breaking - Change typehint from Guzzle ClientInterface to `Omnipay\Common\Http\ClientInterface` - `$client->get('..')`/`$client->post('..')` etc are removed, you can call `$client->request('GET', '')`. - No need to call `$request->send()`, requests are sent directly. - Instead of `$client->createRequest(..)` you can create+send the request directly with `$client->request(..)`. - When sending a JSON body, convert the body to a string with `json_encode()` and set the correct Content-Type. - The response is a PSR-7 Response object. You can call `$response->getBody()->getContents()` to get the body as a string. - `$response->json()` and `$response->xml()` are gone, but you can implement the logic directly. - An HTTP Client is no longer added by default by `omnipay/common`, but `omnipay/omnipay` will add Guzzle. Gateways should not rely on Guzzle or other clients directly. - `$body` should be a string (eg. `http_build_query($data)` or `json_encode($data)` instead of just `$data`). - The `$headers` parameters should be an `array` (not `null`, but can be empty) Examples: ```php // V2 XML: $response = $this->httpClient->post($this->endpoint, null, $data)->send(); $result = $httpResponse->xml(); // V3 XML: $response = $this->httpClient->request('POST', $this->endpoint, [], http_build_query($data)); $result = simplexml_load_string($httpResponse->getBody()->getContents()); ``` ```php // Example JSON request: $response = $this->httpClient->request('POST', $this->endpoint, [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', ], json_encode($data)); $result = json_decode($response->getBody()->getContents(), true); ``` #### Testing PHPUnit is upgraded to PHPUnit 6. Common issues: - `setExpectedException()` is removed ```php // PHPUnit 5: $this->setExpectedException($class, $message); // PHPUnit 6: $this->expectException($class); $this->expectExceptionMessage($message); ``` - Tests that do not perform any assertions, will be marked as risky. This can be avoided by annotating them with ` @doesNotPerformAssertions` - You should remove the `Mockery\Adapter\Phpunit\TestListener` in phpunit.xml.dist .github/FUNDING.yml 0000644 00000000023 15111334703 0007712 0 ustar 00 github: [barryvdh] .github/workflows/phpunit.yml 0000644 00000002154 15111334703 0012353 0 ustar 00 name: "PHPUnit tests" on: pull_request: push: branches: - "master" jobs: phpunit: name: "PHPUnit tests" runs-on: ${{ matrix.operating-system }} strategy: matrix: dependencies: - "lowest" - "highest" php-version: - "7.2" - "7.3" - "7.4" - "8.0" operating-system: - "ubuntu-latest" steps: - name: "Checkout" uses: "actions/checkout@v2" - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: coverage: "pcov" php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 tools: composer:v2 - name: "Install lowest dependencies" if: ${{ matrix.dependencies == 'lowest' }} run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" - name: "Install highest dependencies" if: ${{ matrix.dependencies == 'highest' }} run: "composer update --no-interaction --no-progress --no-suggest" - name: "Tests" run: "vendor/bin/phpunit"
Simpan