initial
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException($err);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit51abcdc9aff1abf99ba4af149c42688d::getLoader();
|
||||
@@ -0,0 +1,579 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
|
||||
* @internal
|
||||
*/
|
||||
private static $selfDir = null;
|
||||
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $installedIsLocalDir;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints((string) $constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
|
||||
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||
// all installed packages for example
|
||||
self::$installedIsLocalDir = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private static function getSelfDir()
|
||||
{
|
||||
if (self::$selfDir === null) {
|
||||
self::$selfDir = strtr(__DIR__, '\\', '/');
|
||||
}
|
||||
|
||||
return self::$selfDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
$copiedLocalDir = false;
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
$selfDir = self::getSelfDir();
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
self::$installed = $required;
|
||||
self::$installedIsLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require __DIR__ . '/installed.php';
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'Environment_Details_Report_Details' => $vendorDir . '/gravityforms/gravity-tools/src/System_Report/class-environment-details-report-group.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Alerts_Handler' => $baseDir . '/includes/alerts/class-alerts-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Alerts_Service_Provider' => $baseDir . '/includes/alerts/class-alerts-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Config\\Alerts_Config' => $baseDir . '/includes/alerts/config/class-alerts-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Config\\Alerts_Endpoints_Config' => $baseDir . '/includes/alerts/config/class-alerts-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Connectors\\Alert_Connector' => $baseDir . '/includes/alerts/connectors/interface-alert-connector.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Connectors\\Slack_Alert_Connector' => $baseDir . '/includes/alerts/connectors/class-slack-alert-connector.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Connectors\\Twilio_Alert_Connector' => $baseDir . '/includes/alerts/connectors/class-twilio-alert-connector.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Endpoints\\Save_Alerts_Settings_Endpoint' => $baseDir . '/includes/alerts/endpoints/class-save-alerts-settings-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Endpoints\\Send_Test_Alert_Endpoint' => $baseDir . '/includes/alerts/endpoints/class-send-test-alert-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\App_Service_Provider' => $baseDir . '/includes/apps/class-apps-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Apps_Config' => $baseDir . '/includes/apps/config/class-apps-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Dashboard_Config' => $baseDir . '/includes/apps/config/class-dashboard-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Email_Log_Config' => $baseDir . '/includes/apps/config/class-email-log-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Email_Log_Single_Config' => $baseDir . '/includes/apps/config/class-email-log-single-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Settings_Config' => $baseDir . '/includes/apps/config/class-settings-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Tools_Config' => $baseDir . '/includes/apps/config/class-tools-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Endpoints\\Get_Dashboard_Data_Endpoint' => $baseDir . '/includes/apps/endpoints/class-get-dashboard-data-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Migration\\Endpoints\\Migrate_Settings_Endpoint' => $baseDir . '/includes/migration/endpoints/class-migrate-settings-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Setup_Wizard\\Config\\Setup_Wizard_Config' => $baseDir . '/includes/apps/setup-wizard/config/class-setup-wizard-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Setup_Wizard\\Config\\Setup_Wizard_Endpoints_Config' => $baseDir . '/includes/apps/setup-wizard/config/class-setup-wizard-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Setup_Wizard\\Endpoints\\License_Check_Endpoint' => $baseDir . '/includes/apps/setup-wizard/endpoints/class-license-check-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Setup_Wizard\\Setup_Wizard_Service_Provider' => $baseDir . '/includes/apps/setup-wizard/class-setup-wizard-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Assets\\Assets_Service_Provider' => $baseDir . '/includes/assets/class-assets-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Config\\Connector_Config' => $baseDir . '/includes/connectors/config/class-connector-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Config\\Connector_Endpoints_Config' => $baseDir . '/includes/connectors/config/class-connector-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Connector_Base' => $baseDir . '/includes/connectors/class-connector-base.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Connector_Factory' => $baseDir . '/includes/connectors/class-connector-factory.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Connector_Service_Provider' => $baseDir . '/includes/connectors/class-connector-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Check_Background_Tasks_Endpoint' => $baseDir . '/includes/connectors/endpoints/class-check-background-tasks-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Cleanup_Data_Endpoint' => $baseDir . '/includes/connectors/endpoints/class-cleanup-data-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Get_Connector_Emails' => $baseDir . '/includes/connectors/endpoints/class-get-connector-emails-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Get_Single_Email_Data_Endpoint' => $baseDir . '/includes/connectors/endpoints/class-get-single-email-data-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Save_Connector_Settings_Endpoint' => $baseDir . '/includes/connectors/endpoints/class-save-connector-settings-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Save_Plugin_Settings_Endpoint' => $baseDir . '/includes/connectors/endpoints/class-save-plugin-settings-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Send_Test_Endpoint' => $baseDir . '/includes/connectors/endpoints/class-send-test-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Oauth\\Google_Oauth_Handler' => $baseDir . '/includes/connectors/oauth/class-google-oauth-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Oauth\\Microsoft_Oauth_Handler' => $baseDir . '/includes/connectors/oauth/class-microsoft-oauth-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Oauth\\Zoho_Oauth_Handler' => $baseDir . '/includes/connectors/oauth/class-zoho-oauth-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Oauth_Data_Handler' => $baseDir . '/includes/connectors/class-oauth-data-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Amazon' => $baseDir . '/includes/connectors/types/class-connector-amazon.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Brevo' => $baseDir . '/includes/connectors/types/class-connector-brevo.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Cloudflare' => $baseDir . '/includes/connectors/types/class-connector-cloudflare.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Elastic_Email' => $baseDir . '/includes/connectors/types/class-connector-elasticemail.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Emailit' => $baseDir . '/includes/connectors/types/class-connector-emailit.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Generic' => $baseDir . '/includes/connectors/types/class-connector-generic.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Google' => $baseDir . '/includes/connectors/types/class-connector-google.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Mailchimp' => $baseDir . '/includes/connectors/types/class-connector-mailchimp.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_MailerSend' => $baseDir . '/includes/connectors/types/class-connector-mailersend.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Mailgun' => $baseDir . '/includes/connectors/types/class-connector-mailgun.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Mailjet' => $baseDir . '/includes/connectors/types/class-connector-mailjet.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Mailtrap' => $baseDir . '/includes/connectors/types/class-connector-mailtrap.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Microsoft' => $baseDir . '/includes/connectors/types/class-connector-microsoft.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Phpmail' => $baseDir . '/includes/connectors/types/class-connector-phpmail.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Postmark' => $baseDir . '/includes/connectors/types/class-connector-postmark.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Resend' => $baseDir . '/includes/connectors/types/class-connector-resend.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_SMTPCom' => $baseDir . '/includes/connectors/types/class-connector-smtpcom.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Sendgrid' => $baseDir . '/includes/connectors/types/class-connector-sendgrid.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Smtp2go' => $baseDir . '/includes/connectors/types/class-connector-smtp2go.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Sparkpost' => $baseDir . '/includes/connectors/types/class-connector-sparkpost.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Zoho' => $baseDir . '/includes/connectors/types/class-connector-zoho.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Const_Data_Store' => $baseDir . '/includes/datastore/class-const-data-store.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Data_Store' => $baseDir . '/includes/datastore/interface-data-store.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Data_Store_Router' => $baseDir . '/includes/datastore/class-data-store-router.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Opts_Data_Store' => $baseDir . '/includes/datastore/class-opts-data-store.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Plugin_Opts_Data_Store' => $baseDir . '/includes/datastore/class-plugin-opts-data-store.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Email_Management\\Config\\Managed_Email_Types_Config' => $baseDir . '/includes/email-management/config/class-managed-email-types-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Email_Management\\Email_Management_Service_Provider' => $baseDir . '/includes/email-management/class-email-management-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Email_Management\\Email_Stopper' => $baseDir . '/includes/email-management/class-email-stopper.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Email_Management\\Managed_Email' => $baseDir . '/includes/email-management/class-managed-email.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Connector_Status_Enum' => $baseDir . '/includes/enums/class-connector-status-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Integration_Enum' => $baseDir . '/includes/enums/class-integration-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Status_Enum' => $baseDir . '/includes/enums/class-status-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Suppression_Reason_Enum' => $baseDir . '/includes/enums/class-suppression-reason-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Zoho_Datacenters_Enum' => $baseDir . '/includes/enums/class-zoho-datacenters-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Environment\\Config\\Environment_Endpoints_Config' => $baseDir . '/includes/environment/config/class-environment-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Environment\\Endpoints\\Uninstall_Endpoint' => $baseDir . '/includes/environment/endpoints/class-uninstall-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Environment\\Environment_Details' => $baseDir . '/includes/environment/class-environment-details.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Environment\\Environment_Service_Provider' => $baseDir . '/includes/environment/class-environment-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Errors\\Error_Handler' => $baseDir . '/includes/errors/class-error-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Errors\\Error_Handler_Service_Provider' => $baseDir . '/includes/errors/class-error-handler-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Experimental_Features\\Experiment_Features_Handler' => $baseDir . '/includes/experimental-features/class-experimental-features-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Experimental_Features\\Experimental_Features_Service_Provider' => $baseDir . '/includes/experimental-features/class-experimental-features-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Feature_Flags\\Config\\Feature_Flags_Config' => $baseDir . '/includes/feature-flags/config/class-feature-flags-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Feature_Flags\\Feature_Flag_Manager' => $baseDir . '/includes/feature-flags/class-feature-flag-manager.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Feature_Flags\\Feature_Flag_Repository' => $baseDir . '/includes/feature-flags/class-feature-flag-repository.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Feature_Flags\\Feature_Flags_Service_Provider' => $baseDir . '/includes/feature-flags/class-feature-flags-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Gravity_SMTP' => $baseDir . '/includes/class-gravity-smtp.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\Config\\Handler_Endpoints_Config' => $baseDir . '/includes/handler/config/class-handler-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\Endpoints\\Resend_Email_Endpoint' => $baseDir . '/includes/handler/endpoints/class-resend-email-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\External\\Gravity_Forms_Note_Handler' => $baseDir . '/includes/handler/external/class-gravity-forms-note-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\Handler_Service_Provider' => $baseDir . '/includes/handler/class-handler-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\Mail_Handler' => $baseDir . '/includes/handler/class-mail-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Config\\Logging_Endpoints_Config' => $baseDir . '/includes/logging/config/class-logging-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Debug\\Debug_Log_Event_Handler' => $baseDir . '/includes/logging/debug/class-debug-log-event-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Debug\\Debug_Logger' => $baseDir . '/includes/logging/debug/class-debug-logger.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Debug\\Null_Logger' => $baseDir . '/includes/logging/debug/class-null-logger.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Debug\\Null_Logging_Provider' => $baseDir . '/includes/logging/debug/class-null-logging-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Delete_Debug_Logs_Endpoint' => $baseDir . '/includes/logging/endpoints/class-delete-debug-logs-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Delete_Email_Endpoint' => $baseDir . '/includes/logging/endpoints/class-delete-email-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Delete_Events_Endpoint' => $baseDir . '/includes/logging/endpoints/class-delete-events-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Get_Email_Message_Endpoint' => $baseDir . '/includes/logging/endpoints/class-get-email-message-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Get_Paginated_Debug_Log_Items_Endpoint' => $baseDir . '/includes/logging/endpoints/class-get-paginated-debug-log-items-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Get_Paginated_Items_Endpoint' => $baseDir . '/includes/logging/endpoints/class-get-paginated-items-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Log_Item_Endpoint' => $baseDir . '/includes/logging/endpoints/class-log-item-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\View_Log_Endpoint' => $baseDir . '/includes/logging/endpoints/class-view-log-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Log\\Logger' => $baseDir . '/includes/logging/log/class-logger.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Log\\WP_Mail_Logger' => $baseDir . '/includes/logging/log/class-wp-mail-logger.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Logging_Service_Provider' => $baseDir . '/includes/logging/class-logging-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Scheduling\\Handler' => $baseDir . '/includes/logging/scheduling/handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Managed_Email_Types' => $baseDir . '/includes/email-management/class-managed-email-types.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Config\\Migration_Endpoints_Config' => $baseDir . '/includes/migration/config/class-migration-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Data\\Migration_Data_Gravityforms' => $baseDir . '/includes/migration/data/class-migration-data-gravityforms.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Data\\Migration_Data_Wpmailsmtp' => $baseDir . '/includes/migration/data/class-migration-data-wpmailsmtp.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Migration' => $baseDir . '/includes/migration/class-migration.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Migration_Service_Provider' => $baseDir . '/includes/migration/class-migration-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Migrator' => $baseDir . '/includes/migration/class-migrator.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Migrator_Collection' => $baseDir . '/includes/migration/class-migrator-collection.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Debug_Log_Model' => $baseDir . '/includes/models/class-debug-log-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Event_Model' => $baseDir . '/includes/models/class-event-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator' => $baseDir . '/includes/models/hydrators/interface-hydrator.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Amazon' => $baseDir . '/includes/models/hydrators/class-hydrator-amazon.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Brevo' => $baseDir . '/includes/models/hydrators/class-hydrator-brevo.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Cloudflare' => $baseDir . '/includes/models/hydrators/class-hydrator-cloudflare.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Factory' => $baseDir . '/includes/models/hydrators/class-hydrator-factory.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Generic' => $baseDir . '/includes/models/hydrators/class-hydrator-generic.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Google' => $baseDir . '/includes/models/hydrators/class-hydrator-google.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Mailgun' => $baseDir . '/includes/models/hydrators/class-hydrator-mailgun.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Microsoft' => $baseDir . '/includes/models/hydrators/class-hydrator-microsoft.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Phpmail' => $baseDir . '/includes/models/hydrators/class-hydrator-phpmail.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Postmark' => $baseDir . '/includes/models/hydrators/class-hydrator-postmark.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Sendgrid' => $baseDir . '/includes/models/hydrators/class-hydrator-sendgrid.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_WP_Mail' => $baseDir . '/includes/models/hydrators/class-hydrator-wp-mail.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Log_Details_Model' => $baseDir . '/includes/models/class-log-details-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Notifications_Model' => $baseDir . '/includes/models/class-notifications-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Suppressed_Emails_Model' => $baseDir . '/includes/models/class-suppressed-emails-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Traits\\Can_Compare_Dynamically' => $baseDir . '/includes/models/traits/trait-can-compare-dynamically.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Notifications\\Config\\Notifications_Endpoints_Config' => $baseDir . '/includes/notifications/config/class-notifications-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Notifications\\Email_Summary_Handler' => $baseDir . '/includes/notifications/class-email-summary-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Notifications\\Notifications_Service_Provider' => $baseDir . '/includes/notifications/class-notifications-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Pages\\Admin_Page' => $baseDir . '/includes/pages/class-admin-page.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Pages\\Page_Service_Provider' => $baseDir . '/includes/pages/class-page-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Routing\\Handlers\\Primary_Backup_Handler' => $baseDir . '/includes/routing/handlers/class-primary-backup-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Routing\\Handlers\\Routing_Handler' => $baseDir . '/includes/routing/handlers/interface-routing-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Routing\\Routing_Service_Provider' => $baseDir . '/includes/routing/class-routing-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Config\\Suppression_Settings_Config' => $baseDir . '/includes/suppression/config/class-suppression-settings-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Endpoints\\Add_Suppressed_Emails_Endpoint' => $baseDir . '/includes/suppression/endpoints/class-add-suppressed-emails-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Endpoints\\Get_Paginated_Items' => $baseDir . '/includes/suppression/endpoints/class-get-paginated-items.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Endpoints\\Reactivate_Suppressed_Emails_Endpoint' => $baseDir . '/includes/suppression/endpoints/class-reactivate-suppressed-emails-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Suppression_Service_Provider' => $baseDir . '/includes/suppression/class-suppression-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Telemetry\\Telemetry_Background_Processor' => $baseDir . '/includes/telemetry/class-telemetry-background-processor.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Telemetry\\Telemetry_Handler' => $baseDir . '/includes/telemetry/class-telemetry-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Telemetry\\Telemetry_Service_Provider' => $baseDir . '/includes/telemetry/class-telemetry-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Telemetry\\Telemetry_Snapshot_Data' => $baseDir . '/includes/telemetry/class-telemetry-snapshot-data.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Translations\\TranslationsPress' => $baseDir . '/includes/translations/class-translationspress.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Translations\\Translations_Service_Provider' => $baseDir . '/includes/translations/class-translations-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Users\\Members_Integration' => $baseDir . '/includes/users/class-members-integration.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Users\\Roles' => $baseDir . '/includes/users/class-roles.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Users\\Users_Service_Provider' => $baseDir . '/includes/users/class-users-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\AWS_Signature_Handler' => $baseDir . '/includes/utils/class-aws-signature-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Attachments_Saver' => $baseDir . '/includes/utils/class-attachments-saver.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Basic_Encrypted_Hash' => $baseDir . '/includes/utils/class-basic-ecrypted-hash.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Booliesh' => $baseDir . '/includes/utils/class-booleish.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Fast_Endpoint' => $baseDir . '/includes/utils/class-fast-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Header_Parser' => $baseDir . '/includes/utils/class-header-parser.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Import_Data_Checker' => $baseDir . '/includes/utils/class-import-data-checker.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Recipient' => $baseDir . '/includes/utils/class-recipient.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Recipient_Collection' => $baseDir . '/includes/utils/class-recipient-collection.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Recipient_Parser' => $baseDir . '/includes/utils/class-recipient-parser.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\SQL_Filter_Parser' => $baseDir . '/includes/utils/class-sql-filter-parser.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Source_Parser' => $baseDir . '/includes/utils/class-source-parser.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\API\\Gravity_Api' => $vendorDir . '/gravityforms/gravity-tools/src/API/class-gravity-api.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\API\\Oauth_Handler' => $vendorDir . '/gravityforms/gravity-tools/src/API/class-oauth-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Apps\\Registers_Apps' => $vendorDir . '/gravityforms/gravity-tools/src/Apps/trait-registers-apps.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Assets\\Asset_Processor' => $vendorDir . '/gravityforms/gravity-tools/src/Assets/class-asset-processor.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Background_Processing\\Background_Process' => $vendorDir . '/gravityforms/gravity-tools/src/Background_Processing/class-background-process.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Background_Processing\\WP_Async_Request' => $vendorDir . '/gravityforms/gravity-tools/src/Background_Processing/class-wp-async-request.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Cache\\Cache' => $vendorDir . '/gravityforms/gravity-tools/src/Cache/class-cache.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Config' => $vendorDir . '/gravityforms/gravity-tools/src/class-config.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Config\\App_Config' => $vendorDir . '/gravityforms/gravity-tools/src/Config/class-app-config.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Config_Collection' => $vendorDir . '/gravityforms/gravity-tools/src/class-config-collection.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Config_Data_Parser' => $vendorDir . '/gravityforms/gravity-tools/src/class-config-data-parser.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data\\Oauth_Data_Handler' => $vendorDir . '/gravityforms/gravity-tools/src/Data/interface-oauth-data-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data\\Transient_Strategy' => $vendorDir . '/gravityforms/gravity-tools/src/Data/class-transient-strategy.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Destination' => $vendorDir . '/gravityforms/gravity-tools/src/Data_Import/interface-destination.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Import_Handler' => $vendorDir . '/gravityforms/gravity-tools/src/Data_Import/class-import-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Record' => $vendorDir . '/gravityforms/gravity-tools/src/Data_Import/class-record.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Source' => $vendorDir . '/gravityforms/gravity-tools/src/Data_Import/interface-source.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Sources\\CSV_Source' => $vendorDir . '/gravityforms/gravity-tools/src/Data_Import/Sources/class-csv-source.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Emails\\Email_Templatizer' => $vendorDir . '/gravityforms/gravity-tools/src/Emails/class-email-templatizer.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Endpoints\\Endpoint' => $vendorDir . '/gravityforms/gravity-tools/src/Endpoints/class-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Enum\\Field_Type_Validation_Enum' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Enum/class-field-type-validation-enum.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Models\\Model' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Models/class-model.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Mutation_Handler' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/class-mutation-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Query_Handler' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/class-query-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Connect_Runner' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Runners/class-connect-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Delete_Runner' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Runners/class-delete-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Disconnect_Runner' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Runners/class-disconnect-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Insert_Runner' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Runners/class-insert-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Runner' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Runners/class-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Schema_Runner' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Runners/class-schema-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Update_Runner' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Runners/class-update-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Arguments_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-arguments-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Base_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-base-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Data_Object_From_Array_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-data-object-from-array-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Field_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-field-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutation_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Connect\\Connect_Mutation_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Connect/class-connect-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Connect\\Connection_Values_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Connect/class-connection-values-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Connect\\Disconnect_Mutation_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Connect/class-disconnect-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Delete\\Delete_Mutation_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Delete/class-delete-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Delete\\ID_To_Delete_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Delete/class-id-to-delete-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Generic_Mutation_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/class-generic-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Insert\\Insert_Mutation_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Insert/class-insert-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Insert\\Insertion_Object_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Insert/class-insertion-object-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Insert\\Insertion_Objects_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Insert/class-insertion-objects-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Update\\Fields_To_Update_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Update/class-fields-to-update-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Update\\Update_Mutation_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Update/class-update-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Query_Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-query-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Token' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Token_From_Array' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-token-from-array.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Utils\\Model_Collection' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Utils/class-model-collection.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Utils\\Relationship' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Utils/class-relationship.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Utils\\Relationship_Collection' => $vendorDir . '/gravityforms/gravity-tools/src/Hermes/Utils/class-relationship-collection.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\API_Response' => $vendorDir . '/gravityforms/gravity-tools/src/License/class-api-response.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\License_API_Connector' => $vendorDir . '/gravityforms/gravity-tools/src/License/class-license-api-connector.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\License_API_Response' => $vendorDir . '/gravityforms/gravity-tools/src/License/class-license-api-response.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\License_API_Response_Factory' => $vendorDir . '/gravityforms/gravity-tools/src/License/class-license-api-response-factory.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\License_Statuses' => $vendorDir . '/gravityforms/gravity-tools/src/License/class-license-statuses.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\DB_Logging_Provider' => $vendorDir . '/gravityforms/gravity-tools/src/Logging/class-db-logging-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\File_Logging_Provider' => $vendorDir . '/gravityforms/gravity-tools/src/Logging/class-file-logging-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\Log_Line' => $vendorDir . '/gravityforms/gravity-tools/src/Logging/class-log-line.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\Logger' => $vendorDir . '/gravityforms/gravity-tools/src/Logging/class-logger.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\Logging_Provider' => $vendorDir . '/gravityforms/gravity-tools/src/Logging/interface-logging-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\Parsers\\File_Log_Parser' => $vendorDir . '/gravityforms/gravity-tools/src/Logging/parsers/class-file-log-parser.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Model\\Form_Model' => $vendorDir . '/gravityforms/gravity-tools/src/Model/class-form-model.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Providers\\Config_Collection_Service_Provider' => $vendorDir . '/gravityforms/gravity-tools/src/Providers/class-config-collection-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Providers\\Config_Service_Provider' => $vendorDir . '/gravityforms/gravity-tools/src/Providers/class-config-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Service_Container' => $vendorDir . '/gravityforms/gravity-tools/src/class-service-container.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Service_Provider' => $vendorDir . '/gravityforms/gravity-tools/src/class-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\System_Report\\System_Report_Group' => $vendorDir . '/gravityforms/gravity-tools/src/System_Report/class-system-report-group.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\System_Report\\System_Report_Item' => $vendorDir . '/gravityforms/gravity-tools/src/System_Report/class-system-report-item.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\System_Report\\System_Report_Repository' => $vendorDir . '/gravityforms/gravity-tools/src/System_Report/class-system-report-repository.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Telemetry\\Telemetry_Data' => $vendorDir . '/gravityforms/gravity-tools/src/Telemetry/class-telemetry-data.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Telemetry\\Telemetry_Processor' => $vendorDir . '/gravityforms/gravity-tools/src/Telemetry/class-telemetry-processor.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Updates\\Auto_Updater' => $vendorDir . '/gravityforms/gravity-tools/src/Updates/class-auto-updater.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Updates\\Updates_Service_Provider' => $baseDir . '/includes/updates/class-updates-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Upgrades\\Upgrade_Routines' => $vendorDir . '/gravityforms/gravity-tools/src/Upgrades/class-upgrade-routines.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Beltloop' => $vendorDir . '/gravityforms/gravity-tools/src/Utils/class-beltloop.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Bettarray' => $vendorDir . '/gravityforms/gravity-tools/src/Utils/class-bettarray.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Booliesh' => $vendorDir . '/gravityforms/gravity-tools/src/Utils/class-booliesh.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Common' => $vendorDir . '/gravityforms/gravity-tools/src/Utils/class-common.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\GeoData' => $vendorDir . '/gravityforms/gravity-tools/src/Utils/class-geodata.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Moola' => $vendorDir . '/gravityforms/gravity-tools/src/Utils/class-moola.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Utils_Service_Provider' => $baseDir . '/includes/utils/class-utils-service-provider.php',
|
||||
);
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'de106312193d3b5d7e278f8e63c27774' => $baseDir . '/includes/functions_include.php',
|
||||
);
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit51abcdc9aff1abf99ba4af149c42688d
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit51abcdc9aff1abf99ba4af149c42688d', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit51abcdc9aff1abf99ba4af149c42688d', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit51abcdc9aff1abf99ba4af149c42688d::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit51abcdc9aff1abf99ba4af149c42688d::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
require $file;
|
||||
}
|
||||
}, null, null);
|
||||
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||
$requireFile($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit51abcdc9aff1abf99ba4af149c42688d
|
||||
{
|
||||
public static $files = array (
|
||||
'de106312193d3b5d7e278f8e63c27774' => __DIR__ . '/../..' . '/includes/functions_include.php',
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'Environment_Details_Report_Details' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/System_Report/class-environment-details-report-group.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Alerts_Handler' => __DIR__ . '/../..' . '/includes/alerts/class-alerts-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Alerts_Service_Provider' => __DIR__ . '/../..' . '/includes/alerts/class-alerts-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Config\\Alerts_Config' => __DIR__ . '/../..' . '/includes/alerts/config/class-alerts-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Config\\Alerts_Endpoints_Config' => __DIR__ . '/../..' . '/includes/alerts/config/class-alerts-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Connectors\\Alert_Connector' => __DIR__ . '/../..' . '/includes/alerts/connectors/interface-alert-connector.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Connectors\\Slack_Alert_Connector' => __DIR__ . '/../..' . '/includes/alerts/connectors/class-slack-alert-connector.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Connectors\\Twilio_Alert_Connector' => __DIR__ . '/../..' . '/includes/alerts/connectors/class-twilio-alert-connector.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Endpoints\\Save_Alerts_Settings_Endpoint' => __DIR__ . '/../..' . '/includes/alerts/endpoints/class-save-alerts-settings-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Alerts\\Endpoints\\Send_Test_Alert_Endpoint' => __DIR__ . '/../..' . '/includes/alerts/endpoints/class-send-test-alert-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\App_Service_Provider' => __DIR__ . '/../..' . '/includes/apps/class-apps-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Apps_Config' => __DIR__ . '/../..' . '/includes/apps/config/class-apps-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Dashboard_Config' => __DIR__ . '/../..' . '/includes/apps/config/class-dashboard-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Email_Log_Config' => __DIR__ . '/../..' . '/includes/apps/config/class-email-log-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Email_Log_Single_Config' => __DIR__ . '/../..' . '/includes/apps/config/class-email-log-single-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Settings_Config' => __DIR__ . '/../..' . '/includes/apps/config/class-settings-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Config\\Tools_Config' => __DIR__ . '/../..' . '/includes/apps/config/class-tools-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Endpoints\\Get_Dashboard_Data_Endpoint' => __DIR__ . '/../..' . '/includes/apps/endpoints/class-get-dashboard-data-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Migration\\Endpoints\\Migrate_Settings_Endpoint' => __DIR__ . '/../..' . '/includes/migration/endpoints/class-migrate-settings-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Setup_Wizard\\Config\\Setup_Wizard_Config' => __DIR__ . '/../..' . '/includes/apps/setup-wizard/config/class-setup-wizard-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Setup_Wizard\\Config\\Setup_Wizard_Endpoints_Config' => __DIR__ . '/../..' . '/includes/apps/setup-wizard/config/class-setup-wizard-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Setup_Wizard\\Endpoints\\License_Check_Endpoint' => __DIR__ . '/../..' . '/includes/apps/setup-wizard/endpoints/class-license-check-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Apps\\Setup_Wizard\\Setup_Wizard_Service_Provider' => __DIR__ . '/../..' . '/includes/apps/setup-wizard/class-setup-wizard-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Assets\\Assets_Service_Provider' => __DIR__ . '/../..' . '/includes/assets/class-assets-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Config\\Connector_Config' => __DIR__ . '/../..' . '/includes/connectors/config/class-connector-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Config\\Connector_Endpoints_Config' => __DIR__ . '/../..' . '/includes/connectors/config/class-connector-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Connector_Base' => __DIR__ . '/../..' . '/includes/connectors/class-connector-base.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Connector_Factory' => __DIR__ . '/../..' . '/includes/connectors/class-connector-factory.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Connector_Service_Provider' => __DIR__ . '/../..' . '/includes/connectors/class-connector-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Check_Background_Tasks_Endpoint' => __DIR__ . '/../..' . '/includes/connectors/endpoints/class-check-background-tasks-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Cleanup_Data_Endpoint' => __DIR__ . '/../..' . '/includes/connectors/endpoints/class-cleanup-data-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Get_Connector_Emails' => __DIR__ . '/../..' . '/includes/connectors/endpoints/class-get-connector-emails-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Get_Single_Email_Data_Endpoint' => __DIR__ . '/../..' . '/includes/connectors/endpoints/class-get-single-email-data-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Save_Connector_Settings_Endpoint' => __DIR__ . '/../..' . '/includes/connectors/endpoints/class-save-connector-settings-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Save_Plugin_Settings_Endpoint' => __DIR__ . '/../..' . '/includes/connectors/endpoints/class-save-plugin-settings-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Endpoints\\Send_Test_Endpoint' => __DIR__ . '/../..' . '/includes/connectors/endpoints/class-send-test-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Oauth\\Google_Oauth_Handler' => __DIR__ . '/../..' . '/includes/connectors/oauth/class-google-oauth-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Oauth\\Microsoft_Oauth_Handler' => __DIR__ . '/../..' . '/includes/connectors/oauth/class-microsoft-oauth-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Oauth\\Zoho_Oauth_Handler' => __DIR__ . '/../..' . '/includes/connectors/oauth/class-zoho-oauth-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Oauth_Data_Handler' => __DIR__ . '/../..' . '/includes/connectors/class-oauth-data-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Amazon' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-amazon.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Brevo' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-brevo.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Cloudflare' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-cloudflare.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Elastic_Email' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-elasticemail.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Emailit' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-emailit.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Generic' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-generic.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Google' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-google.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Mailchimp' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-mailchimp.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_MailerSend' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-mailersend.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Mailgun' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-mailgun.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Mailjet' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-mailjet.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Mailtrap' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-mailtrap.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Microsoft' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-microsoft.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Phpmail' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-phpmail.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Postmark' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-postmark.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Resend' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-resend.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_SMTPCom' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-smtpcom.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Sendgrid' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-sendgrid.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Smtp2go' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-smtp2go.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Sparkpost' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-sparkpost.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Connectors\\Types\\Connector_Zoho' => __DIR__ . '/../..' . '/includes/connectors/types/class-connector-zoho.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Const_Data_Store' => __DIR__ . '/../..' . '/includes/datastore/class-const-data-store.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Data_Store' => __DIR__ . '/../..' . '/includes/datastore/interface-data-store.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Data_Store_Router' => __DIR__ . '/../..' . '/includes/datastore/class-data-store-router.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Opts_Data_Store' => __DIR__ . '/../..' . '/includes/datastore/class-opts-data-store.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Data_Store\\Plugin_Opts_Data_Store' => __DIR__ . '/../..' . '/includes/datastore/class-plugin-opts-data-store.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Email_Management\\Config\\Managed_Email_Types_Config' => __DIR__ . '/../..' . '/includes/email-management/config/class-managed-email-types-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Email_Management\\Email_Management_Service_Provider' => __DIR__ . '/../..' . '/includes/email-management/class-email-management-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Email_Management\\Email_Stopper' => __DIR__ . '/../..' . '/includes/email-management/class-email-stopper.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Email_Management\\Managed_Email' => __DIR__ . '/../..' . '/includes/email-management/class-managed-email.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Connector_Status_Enum' => __DIR__ . '/../..' . '/includes/enums/class-connector-status-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Integration_Enum' => __DIR__ . '/../..' . '/includes/enums/class-integration-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Status_Enum' => __DIR__ . '/../..' . '/includes/enums/class-status-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Suppression_Reason_Enum' => __DIR__ . '/../..' . '/includes/enums/class-suppression-reason-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Enums\\Zoho_Datacenters_Enum' => __DIR__ . '/../..' . '/includes/enums/class-zoho-datacenters-enum.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Environment\\Config\\Environment_Endpoints_Config' => __DIR__ . '/../..' . '/includes/environment/config/class-environment-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Environment\\Endpoints\\Uninstall_Endpoint' => __DIR__ . '/../..' . '/includes/environment/endpoints/class-uninstall-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Environment\\Environment_Details' => __DIR__ . '/../..' . '/includes/environment/class-environment-details.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Environment\\Environment_Service_Provider' => __DIR__ . '/../..' . '/includes/environment/class-environment-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Errors\\Error_Handler' => __DIR__ . '/../..' . '/includes/errors/class-error-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Errors\\Error_Handler_Service_Provider' => __DIR__ . '/../..' . '/includes/errors/class-error-handler-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Experimental_Features\\Experiment_Features_Handler' => __DIR__ . '/../..' . '/includes/experimental-features/class-experimental-features-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Experimental_Features\\Experimental_Features_Service_Provider' => __DIR__ . '/../..' . '/includes/experimental-features/class-experimental-features-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Feature_Flags\\Config\\Feature_Flags_Config' => __DIR__ . '/../..' . '/includes/feature-flags/config/class-feature-flags-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Feature_Flags\\Feature_Flag_Manager' => __DIR__ . '/../..' . '/includes/feature-flags/class-feature-flag-manager.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Feature_Flags\\Feature_Flag_Repository' => __DIR__ . '/../..' . '/includes/feature-flags/class-feature-flag-repository.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Feature_Flags\\Feature_Flags_Service_Provider' => __DIR__ . '/../..' . '/includes/feature-flags/class-feature-flags-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Gravity_SMTP' => __DIR__ . '/../..' . '/includes/class-gravity-smtp.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\Config\\Handler_Endpoints_Config' => __DIR__ . '/../..' . '/includes/handler/config/class-handler-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\Endpoints\\Resend_Email_Endpoint' => __DIR__ . '/../..' . '/includes/handler/endpoints/class-resend-email-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\External\\Gravity_Forms_Note_Handler' => __DIR__ . '/../..' . '/includes/handler/external/class-gravity-forms-note-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\Handler_Service_Provider' => __DIR__ . '/../..' . '/includes/handler/class-handler-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Handler\\Mail_Handler' => __DIR__ . '/../..' . '/includes/handler/class-mail-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Config\\Logging_Endpoints_Config' => __DIR__ . '/../..' . '/includes/logging/config/class-logging-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Debug\\Debug_Log_Event_Handler' => __DIR__ . '/../..' . '/includes/logging/debug/class-debug-log-event-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Debug\\Debug_Logger' => __DIR__ . '/../..' . '/includes/logging/debug/class-debug-logger.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Debug\\Null_Logger' => __DIR__ . '/../..' . '/includes/logging/debug/class-null-logger.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Debug\\Null_Logging_Provider' => __DIR__ . '/../..' . '/includes/logging/debug/class-null-logging-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Delete_Debug_Logs_Endpoint' => __DIR__ . '/../..' . '/includes/logging/endpoints/class-delete-debug-logs-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Delete_Email_Endpoint' => __DIR__ . '/../..' . '/includes/logging/endpoints/class-delete-email-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Delete_Events_Endpoint' => __DIR__ . '/../..' . '/includes/logging/endpoints/class-delete-events-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Get_Email_Message_Endpoint' => __DIR__ . '/../..' . '/includes/logging/endpoints/class-get-email-message-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Get_Paginated_Debug_Log_Items_Endpoint' => __DIR__ . '/../..' . '/includes/logging/endpoints/class-get-paginated-debug-log-items-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Get_Paginated_Items_Endpoint' => __DIR__ . '/../..' . '/includes/logging/endpoints/class-get-paginated-items-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\Log_Item_Endpoint' => __DIR__ . '/../..' . '/includes/logging/endpoints/class-log-item-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Endpoints\\View_Log_Endpoint' => __DIR__ . '/../..' . '/includes/logging/endpoints/class-view-log-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Log\\Logger' => __DIR__ . '/../..' . '/includes/logging/log/class-logger.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Log\\WP_Mail_Logger' => __DIR__ . '/../..' . '/includes/logging/log/class-wp-mail-logger.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Logging_Service_Provider' => __DIR__ . '/../..' . '/includes/logging/class-logging-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Logging\\Scheduling\\Handler' => __DIR__ . '/../..' . '/includes/logging/scheduling/handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Managed_Email_Types' => __DIR__ . '/../..' . '/includes/email-management/class-managed-email-types.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Config\\Migration_Endpoints_Config' => __DIR__ . '/../..' . '/includes/migration/config/class-migration-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Data\\Migration_Data_Gravityforms' => __DIR__ . '/../..' . '/includes/migration/data/class-migration-data-gravityforms.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Data\\Migration_Data_Wpmailsmtp' => __DIR__ . '/../..' . '/includes/migration/data/class-migration-data-wpmailsmtp.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Migration' => __DIR__ . '/../..' . '/includes/migration/class-migration.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Migration_Service_Provider' => __DIR__ . '/../..' . '/includes/migration/class-migration-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Migrator' => __DIR__ . '/../..' . '/includes/migration/class-migrator.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Migration\\Migrator_Collection' => __DIR__ . '/../..' . '/includes/migration/class-migrator-collection.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Debug_Log_Model' => __DIR__ . '/../..' . '/includes/models/class-debug-log-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Event_Model' => __DIR__ . '/../..' . '/includes/models/class-event-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator' => __DIR__ . '/../..' . '/includes/models/hydrators/interface-hydrator.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Amazon' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-amazon.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Brevo' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-brevo.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Cloudflare' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-cloudflare.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Factory' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-factory.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Generic' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-generic.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Google' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-google.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Mailgun' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-mailgun.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Microsoft' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-microsoft.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Phpmail' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-phpmail.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Postmark' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-postmark.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_Sendgrid' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-sendgrid.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Hydrators\\Hydrator_WP_Mail' => __DIR__ . '/../..' . '/includes/models/hydrators/class-hydrator-wp-mail.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Log_Details_Model' => __DIR__ . '/../..' . '/includes/models/class-log-details-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Notifications_Model' => __DIR__ . '/../..' . '/includes/models/class-notifications-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Suppressed_Emails_Model' => __DIR__ . '/../..' . '/includes/models/class-suppressed-emails-model.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Models\\Traits\\Can_Compare_Dynamically' => __DIR__ . '/../..' . '/includes/models/traits/trait-can-compare-dynamically.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Notifications\\Config\\Notifications_Endpoints_Config' => __DIR__ . '/../..' . '/includes/notifications/config/class-notifications-endpoints-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Notifications\\Email_Summary_Handler' => __DIR__ . '/../..' . '/includes/notifications/class-email-summary-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Notifications\\Notifications_Service_Provider' => __DIR__ . '/../..' . '/includes/notifications/class-notifications-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Pages\\Admin_Page' => __DIR__ . '/../..' . '/includes/pages/class-admin-page.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Pages\\Page_Service_Provider' => __DIR__ . '/../..' . '/includes/pages/class-page-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Routing\\Handlers\\Primary_Backup_Handler' => __DIR__ . '/../..' . '/includes/routing/handlers/class-primary-backup-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Routing\\Handlers\\Routing_Handler' => __DIR__ . '/../..' . '/includes/routing/handlers/interface-routing-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Routing\\Routing_Service_Provider' => __DIR__ . '/../..' . '/includes/routing/class-routing-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Config\\Suppression_Settings_Config' => __DIR__ . '/../..' . '/includes/suppression/config/class-suppression-settings-config.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Endpoints\\Add_Suppressed_Emails_Endpoint' => __DIR__ . '/../..' . '/includes/suppression/endpoints/class-add-suppressed-emails-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Endpoints\\Get_Paginated_Items' => __DIR__ . '/../..' . '/includes/suppression/endpoints/class-get-paginated-items.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Endpoints\\Reactivate_Suppressed_Emails_Endpoint' => __DIR__ . '/../..' . '/includes/suppression/endpoints/class-reactivate-suppressed-emails-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Suppression\\Suppression_Service_Provider' => __DIR__ . '/../..' . '/includes/suppression/class-suppression-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Telemetry\\Telemetry_Background_Processor' => __DIR__ . '/../..' . '/includes/telemetry/class-telemetry-background-processor.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Telemetry\\Telemetry_Handler' => __DIR__ . '/../..' . '/includes/telemetry/class-telemetry-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Telemetry\\Telemetry_Service_Provider' => __DIR__ . '/../..' . '/includes/telemetry/class-telemetry-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Telemetry\\Telemetry_Snapshot_Data' => __DIR__ . '/../..' . '/includes/telemetry/class-telemetry-snapshot-data.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Translations\\TranslationsPress' => __DIR__ . '/../..' . '/includes/translations/class-translationspress.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Translations\\Translations_Service_Provider' => __DIR__ . '/../..' . '/includes/translations/class-translations-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Users\\Members_Integration' => __DIR__ . '/../..' . '/includes/users/class-members-integration.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Users\\Roles' => __DIR__ . '/../..' . '/includes/users/class-roles.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Users\\Users_Service_Provider' => __DIR__ . '/../..' . '/includes/users/class-users-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\AWS_Signature_Handler' => __DIR__ . '/../..' . '/includes/utils/class-aws-signature-handler.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Attachments_Saver' => __DIR__ . '/../..' . '/includes/utils/class-attachments-saver.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Basic_Encrypted_Hash' => __DIR__ . '/../..' . '/includes/utils/class-basic-ecrypted-hash.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Booliesh' => __DIR__ . '/../..' . '/includes/utils/class-booleish.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Fast_Endpoint' => __DIR__ . '/../..' . '/includes/utils/class-fast-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Header_Parser' => __DIR__ . '/../..' . '/includes/utils/class-header-parser.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Import_Data_Checker' => __DIR__ . '/../..' . '/includes/utils/class-import-data-checker.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Recipient' => __DIR__ . '/../..' . '/includes/utils/class-recipient.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Recipient_Collection' => __DIR__ . '/../..' . '/includes/utils/class-recipient-collection.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Recipient_Parser' => __DIR__ . '/../..' . '/includes/utils/class-recipient-parser.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\SQL_Filter_Parser' => __DIR__ . '/../..' . '/includes/utils/class-sql-filter-parser.php',
|
||||
'Gravity_Forms\\Gravity_SMTP\\Utils\\Source_Parser' => __DIR__ . '/../..' . '/includes/utils/class-source-parser.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\API\\Gravity_Api' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/API/class-gravity-api.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\API\\Oauth_Handler' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/API/class-oauth-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Apps\\Registers_Apps' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Apps/trait-registers-apps.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Assets\\Asset_Processor' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Assets/class-asset-processor.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Background_Processing\\Background_Process' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Background_Processing/class-background-process.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Background_Processing\\WP_Async_Request' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Background_Processing/class-wp-async-request.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Cache\\Cache' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Cache/class-cache.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Config' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/class-config.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Config\\App_Config' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Config/class-app-config.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Config_Collection' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/class-config-collection.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Config_Data_Parser' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/class-config-data-parser.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data\\Oauth_Data_Handler' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Data/interface-oauth-data-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data\\Transient_Strategy' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Data/class-transient-strategy.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Destination' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Data_Import/interface-destination.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Import_Handler' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Data_Import/class-import-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Record' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Data_Import/class-record.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Source' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Data_Import/interface-source.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Data_Import\\Sources\\CSV_Source' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Data_Import/Sources/class-csv-source.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Emails\\Email_Templatizer' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Emails/class-email-templatizer.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Endpoints\\Endpoint' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Endpoints/class-endpoint.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Enum\\Field_Type_Validation_Enum' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Enum/class-field-type-validation-enum.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Models\\Model' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Models/class-model.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Mutation_Handler' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/class-mutation-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Query_Handler' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/class-query-handler.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Connect_Runner' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Runners/class-connect-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Delete_Runner' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Runners/class-delete-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Disconnect_Runner' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Runners/class-disconnect-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Insert_Runner' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Runners/class-insert-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Runner' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Runners/class-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Schema_Runner' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Runners/class-schema-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Runners\\Update_Runner' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Runners/class-update-runner.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Arguments_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-arguments-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Base_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-base-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Data_Object_From_Array_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-data-object-from-array-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Field_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-field-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutation_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Connect\\Connect_Mutation_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Connect/class-connect-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Connect\\Connection_Values_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Connect/class-connection-values-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Connect\\Disconnect_Mutation_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Connect/class-disconnect-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Delete\\Delete_Mutation_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Delete/class-delete-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Delete\\ID_To_Delete_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Delete/class-id-to-delete-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Generic_Mutation_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/class-generic-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Insert\\Insert_Mutation_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Insert/class-insert-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Insert\\Insertion_Object_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Insert/class-insertion-object-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Insert\\Insertion_Objects_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Insert/class-insertion-objects-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Update\\Fields_To_Update_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Update/class-fields-to-update-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Mutations\\Update\\Update_Mutation_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/Mutations/Update/class-update-mutation-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Query_Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-query-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Token' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-token.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Tokens\\Token_From_Array' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Tokens/class-token-from-array.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Utils\\Model_Collection' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Utils/class-model-collection.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Utils\\Relationship' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Utils/class-relationship.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Hermes\\Utils\\Relationship_Collection' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Hermes/Utils/class-relationship-collection.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\API_Response' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/License/class-api-response.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\License_API_Connector' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/License/class-license-api-connector.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\License_API_Response' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/License/class-license-api-response.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\License_API_Response_Factory' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/License/class-license-api-response-factory.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\License\\License_Statuses' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/License/class-license-statuses.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\DB_Logging_Provider' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Logging/class-db-logging-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\File_Logging_Provider' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Logging/class-file-logging-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\Log_Line' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Logging/class-log-line.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\Logger' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Logging/class-logger.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\Logging_Provider' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Logging/interface-logging-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Logging\\Parsers\\File_Log_Parser' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Logging/parsers/class-file-log-parser.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Model\\Form_Model' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Model/class-form-model.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Providers\\Config_Collection_Service_Provider' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Providers/class-config-collection-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Providers\\Config_Service_Provider' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Providers/class-config-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Service_Container' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/class-service-container.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Service_Provider' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/class-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\System_Report\\System_Report_Group' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/System_Report/class-system-report-group.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\System_Report\\System_Report_Item' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/System_Report/class-system-report-item.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\System_Report\\System_Report_Repository' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/System_Report/class-system-report-repository.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Telemetry\\Telemetry_Data' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Telemetry/class-telemetry-data.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Telemetry\\Telemetry_Processor' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Telemetry/class-telemetry-processor.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Updates\\Auto_Updater' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Updates/class-auto-updater.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Updates\\Updates_Service_Provider' => __DIR__ . '/../..' . '/includes/updates/class-updates-service-provider.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Upgrades\\Upgrade_Routines' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Upgrades/class-upgrade-routines.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Beltloop' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Utils/class-beltloop.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Bettarray' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Utils/class-bettarray.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Booliesh' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Utils/class-booliesh.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Common' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Utils/class-common.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\GeoData' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Utils/class-geodata.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Moola' => __DIR__ . '/..' . '/gravityforms/gravity-tools/src/Utils/class-moola.php',
|
||||
'Gravity_Forms\\Gravity_Tools\\Utils\\Utils_Service_Provider' => __DIR__ . '/../..' . '/includes/utils/class-utils-service-provider.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->classMap = ComposerStaticInit51abcdc9aff1abf99ba4af149c42688d::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "gravityforms/gravity-tools",
|
||||
"version": "0.4.14",
|
||||
"version_normalized": "0.4.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/gravityforms/gravity-tools.git",
|
||||
"reference": "38c993edb6e296296265de4f1eae2b6e297dd224"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/gravityforms/gravity-tools/zipball/38c993edb6e296296265de4f1eae2b6e297dd224",
|
||||
"reference": "38c993edb6e296296265de4f1eae2b6e297dd224",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"lucatume/function-mocker": "~2.0",
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"wordpress/wordpress": "dev-master",
|
||||
"yoast/phpunit-polyfills": "4.0.0"
|
||||
},
|
||||
"time": "2026-03-23T20:53:41+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rocket Genius",
|
||||
"email": "info@rocketgenius.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP libraries to support Gravity Forms applications.",
|
||||
"support": {
|
||||
"source": "https://github.com/gravityforms/gravity-tools/tree/0.4.14"
|
||||
},
|
||||
"install-path": "../gravityforms/gravity-tools"
|
||||
}
|
||||
],
|
||||
"dev": false,
|
||||
"dev-package-names": []
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => 'gravityforms/gravitysmtp',
|
||||
'pretty_version' => 'dev-main',
|
||||
'version' => 'dev-main',
|
||||
'reference' => '1c19348314dc74e8e49fc4ce70f4a5dea2c5254d',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => false,
|
||||
),
|
||||
'versions' => array(
|
||||
'gravityforms/gravity-tools' => array(
|
||||
'pretty_version' => '0.4.14',
|
||||
'version' => '0.4.14.0',
|
||||
'reference' => '38c993edb6e296296265de4f1eae2b6e297dd224',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../gravityforms/gravity-tools',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'gravityforms/gravitysmtp' => array(
|
||||
'pretty_version' => 'dev-main',
|
||||
'version' => 'dev-main',
|
||||
'reference' => '1c19348314dc74e8e49fc4ce70f4a5dea2c5254d',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,40 @@
|
||||
Gravity Tools - PHP libraries to support Gravity Forms.
|
||||
=======================================================
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
To install with composer:
|
||||
|
||||
```sh
|
||||
composer require gravityforms/gravity-tools
|
||||
```
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Basic usage example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
require '/path/to/vendor/autoload.php';
|
||||
|
||||
$container = new Gravity_Forms\Gravity_Tools\Service_Container();
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see http://www.gnu.org/licenses.
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
function rsearch($folder, $regPattern) {
|
||||
$dir = new RecursiveDirectoryIterator($folder);
|
||||
$ite = new RecursiveIteratorIterator($dir);
|
||||
$files = new RegexIterator($ite, $regPattern, RegexIterator::GET_MATCH);
|
||||
$fileList = array();
|
||||
foreach($files as $file) {
|
||||
$fileList = array_merge($fileList, $file);
|
||||
}
|
||||
return $fileList;
|
||||
}
|
||||
|
||||
$new_namespace = $argv[1];
|
||||
|
||||
// First, replace all lib file namespaces.
|
||||
$vendor_files_to_mod = rsearch( './vendor/gravityforms/gravity-tools/src', '/.*php/' );
|
||||
|
||||
foreach( $vendor_files_to_mod as $path ) {
|
||||
$contents = file_get_contents( $path );
|
||||
if ( strpos( $contents, 'Gravity_Forms\Gravity_Tools' ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$replaced = str_replace( 'Gravity_Forms\Gravity_Tools', "Gravity_Forms\\$new_namespace\Gravity_Tools", $contents );
|
||||
|
||||
file_put_contents( $path, $replaced );
|
||||
}
|
||||
|
||||
// Next, do the same to plugin files.
|
||||
$files_to_mod = rsearch( './includes', '/.*php/' );
|
||||
|
||||
foreach( $files_to_mod as $path ) {
|
||||
$contents = file_get_contents( $path );
|
||||
if ( strpos( $contents, 'Gravity_Forms\Gravity_Tools' ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$replaced = str_replace( 'Gravity_Forms\Gravity_Tools', "Gravity_Forms\\$new_namespace\Gravity_Tools", $contents );
|
||||
|
||||
file_put_contents( $path, $replaced );
|
||||
}
|
||||
|
||||
?>
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Enum\Field_Type_Validation_Enum;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship_Collection;
|
||||
use tad\FunctionMocker\FunctionMocker;
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
FunctionMocker::init();
|
||||
|
||||
/**
|
||||
* Bootstrap for WP Unit Tests
|
||||
*/
|
||||
require __DIR__ . '/wp-loader.php';
|
||||
$core_loader = new WpLoader();
|
||||
$core_loader->init();
|
||||
|
||||
class FakeUserModel extends Model {
|
||||
protected $type = 'user';
|
||||
protected $access_cap = 'manage_options';
|
||||
protected $forced_table_name = 'users';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'ID' => Field_Type_Validation_Enum::INT,
|
||||
'user_login' => Field_Type_Validation_Enum::STRING,
|
||||
'user_nicename' => Field_Type_Validation_Enum::STRING,
|
||||
'user_email' => Field_Type_Validation_Enum::EMAIL,
|
||||
'user_url' => Field_Type_Validation_Enum::STRING,
|
||||
'user_registered' => Field_Type_Validation_Enum::DATE,
|
||||
'user_status' => Field_Type_Validation_Enum::INT,
|
||||
'display_name' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
public function relationships() {
|
||||
return new Relationship_Collection( array(
|
||||
new Relationship( 'user', 'deal', 'manage_options', false, 'one_to_many' ),
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
class FakeWebsiteModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
protected $type = 'website';
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'id' => Field_Type_Validation_Enum::INT,
|
||||
'type' => Field_Type_Validation_Enum::STRING,
|
||||
'url' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
public function relationships() {
|
||||
return new Relationship_Collection( array() );
|
||||
}
|
||||
}
|
||||
|
||||
class FakePhoneModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
protected $type = 'phone';
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'id' => Field_Type_Validation_Enum::INT,
|
||||
'type' => Field_Type_Validation_Enum::STRING,
|
||||
'number' => Field_Type_Validation_Enum::INT,
|
||||
'countryCode' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
public function relationships() {
|
||||
return new Relationship_Collection( array() );
|
||||
}
|
||||
}
|
||||
|
||||
class FakeEmailModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
|
||||
protected $type = 'email';
|
||||
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'id' => Field_Type_Validation_Enum::INT,
|
||||
'address' => Field_Type_Validation_Enum::STRING,
|
||||
'type' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
public function relationships() {
|
||||
return new Relationship_Collection( array() );
|
||||
}
|
||||
}
|
||||
|
||||
class FakeContactModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
|
||||
protected $type = 'contact';
|
||||
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'id' => Field_Type_Validation_Enum::INT,
|
||||
'firstName' => Field_Type_Validation_Enum::STRING,
|
||||
'lastName' => Field_Type_Validation_Enum::STRING,
|
||||
'profile_picture' => Field_Type_Validation_Enum::INT,
|
||||
'foobar' => function ( $value ) {
|
||||
if ( $value === 'foo' ) {
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public function meta_fields() {
|
||||
return array(
|
||||
'secondary_phone' => Field_Type_Validation_Enum::STRING,
|
||||
'alternate_website' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
public function transformations() {
|
||||
return array(
|
||||
'transformMakeThumb' => function ( $thumb_id, $thumb_type = 'hexagon', $thumb_size = 'medium' ) {
|
||||
return sprintf( 'thumbnail_url:%s/%s/%s', $thumb_id, $thumb_type, $thumb_size );
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public function relationships() {
|
||||
return new \Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship_Collection(
|
||||
array(
|
||||
new Relationship( 'contact', 'email', 'manage_options', false, 'one_to_many' ),
|
||||
new Relationship( 'contact', 'phone', 'manage_options', false, 'one_to_many' ),
|
||||
new Relationship( 'contact', 'website', 'manage_options', false, 'one_to_many' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeCompanyModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
|
||||
protected $type = 'company';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'id' => Field_Type_Validation_Enum::STRING,
|
||||
'companyName' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function transformations() {
|
||||
return array(
|
||||
'transformMakeFoo' => function ( $arg, $value ) {
|
||||
return sprintf( "IM%s", $arg );
|
||||
},
|
||||
);
|
||||
}
|
||||
public function relationships() {
|
||||
$relationships = array(
|
||||
new Relationship( 'company', 'contact', 'manage_options' ),
|
||||
new Relationship( 'company', 'email', 'manage_options', false, 'one_to_many' ),
|
||||
new Relationship( 'company', 'phone', 'manage_options', false, 'one_to_many' ),
|
||||
new Relationship( 'company', 'website', 'manage_options', false, 'one_to_many' ),
|
||||
);
|
||||
|
||||
return new Relationship_Collection( $relationships );
|
||||
}
|
||||
}
|
||||
|
||||
class FakeGroupModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
|
||||
protected $type = 'group';
|
||||
|
||||
protected $fields = array(
|
||||
'label',
|
||||
);
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'label' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function relationships() {
|
||||
return new \Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship_Collection(
|
||||
array(
|
||||
new \Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship( 'group', 'contact', 'manage_options' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeDealModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
|
||||
protected $type = 'deal';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'label' => Field_Type_Validation_Enum::STRING,
|
||||
'value' => Field_Type_Validation_Enum::INT,
|
||||
'id' => Field_Type_Validation_Enum::INT,
|
||||
);
|
||||
}
|
||||
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function relationships() {
|
||||
return new \Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship_Collection(
|
||||
array(
|
||||
new \Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship( 'deal', 'stage', 'manage_options', true, 'one_to_many' ),
|
||||
new Relationship( 'deal', 'user', 'manage_options', true, 'one_to_many' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeStageModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
|
||||
protected $type = 'stage';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'id' => Field_Type_Validation_Enum::INT,
|
||||
'label' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function relationships() {
|
||||
return new \Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship_Collection(
|
||||
array()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function gravitytools_tests_reset_db() {
|
||||
echo "\r\n";
|
||||
echo '=========================================' . "\r\n";
|
||||
echo 'Cleaning up test database for next run...' . "\r\n";
|
||||
global $wpdb;
|
||||
|
||||
$tables = array(
|
||||
'contact',
|
||||
'company',
|
||||
'deal',
|
||||
'pipeline',
|
||||
'company_contact',
|
||||
'deal_company',
|
||||
'deal_contact',
|
||||
'address',
|
||||
'social',
|
||||
'meta',
|
||||
'email',
|
||||
'phone',
|
||||
'website',
|
||||
'stage',
|
||||
);
|
||||
|
||||
foreach ( $tables as $table ) {
|
||||
$table_name = sprintf( '%s%s_%s', $wpdb->prefix, 'gravitycrm', $table );
|
||||
$sql = sprintf( 'TRUNCATE TABLE %s', $table_name );
|
||||
$wpdb->query( $sql );
|
||||
}
|
||||
|
||||
echo 'Done cleaning test database!' . "\r\n";
|
||||
echo '=========================================' . "\r\n";
|
||||
echo "\r\n";
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "gravityforms/gravity-tools",
|
||||
"description": "PHP libraries to support Gravity Forms applications.",
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src"
|
||||
]
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rocket Genius",
|
||||
"email": "info@rocketgenius.com"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"repositories": [
|
||||
{
|
||||
"url": "https://github.com/WordPress/wordpress-develop.git",
|
||||
"type": "git"
|
||||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"yoast/phpunit-polyfills": "4.0.0",
|
||||
"lucatume/function-mocker": "~2.0",
|
||||
"wordpress/wordpress": "dev-master"
|
||||
}
|
||||
}
|
||||
+2097
File diff suppressed because it is too large
Load Diff
+674
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<phpunit bootstrap="bootstrap.php">
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Gravity Tools tests.">
|
||||
<directory>./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
</phpunit>
|
||||
Vendored
+645
@@ -0,0 +1,645 @@
|
||||
<?php
|
||||
namespace Gravity_Forms\Gravity_Tools\API;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Model\Form_Model;
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
use WP_Error;
|
||||
|
||||
if ( ! defined( 'GRAVITY_API_URL' ) ) {
|
||||
define( 'GRAVITY_API_URL', 'https://gravityapi.com/wp-json/gravityapi/v1' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Client-side API wrapper for interacting with the Gravity APIs.
|
||||
*
|
||||
* @package Gravity Tools
|
||||
* @since 1.0
|
||||
*/
|
||||
class Gravity_Api {
|
||||
|
||||
/**
|
||||
* @var Common
|
||||
*/
|
||||
protected $common;
|
||||
|
||||
/**
|
||||
* @var Form_Model
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $common
|
||||
* @param $model
|
||||
* @param $namespace
|
||||
*/
|
||||
public function __construct( $common, $model, $namespace ) {
|
||||
$this->common = $common;
|
||||
$this->model = $model;
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves site key and site secret key from remote API and stores them as WP options. Returns false if license key is invalid; otherwise, returns true.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $license_key License key to be registered.
|
||||
* @param boolean $is_md5 Specifies if $license_key provided is an MD5 or unhashed license key.
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function register_current_site( $license_key, $is_md5 = false ) {
|
||||
$body = array();
|
||||
$body['site_name'] = get_bloginfo( 'name' );
|
||||
$body['site_url'] = get_bloginfo( 'url' );
|
||||
|
||||
if ( $is_md5 ) {
|
||||
$body['license_key_md5'] = $license_key;
|
||||
} else {
|
||||
$body['license_key'] = $license_key;
|
||||
}
|
||||
|
||||
$result = $this->request( 'sites', $body, 'POST', array( 'headers' => $this->get_license_auth_header( $license_key ) ) );
|
||||
$result = $this->prepare_response_body( $result, true );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
update_option( 'gf_site_key', $result['key'] );
|
||||
update_option( 'gf_site_secret', $result['secret'] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates license key for a site that has already been registered.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $new_license_key_md5 Hash license key to be updated
|
||||
*
|
||||
* @return \Gravity_Forms\Gravity_Tools\License\License_API_Response|WP_Error
|
||||
*/
|
||||
public function update_current_site( $new_license_key_md5 ) {
|
||||
|
||||
$site_key = $this->get_site_key();
|
||||
$site_secret = $this->get_site_secret();
|
||||
if ( empty( $site_key ) || empty( $site_secret ) ) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = $this->get_remote_post_params();
|
||||
$body['site_name'] = get_bloginfo( 'name' );
|
||||
$body['site_url'] = get_bloginfo( 'url' );
|
||||
$body['site_key'] = $site_key;
|
||||
$body['site_secret'] = $site_secret;
|
||||
$body['license_key_md5'] = $new_license_key_md5;
|
||||
|
||||
$result = $this->request( 'sites/' . $site_key, $body, 'PUT', array( 'headers' => $this->get_site_auth_header( $site_key, $site_secret ) ) );
|
||||
$result = $this->prepare_response_body( $result, true );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/***
|
||||
* Removes a license key from a registered site. NOTE: It doesn't actually deregister the site.
|
||||
*
|
||||
* @deprecated Use gapi()->update_current_site('') instead.
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function deregister_current_site() {
|
||||
$site_key = $this->get_site_key();
|
||||
$site_secret = $this->get_site_secret();
|
||||
|
||||
if ( empty( $site_key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = array(
|
||||
'license_key_md5' => '',
|
||||
);
|
||||
|
||||
$result = $this->request( 'sites/' . $site_key, $body, 'PUT', array( 'headers' => $this->get_site_auth_header( $site_key, $site_secret ) ) );
|
||||
$result = $this->prepare_response_body( $result, true );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given license key to get its information from the API.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $key The license key.
|
||||
*
|
||||
* @return array|false|WP_Error
|
||||
*/
|
||||
public function check_license( $key ) {
|
||||
$params = array(
|
||||
'site_url' => get_option( 'home' ),
|
||||
'is_multisite' => is_multisite(),
|
||||
);
|
||||
|
||||
/**
|
||||
* Allow the params passed to check_license to be modified before sending.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
$params = apply_filters( 'gravity_api_check_license_params', $params );
|
||||
|
||||
$resource = 'licenses/' . $key . '/check?' . build_query( $params );
|
||||
$result = $this->request( $resource, null );
|
||||
$result = $this->prepare_response_body( $result, true );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$response = $result;
|
||||
|
||||
if ( $this->common->rgar( $result, 'license' ) ) {
|
||||
$response = $this->common->rgar( $result, 'license' );
|
||||
}
|
||||
|
||||
// Set the license object to the transient.
|
||||
set_transient( 'rg_gforms_license', $response, DAY_IN_SECONDS );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GF core and add-on family information.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return false|array
|
||||
*/
|
||||
public function get_plugins_info() {
|
||||
$version_info = $this->get_version_info();
|
||||
|
||||
if ( empty( $version_info['offerings'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $version_info['offerings'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get version information from the Gravity Manager API.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param false $cache
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_version_info( $cache = false ) {
|
||||
|
||||
$version_info = null;
|
||||
|
||||
if ( $cache ) {
|
||||
$cache_key = sprintf( '%s_version_info', $this->namespace );
|
||||
$cached_info = get_option( $cache_key );
|
||||
|
||||
// Checking cache expiration
|
||||
$cache_duration = DAY_IN_SECONDS; // 24 hours.
|
||||
$cache_timestamp = $cached_info && isset( $cached_info['timestamp'] ) ? $cached_info['timestamp'] : 0;
|
||||
|
||||
// Is cache expired? If not, set $version_info to the cached data.
|
||||
if ( $cache_timestamp + $cache_duration >= time() ) {
|
||||
$version_info = $cached_info;
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_wp_error( $version_info ) || isset( $version_info['headers'] ) ) {
|
||||
// Legacy ( < 2.1.1.14 ) version info contained the whole raw response.
|
||||
$version_info = null;
|
||||
}
|
||||
|
||||
// If we reach this point with a $version_info array, it's from cache, and we can return it.
|
||||
if ( $version_info ) {
|
||||
return $version_info;
|
||||
}
|
||||
|
||||
//Getting version number
|
||||
$options = array(
|
||||
'method' => 'POST',
|
||||
'timeout' => 20,
|
||||
);
|
||||
|
||||
$options['headers'] = array(
|
||||
'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ),
|
||||
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
|
||||
);
|
||||
|
||||
$options['body'] = $this->get_remote_post_params();
|
||||
$options['timeout'] = 15;
|
||||
|
||||
$nocache = $cache ? '' : 'nocache=1'; //disabling server side caching
|
||||
|
||||
$raw_response = $this->common->post_to_manager( 'version.php', $nocache, $options );
|
||||
$version_info = array(
|
||||
'is_valid_key' => '1',
|
||||
'version' => '',
|
||||
'url' => '',
|
||||
'is_error' => '1',
|
||||
);
|
||||
|
||||
if ( is_wp_error( $raw_response ) || $this->common->rgars( $raw_response, 'response/code' ) != 200 ) {
|
||||
$version_info['timestamp'] = time();
|
||||
|
||||
return $version_info;
|
||||
}
|
||||
|
||||
$decoded = json_decode( $raw_response['body'], true );
|
||||
|
||||
if ( empty( $decoded ) ) {
|
||||
$version_info['timestamp'] = time();
|
||||
|
||||
return $version_info;
|
||||
}
|
||||
|
||||
$decoded['timestamp'] = time();
|
||||
|
||||
// Caching response.
|
||||
$cache_key = sprintf( '%s_version_info', $this->namespace );
|
||||
update_option( $cache_key, $decoded, false ); //caching version info
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameters to use in a remote request.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_remote_post_params() {
|
||||
|
||||
// This can get called in contexts where this file isn't loaded. Require it here to avoid fatals.
|
||||
if ( ! function_exists( 'get_plugins' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$plugin_list = get_plugins();
|
||||
$plugins = array();
|
||||
|
||||
$active_plugins = get_option( 'active_plugins' );
|
||||
|
||||
foreach ( $plugin_list as $key => $plugin ) {
|
||||
$is_active = in_array( $key, $active_plugins );
|
||||
|
||||
$slug = substr( $key, 0, strpos( $key, '/' ) );
|
||||
if ( empty( $slug ) ) {
|
||||
$slug = str_replace( '.php', '', $key );
|
||||
}
|
||||
|
||||
$plugins[] = array(
|
||||
'name' => str_replace( 'phpinfo()', 'PHP Info', $plugin['Name'] ),
|
||||
'slug' => $slug,
|
||||
'version' => $plugin['Version'],
|
||||
'is_active' => $is_active,
|
||||
);
|
||||
}
|
||||
|
||||
$plugins = json_encode( $plugins );
|
||||
|
||||
//get theme info
|
||||
$theme = wp_get_theme();
|
||||
$theme_name = $theme->get( 'Name' );
|
||||
$theme_uri = $theme->get( 'ThemeURI' );
|
||||
$theme_version = $theme->get( 'Version' );
|
||||
$theme_author = $theme->get( 'Author' );
|
||||
$theme_author_uri = $theme->get( 'AuthorURI' );
|
||||
|
||||
$im = is_multisite();
|
||||
$lang = get_locale();
|
||||
|
||||
$post = array(
|
||||
'plugins' => $plugins,
|
||||
'tn' => $theme_name,
|
||||
'tu' => $theme_uri,
|
||||
'tv' => $theme_version,
|
||||
'ta' => $theme_author,
|
||||
'tau' => $theme_author_uri,
|
||||
'im' => $im,
|
||||
'lang' => $lang,
|
||||
);
|
||||
|
||||
/**
|
||||
* Allows the remote post parameters to be filtered to add more data.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param array $post The current data array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
return apply_filters( 'gravity_api_remote_post_params', $post );;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the usage data (call version.php in Gravity Manager). We will replace it once we have statistics API endpoints.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function update_site_data() {
|
||||
|
||||
// Whenever we update the plugins info, we call the versions.php to update usage data.
|
||||
$options = array( 'method' => 'POST' );
|
||||
$options['headers'] = array(
|
||||
'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ),
|
||||
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
|
||||
'Referer' => get_bloginfo( 'url' ),
|
||||
);
|
||||
$options['body'] = $this->common->get_remote_post_params();
|
||||
// Set the version to 3 which lightens the burden of version.php, it won't return anything to us anymore.
|
||||
$options['body']['version'] = '3';
|
||||
$options['timeout'] = 15;
|
||||
|
||||
$nocache = 'nocache=1'; //disabling server side caching
|
||||
|
||||
$this->common->post_to_manager( 'version.php', $nocache, $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email to Hubspot to add to the list.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $email
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function send_email_to_hubspot( $email ) {
|
||||
$body = array(
|
||||
'email' => $email,
|
||||
);
|
||||
|
||||
$result = $this->request( 'emails/installation/add-to-list', $body, 'POST', array( 'headers' => $this->get_license_info_header( $site_secret ) ) );
|
||||
$result = $this->prepare_response_body( $result, true );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// # HELPERS
|
||||
|
||||
/**
|
||||
* Get the stored license key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_key() {
|
||||
return $this->common->get_key();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the site auth header.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $site_key
|
||||
* @param $site_secret
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function get_site_auth_header( $site_key, $site_secret ) {
|
||||
|
||||
$auth = base64_encode( "{$site_key}:{$site_secret}" );
|
||||
|
||||
return array( 'Authorization' => 'GravityAPI ' . $auth );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license info header.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $site_secret
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function get_license_info_header( $site_secret ) {
|
||||
$auth = base64_encode( "gravityforms.com:{$site_secret}" );
|
||||
|
||||
return array( 'Authorization' => 'GravityAPI ' . $auth );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license auth header.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $license_key_md5
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function get_license_auth_header( $license_key_md5 ) {
|
||||
|
||||
$auth = base64_encode( "license:{$license_key_md5}" );
|
||||
|
||||
return array( 'Authorization' => 'GravityAPI ' . $auth );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare response body.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param WP_Error|WP_REST_Response $raw_response The API response.
|
||||
* @param bool $as_array Whether to return the response as an array or object.
|
||||
*
|
||||
* @return array|object|WP_Error
|
||||
*/
|
||||
public function prepare_response_body( $raw_response, $as_array = false ) {
|
||||
|
||||
if ( is_wp_error( $raw_response ) ) {
|
||||
return $raw_response;
|
||||
}
|
||||
|
||||
$response_body = json_decode( wp_remote_retrieve_body( $raw_response ), $as_array );
|
||||
$response_code = wp_remote_retrieve_response_code( $raw_response );
|
||||
$response_message = wp_remote_retrieve_response_message( $raw_response );
|
||||
|
||||
if ( $response_code > 200 ) {
|
||||
|
||||
// If a WP_Error was returned in the body.
|
||||
if ( $this->common->rgar( $response_body, 'code' ) ) {
|
||||
|
||||
// Restore the WP_Error.
|
||||
$error = new WP_Error( $response_body['code'], $response_body['message'], $response_body['data'] );
|
||||
} else {
|
||||
$error = new WP_Error( 'server_error', 'Error from server: ' . $response_message );
|
||||
}
|
||||
|
||||
return $error;
|
||||
|
||||
}
|
||||
|
||||
return $response_body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge the site credentials.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function purge_site_credentials() {
|
||||
|
||||
delete_option( 'gf_site_key' );
|
||||
delete_option( 'gf_site_secret' );
|
||||
delete_option( 'gf_site_registered' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Making API requests.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $resource The API route.
|
||||
* @param array $body The request body.
|
||||
* @param string $method The method.
|
||||
* @param array $options The options.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function request( $resource, $body, $method = 'POST', $options = array() ) {
|
||||
$body['timestamp'] = time();
|
||||
|
||||
// set default options
|
||||
$options = wp_parse_args( $options, array(
|
||||
'method' => $method,
|
||||
'timeout' => 10,
|
||||
'body' => in_array( $method, array( 'GET', 'DELETE' ) ) ? null : json_encode( $body ),
|
||||
'headers' => array(),
|
||||
'sslverify' => false,
|
||||
) );
|
||||
|
||||
// set default header options
|
||||
$options['headers'] = wp_parse_args( $options['headers'], array(
|
||||
'Content-Type' => 'application/json; charset=' . get_option( 'blog_charset' ),
|
||||
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
|
||||
'Referer' => get_bloginfo( 'url' ),
|
||||
) );
|
||||
|
||||
// WP docs say method should be uppercase
|
||||
$options['method'] = strtoupper( $options['method'] );
|
||||
|
||||
$request_url = $this->get_gravity_api_url() . $resource;
|
||||
|
||||
return wp_remote_request( $request_url, $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the site key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return false|mixed|void
|
||||
*/
|
||||
public function get_site_key() {
|
||||
|
||||
if ( defined( 'GRAVITY_API_SITE_KEY' ) ) {
|
||||
return GRAVITY_API_SITE_KEY;
|
||||
}
|
||||
|
||||
$site_key = get_option( 'gf_site_key' );
|
||||
if ( empty( $site_key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $site_key;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the site secret.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return false|mixed|void
|
||||
*/
|
||||
public function get_site_secret() {
|
||||
if ( defined( 'GRAVITY_API_SITE_SECRET' ) ) {
|
||||
return GRAVITY_API_SITE_SECRET;
|
||||
}
|
||||
$site_secret = get_option( 'gf_site_secret' );
|
||||
if ( empty( $site_secret ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $site_secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the gravity URL.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_gravity_api_url() {
|
||||
return trailingslashit( GRAVITY_API_URL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the site has the gf_site_key and gf_site_secret options.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_site_registered() {
|
||||
return $this->get_site_key() && $this->get_site_secret();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the site has the gf_site_key, gf_site_secret and also the gf_site_registered options.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_legacy_registration() {
|
||||
return $this->is_site_registered() && ! get_option( 'gf_site_registered' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vendored
+96
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\API;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Data\Oauth_Data_Handler;
|
||||
|
||||
abstract class Oauth_Handler {
|
||||
|
||||
protected $supports_refresh_token = false;
|
||||
|
||||
protected $response_payload_name = 'auth_payload';
|
||||
|
||||
protected $payload_access_token_name = 'access_token';
|
||||
|
||||
protected $payload_refresh_token_name = 'refresh_token';
|
||||
|
||||
protected $namespace = '';
|
||||
|
||||
/**
|
||||
* @var Oauth_Data_Handler $data
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
public function __construct( $data ) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function handle_response() {
|
||||
if ( ! $this->is_response() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payload = filter_input( INPUT_POST, $this->response_payload_name );
|
||||
|
||||
if ( is_string( $payload ) ) {
|
||||
$payload = json_decode( $payload, true );
|
||||
}
|
||||
|
||||
if ( empty( $payload ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isset( $payload[ $this->payload_access_token_name ] ) ) {
|
||||
$this->store_access_token( $payload[ $this->payload_access_token_name ] );
|
||||
}
|
||||
|
||||
if ( isset( $payload[ $this->payload_refresh_token_name ] ) ) {
|
||||
$this->store_refresh_token( $payload[ $this->payload_refresh_token_name ] );
|
||||
}
|
||||
}
|
||||
|
||||
public function get_access_token() {
|
||||
$token = $this->data->get( 'access_token', $this->namespace );
|
||||
|
||||
if ( $this->is_valid_token( $token ) ) {
|
||||
return $token;
|
||||
}
|
||||
|
||||
if ( ! $this->supports_refresh_token ) {
|
||||
return new \WP_Error( __( 'Token is invalid or expired. Please re-connect.', 'gravity-tools' ) );
|
||||
}
|
||||
|
||||
return $this->refresh_expired_token();
|
||||
}
|
||||
|
||||
public function get_refresh_token() {
|
||||
return $this->data->get( 'refresh_token', $this->namespace );
|
||||
}
|
||||
|
||||
protected function refresh_expired_token() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function store_access_token( $token ) {
|
||||
$this->data->save( 'access_token', $token, $this->namespace );
|
||||
}
|
||||
|
||||
protected function store_refresh_token( $refresh_token ) {
|
||||
$this->data->save( 'refresh_token', $refresh_token, $this->namespace );
|
||||
}
|
||||
|
||||
protected function is_response() {
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract public function get_return_url();
|
||||
|
||||
abstract public function get_oauth_url();
|
||||
|
||||
abstract public function get_refresh_url();
|
||||
|
||||
abstract protected function is_valid_token( $token );
|
||||
|
||||
abstract public function get_connection_details();
|
||||
|
||||
}
|
||||
Vendored
+99
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Apps;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Providers\Config_Collection_Service_Provider;
|
||||
use Gravity_Forms\Gravity_Tools\Config\App_Config;
|
||||
|
||||
trait Registers_Apps {
|
||||
|
||||
//----------------------------------------
|
||||
//---------- App Registration ------------
|
||||
//----------------------------------------
|
||||
|
||||
/**
|
||||
* Register a JS app with the given arguments.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
public function register_app( $args ) {
|
||||
$config = new App_Config( $this->container->get( Config_Collection_Service_Provider::DATA_PARSER ) );
|
||||
$config->set_data( $args );
|
||||
|
||||
$this->container->get( Config_Collection_Service_Provider::CONFIG_COLLECTION )->add_config( $config );
|
||||
|
||||
$should_display = is_callable( $args['enqueue'] ) ? call_user_func( $args['enqueue'] ) : $args['enqueue'];
|
||||
|
||||
if ( ! $should_display ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! empty( $args['css'] ) ) {
|
||||
$this->enqueue_app_css( $args );
|
||||
}
|
||||
|
||||
if ( ! empty( $args['root_element'] ) ) {
|
||||
$this->add_root_element( $args['root_element'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the CSS assets for the app.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $args
|
||||
*/
|
||||
protected function enqueue_app_css( $args ) {
|
||||
$css_asset = $args['css'];
|
||||
|
||||
add_action( 'wp_enqueue_scripts', function () use ( $css_asset ) {
|
||||
call_user_func_array( 'wp_enqueue_style', $css_asset );
|
||||
} );
|
||||
|
||||
add_action( 'admin_enqueue_scripts', function () use ( $css_asset ) {
|
||||
call_user_func_array( 'wp_enqueue_style', $css_asset );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the root element to the footer output for bootstrapping.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $root
|
||||
*/
|
||||
protected function add_root_element( $root ) {
|
||||
$self = $this;
|
||||
add_action( $this->get_inject_action(), function() use ( $root, $self ) {
|
||||
echo $self->get_root_markup( $root );
|
||||
}, 10, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* The markup for the root element of the app.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $root
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_root_markup( $root ) {
|
||||
return '<div data-js="' . $root . '"></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the action name for injecting app root.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_inject_action() {
|
||||
return 'admin_footer';
|
||||
}
|
||||
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Assets;
|
||||
|
||||
class Asset_Processor {
|
||||
/**
|
||||
* @var array $map - The Hash Map generated by our node scripts.
|
||||
*/
|
||||
private $js_map;
|
||||
|
||||
/**
|
||||
* @var string $asset_path - The path to the js dist directory.
|
||||
*/
|
||||
private $js_asset_path;
|
||||
|
||||
/**
|
||||
* @var string $match_pattern - The pattern to match against when identifying scripts to process.
|
||||
*/
|
||||
private $js_match_pattern;
|
||||
|
||||
/**
|
||||
* @var array $map - The Hash Map generated by our node scripts.
|
||||
*/
|
||||
private $css_map;
|
||||
|
||||
/**
|
||||
* @var string $asset_path - The path to the css dist directory.
|
||||
*/
|
||||
private $css_asset_path;
|
||||
|
||||
/**
|
||||
* @var string $match_pattern - The pattern to match against when identifying scripts to process.
|
||||
*/
|
||||
private $css_match_pattern;
|
||||
|
||||
private $constant_name;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param array $map
|
||||
* @param string $asset_path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $js_map, $css_map, $js_asset_path, $css_asset_path, $js_match_pattern, $css_match_pattern, $constant_name ) {
|
||||
$this->js_map = $js_map;
|
||||
$this->js_asset_path = $js_asset_path;
|
||||
$this->js_match_pattern = $js_match_pattern;
|
||||
$this->css_map = $css_map;
|
||||
$this->css_asset_path = $css_asset_path;
|
||||
$this->css_match_pattern = $css_match_pattern;
|
||||
$this->constant_name = $constant_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing actions on assets.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process_assets() {
|
||||
$this->process_scripts();
|
||||
$this->process_styles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the ver values for all of the registered scripts in order to append a
|
||||
* file hash (if it exists) or the filemtime (if required).
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function process_scripts() {
|
||||
global $wp_scripts;
|
||||
|
||||
$registered = $wp_scripts->registered;
|
||||
|
||||
foreach ( $registered as &$asset ) {
|
||||
|
||||
// Bail if not one of our assets.
|
||||
if ( strpos( $asset->src, $this->js_match_pattern ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$basename = basename( $asset->src );
|
||||
$path = sprintf( '%s/%s', $this->js_asset_path, $basename );
|
||||
|
||||
// Asset doesn't exist in hash_map, skip.
|
||||
if ( ! array_key_exists( $basename, $this->js_map ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The hash is either the value from our map, or the filemtime for dev.
|
||||
$hash = defined( $this->constant_name ) && constant( $this->constant_name ) ?
|
||||
filemtime( $path ) :
|
||||
$this->js_map[ $basename ]['version'];
|
||||
|
||||
$asset->ver = $hash;
|
||||
}
|
||||
|
||||
$wp_scripts->registered = $registered;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the ver values for all of the registered scripts in order to append a
|
||||
* file hash (if it exists) or the filemtime (if required).
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function process_styles() {
|
||||
global $wp_styles;
|
||||
|
||||
$registered = $wp_styles->registered;
|
||||
|
||||
foreach ( $registered as &$asset ) {
|
||||
|
||||
// Bail if not one of our assets.
|
||||
if ( strpos( $asset->src, $this->css_match_pattern ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$basename = basename( $asset->src );
|
||||
$path = sprintf( '%s/%s', $this->css_asset_path, $basename );
|
||||
|
||||
// Asset doesn't exist in hash_map, skip.
|
||||
if ( ! array_key_exists( $basename, $this->css_map ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The hash is either the value from our map, or the filemtime for dev.
|
||||
$hash = defined( $this->constant_name ) && constant( $this->constant_name ) ?
|
||||
filemtime( $path ) :
|
||||
$this->css_map[ $basename ]['version'];
|
||||
|
||||
$asset->ver = $hash;
|
||||
}
|
||||
|
||||
$wp_styles->registered = $registered;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
+806
@@ -0,0 +1,806 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Background_Processing;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Cache\Cache;
|
||||
use Gravity_Forms\Gravity_Tools\Logging\Logger;
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
|
||||
/**
|
||||
* Abstract Background_Process class.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @abstract
|
||||
* @extends WP_Async_Request
|
||||
*/
|
||||
abstract class Background_Process extends WP_Async_Request {
|
||||
|
||||
/**
|
||||
* Action
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* (default value: 'background_process')
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $action = 'background_process';
|
||||
|
||||
/**
|
||||
* Start time of current process.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* (default value: 0)
|
||||
*
|
||||
* @var int
|
||||
* @access protected
|
||||
*/
|
||||
protected $start_time = 0;
|
||||
|
||||
/**
|
||||
* Cron_hook_identifier
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @var mixed
|
||||
* @access protected
|
||||
*/
|
||||
protected $cron_hook_identifier;
|
||||
|
||||
/**
|
||||
* Cron_interval_identifier
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @var mixed
|
||||
* @access protected
|
||||
*/
|
||||
protected $cron_interval_identifier;
|
||||
|
||||
/**
|
||||
* Query_url
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $query_url;
|
||||
|
||||
/**
|
||||
* @var Common
|
||||
*/
|
||||
protected $utils;
|
||||
|
||||
/**
|
||||
* @var Logger
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* @var Cache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Initiate new background process
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function __construct( Common $utils, Logger $logger, Cache $cache ) {
|
||||
parent::__construct();
|
||||
|
||||
$this->utils = $utils;
|
||||
$this->logger = $logger;
|
||||
$this->cache = $cache;
|
||||
|
||||
$this->query_url = admin_url( 'admin-ajax.php' );
|
||||
$this->cron_hook_identifier = $this->identifier . '_cron';
|
||||
$this->cron_interval_identifier = $this->identifier . '_cron_interval';
|
||||
|
||||
add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
|
||||
add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the queued tasks to Admin Ajax for processing and schedules a cron job in case processing fails.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function dispatch() {
|
||||
// @todo implement logging
|
||||
$this->logger->log_debug( sprintf( '%s(): Running for %s.', __METHOD__, $this->action ) );
|
||||
|
||||
if ( $this->is_queue_empty() ) {
|
||||
$this->clear_scheduled_event();
|
||||
|
||||
$dispatched = new \WP_Error( 'queue_empty', 'Nothing left to process' );
|
||||
} else {
|
||||
// Schedule the cron healthcheck.
|
||||
$this->schedule_event();
|
||||
|
||||
// Perform remote post.
|
||||
$dispatched = parent::dispatch();
|
||||
}
|
||||
|
||||
if ( is_wp_error( $dispatched ) ) {
|
||||
$this->logger->log_debug( sprintf( '%s(): Unable to dispatch tasks to Admin Ajax: %s', __METHOD__, $dispatched->get_error_message() ) );
|
||||
}
|
||||
|
||||
return $dispatched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dispatch request arguments.
|
||||
*
|
||||
* @since 2.3-rc-2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_post_args() {
|
||||
$post_args = parent::get_post_args();
|
||||
|
||||
// Blocking prevents some issues such as cURL connection errors being reported.
|
||||
unset( $post_args['blocking'] );
|
||||
|
||||
return $post_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push to queue
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function push_to_queue( $data ) {
|
||||
$this->data[] = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save queue
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function save() {
|
||||
$key = $this->generate_key();
|
||||
|
||||
if ( ! empty( $this->data ) ) {
|
||||
$data = array(
|
||||
'blog_id' => get_current_blog_id(),
|
||||
'data' => $this->data,
|
||||
);
|
||||
update_site_option( $key, $data );
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update queue
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $key Key.
|
||||
* @param array $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function update( $key, $data ) {
|
||||
if ( ! empty( $data ) ) {
|
||||
$old_value = get_site_option( $key );
|
||||
if ( $old_value ) {
|
||||
$this->logger->log_debug( sprintf( '%s(): Updating batch %s. Tasks remaining: %d.', __METHOD__, $key, count( $data ) ) );
|
||||
$data = array(
|
||||
'blog_id' => get_current_blog_id(),
|
||||
'data' => $data,
|
||||
);
|
||||
update_site_option( $key, $data );
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete queue
|
||||
*
|
||||
* @param string $key Key.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function delete( $key ) {
|
||||
$this->logger->log_debug( sprintf( '%s(): Deleting batch %s.', __METHOD__, $key ) );
|
||||
delete_site_option( $key );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate key
|
||||
*
|
||||
* Generates a unique key based on microtime. Queue items are
|
||||
* given a unique key so that they can be merged upon save.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param int $length Length.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_key( $length = 64 ) {
|
||||
$unique = md5( microtime() . rand() );
|
||||
$prepend = $this->identifier . '_batch_blog_id_' . get_current_blog_id() . '_';
|
||||
|
||||
return substr( $prepend . $unique, 0, $length );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe process queue
|
||||
*
|
||||
* Checks whether data exists within the queue and that
|
||||
* the process is not already running.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function maybe_handle() {
|
||||
$this->logger->log_debug( sprintf( '%s(): Running for %s.', __METHOD__, $this->action ) );
|
||||
|
||||
// Don't lock up other requests while processing
|
||||
session_write_close();
|
||||
|
||||
if ( $this->is_process_running() ) {
|
||||
// Background process already running.
|
||||
wp_die();
|
||||
}
|
||||
|
||||
if ( $this->is_queue_empty() ) {
|
||||
// No data to process.
|
||||
wp_die();
|
||||
}
|
||||
|
||||
check_ajax_referer( $this->identifier, 'nonce' );
|
||||
|
||||
$this->handle();
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is queue empty
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_queue_empty() {
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->options;
|
||||
$column = 'option_name';
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$table = $wpdb->sitemeta;
|
||||
$column = 'meta_key';
|
||||
}
|
||||
|
||||
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
|
||||
|
||||
$count = $wpdb->get_var( $wpdb->prepare( "
|
||||
SELECT COUNT(*)
|
||||
FROM {$table}
|
||||
WHERE {$column} LIKE %s
|
||||
", $key ) );
|
||||
|
||||
return ( $count > 0 ) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is process running
|
||||
*
|
||||
* Check whether the current process is already running
|
||||
* in a background process.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
protected function is_process_running() {
|
||||
$running = false;
|
||||
$lock_timestamp = get_site_option( $this->identifier . '_process_lock' );
|
||||
if ( $lock_timestamp ) {
|
||||
|
||||
$lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
|
||||
$lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
|
||||
|
||||
if ( microtime( true ) - $lock_timestamp > $lock_duration ) {
|
||||
$this->unlock_process();
|
||||
} else {
|
||||
$running = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $running;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock process
|
||||
*
|
||||
* Lock the process so that multiple instances can't run simultaneously.
|
||||
* Override if applicable, but the duration should be greater than that
|
||||
* defined in the time_exceeded() method.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
protected function lock_process() {
|
||||
$this->start_time = time(); // Set start time of current process.
|
||||
|
||||
update_site_option( $this->identifier . '_process_lock', microtime( true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock process
|
||||
*
|
||||
* Unlock the process so that other instances can spawn.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function unlock_process() {
|
||||
delete_site_option( $this->identifier . '_process_lock' );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get batch
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return stdClass Return the first batch from the queue
|
||||
*/
|
||||
protected function get_batch() {
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->options;
|
||||
$column = 'option_name';
|
||||
$key_column = 'option_id';
|
||||
$value_column = 'option_value';
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$table = $wpdb->sitemeta;
|
||||
$column = 'meta_key';
|
||||
$key_column = 'meta_id';
|
||||
$value_column = 'meta_value';
|
||||
}
|
||||
|
||||
$key = $wpdb->esc_like( $this->identifier . '_batch_blog_id_' . get_current_blog_id() . '_' ) . '%';
|
||||
|
||||
$sql = "
|
||||
SELECT *
|
||||
FROM {$table}
|
||||
WHERE {$column} LIKE %s
|
||||
ORDER BY {$key_column} ASC
|
||||
LIMIT 1
|
||||
";
|
||||
|
||||
$query = $wpdb->get_row( $wpdb->prepare( $sql, $key ) );
|
||||
|
||||
if ( empty( $query ) ) {
|
||||
// No more batches for this blog ID. Get the next one in the queue regardless of the blog ID.
|
||||
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
|
||||
$query = $wpdb->get_row( $wpdb->prepare( $sql, $key ) );
|
||||
}
|
||||
|
||||
$batch = new \stdClass();
|
||||
$batch->key = $query->$column;
|
||||
$value = maybe_unserialize( $query->$value_column );
|
||||
$batch->data = $value['data'];
|
||||
$batch->blog_id = $value['blog_id'];
|
||||
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle
|
||||
*
|
||||
* Pass each queue item to the task handler, while remaining
|
||||
* within server memory and time limit constraints.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
protected function handle() {
|
||||
$this->lock_process();
|
||||
|
||||
do {
|
||||
$batch = $this->get_batch();
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$current_blog_id = get_current_blog_id();
|
||||
if ( $current_blog_id !== $batch->blog_id ) {
|
||||
$this->spawn_multisite_child_process( $batch->blog_id );
|
||||
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
|
||||
// Switch back to the current blog and return so the other tasks queued in this process can be run.
|
||||
switch_to_blog( $current_blog_id );
|
||||
|
||||
return;
|
||||
} else {
|
||||
wp_die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->log_debug( sprintf( '%s(): Processing batch %s; Tasks: %d.', __METHOD__, $batch->key, count( $batch->data ) ) );
|
||||
|
||||
$task_num = 0;
|
||||
|
||||
foreach ( $batch->data as $key => $value ) {
|
||||
$this->logger->log_debug( sprintf( '%s(): Processing task %d.', __METHOD__, ++ $task_num ) );
|
||||
$task = $this->task( $value );
|
||||
|
||||
if ( $task !== false ) {
|
||||
$this->logger->log_debug( sprintf( '%s(): Keeping task %d in batch.', __METHOD__, $task_num ) );
|
||||
$batch->data[ $key ] = $task;
|
||||
} else {
|
||||
$this->logger->log_debug( sprintf( '%s(): Removing task %d from batch.', __METHOD__, $task_num ) );
|
||||
unset( $batch->data[ $key ] );
|
||||
}
|
||||
|
||||
if ( $task !== false || $this->time_exceeded() || $this->memory_exceeded() ) {
|
||||
// Batch limits reached or task not complete.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update or delete current batch.
|
||||
if ( ! empty( $batch->data ) ) {
|
||||
$this->update( $batch->key, $batch->data );
|
||||
} else {
|
||||
$this->delete( $batch->key );
|
||||
}
|
||||
} while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
|
||||
|
||||
$this->logger->log_debug( sprintf( '%s(): Batch completed for %s.', __METHOD__, $this->action ) );
|
||||
|
||||
$this->unlock_process();
|
||||
|
||||
// Start next batch or complete process.
|
||||
if ( ! $this->is_queue_empty() ) {
|
||||
$this->dispatch();
|
||||
} else {
|
||||
$this->complete();
|
||||
}
|
||||
|
||||
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
|
||||
// Return so the other tasks queued in this process can be run.
|
||||
return;
|
||||
} else {
|
||||
wp_die();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn a new background process on the multisite that scheduled the current task
|
||||
*
|
||||
* @param int $blog_id
|
||||
*
|
||||
* @since 2.3
|
||||
*/
|
||||
protected function spawn_multisite_child_process( $blog_id ) {
|
||||
$this->logger->log_debug( sprintf( '%s(): Running for blog #%s.', __METHOD__, $blog_id ) );
|
||||
switch_to_blog( $blog_id );
|
||||
$this->query_url = admin_url( 'admin-ajax.php' );
|
||||
$this->unlock_process();
|
||||
$this->dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory exceeded
|
||||
*
|
||||
* Ensures the batch process never exceeds 90%
|
||||
* of the maximum WordPress memory.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function memory_exceeded() {
|
||||
$memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
|
||||
$current_memory = memory_get_usage( true );
|
||||
$return = false;
|
||||
|
||||
if ( $current_memory >= $memory_limit ) {
|
||||
$return = true;
|
||||
}
|
||||
|
||||
return apply_filters( $this->identifier . '_memory_exceeded', $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory limit
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_memory_limit() {
|
||||
if ( function_exists( 'ini_get' ) ) {
|
||||
$memory_limit = ini_get( 'memory_limit' );
|
||||
} else {
|
||||
// Sensible default.
|
||||
$memory_limit = '128M';
|
||||
}
|
||||
|
||||
if ( ! $memory_limit || - 1 === intval( $memory_limit ) ) {
|
||||
// Unlimited, set to 32GB.
|
||||
$memory_limit = '32G';
|
||||
}
|
||||
|
||||
return $this->convert_hr_to_bytes( $memory_limit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a shorthand byte value to an integer byte value.
|
||||
*
|
||||
* @param string $value A (PHP ini) byte value, either shorthand or ordinary.
|
||||
*
|
||||
* @return int An integer byte value.
|
||||
*/
|
||||
protected function convert_hr_to_bytes( $value ) {
|
||||
|
||||
// Globally available in WordPress 4.6
|
||||
if ( function_exists( 'wp_convert_hr_to_bytes' ) ) {
|
||||
return wp_convert_hr_to_bytes( $value );
|
||||
}
|
||||
|
||||
// Backwards compatible support for Wordpress 3.6 to 4.5
|
||||
$value = strtolower( trim( $value ) );
|
||||
$bytes = (int) $value;
|
||||
|
||||
if ( false !== strpos( $value, 'g' ) ) {
|
||||
$bytes *= pow( 1024, 3 );
|
||||
} elseif ( false !== strpos( $value, 'm' ) ) {
|
||||
$bytes *= pow( 1024, 2 );
|
||||
} elseif ( false !== strpos( $value, 'k' ) ) {
|
||||
$bytes *= 1024;
|
||||
}
|
||||
|
||||
// Deal with large (float) values which run into the maximum integer size.
|
||||
return min( $bytes, PHP_INT_MAX );
|
||||
}
|
||||
|
||||
/**
|
||||
* Time exceeded.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* Ensures the batch never exceeds a sensible time limit.
|
||||
* A timeout limit of 30s is common on shared hosting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function time_exceeded() {
|
||||
$finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds
|
||||
$return = false;
|
||||
|
||||
if ( time() >= $finish ) {
|
||||
$return = true;
|
||||
}
|
||||
|
||||
return apply_filters( $this->identifier . '_time_exceeded', $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* Override if applicable, but ensure that the below actions are
|
||||
* performed, or, call parent::complete().
|
||||
*/
|
||||
protected function complete() {
|
||||
// Unschedule the cron healthcheck.
|
||||
$this->clear_scheduled_event();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule cron healthcheck
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param mixed $schedules Schedules.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function schedule_cron_healthcheck( $schedules ) {
|
||||
$interval = apply_filters( $this->identifier . '_cron_interval', 5 );
|
||||
|
||||
if ( property_exists( $this, 'cron_interval' ) ) {
|
||||
$interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval_identifier );
|
||||
}
|
||||
|
||||
// Adds every 5 minutes to the existing schedules.
|
||||
$schedules[ $this->identifier . '_cron_interval' ] = array(
|
||||
'interval' => MINUTE_IN_SECONDS * $interval,
|
||||
'display' => sprintf( __( 'Every %d Minutes', 'gravityforms' ), $interval ),
|
||||
);
|
||||
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cron healthcheck
|
||||
*
|
||||
* Restart the background process if not already running
|
||||
* and data exists in the queue.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function handle_cron_healthcheck() {
|
||||
$this->logger->log_debug( sprintf( '%s(): Running for %s.', __METHOD__, $this->action ) );
|
||||
$this->record_cron_event( $this->cron_hook_identifier );
|
||||
|
||||
if ( $this->is_process_running() ) {
|
||||
// Background process already running.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( $this->is_queue_empty() ) {
|
||||
// No data to process.
|
||||
$this->clear_scheduled_event();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maintains a semipersistent record of the 3 most recent events for the specified hook.
|
||||
*
|
||||
* @since 2.7.1
|
||||
*
|
||||
* @param string $hook The cron hook name.
|
||||
*/
|
||||
public function record_cron_event( $hook ) {
|
||||
if ( ! defined( 'DOING_CRON' ) || ! DOING_CRON ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$events = $this->cache->get( Cache::KEY_CRON_EVENTS );
|
||||
if ( ! is_array( $events ) ) {
|
||||
$events = array();
|
||||
}
|
||||
|
||||
if ( empty( $events[ $hook ] ) || ! is_array( $events[ $hook ] ) ) {
|
||||
$events[ $hook ] = array( time() );
|
||||
} else {
|
||||
array_unshift( $events[ $hook ], time() );
|
||||
array_splice( $events[ $hook ], 3 );
|
||||
}
|
||||
|
||||
$this->cache->set( Cache::KEY_CRON_EVENTS, $events, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule event
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
protected function schedule_event() {
|
||||
if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
|
||||
$this->logger->log_debug( sprintf( '%s(): Scheduling cron event for %s.', __METHOD__, $this->action ) );
|
||||
wp_schedule_event( time() + 10, $this->cron_interval_identifier, $this->cron_hook_identifier );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear scheduled event
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
protected function clear_scheduled_event() {
|
||||
$timestamp = wp_next_scheduled( $this->cron_hook_identifier );
|
||||
|
||||
if ( $timestamp ) {
|
||||
$this->logger->log_debug( sprintf( '%s(): Clearing cron event for %s.', __METHOD__, $this->action ) );
|
||||
wp_unschedule_event( $timestamp, $this->cron_hook_identifier );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all scheduled events.
|
||||
*
|
||||
* @since 2.3.1.x
|
||||
*/
|
||||
public function clear_scheduled_events() {
|
||||
wp_clear_scheduled_hook( $this->cron_hook_identifier );
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel Process
|
||||
*
|
||||
* Stop processing queue items, clear cronjob and delete batch.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function cancel_process() {
|
||||
if ( ! $this->is_queue_empty() ) {
|
||||
$batch = $this->get_batch();
|
||||
|
||||
$this->delete( $batch->key );
|
||||
$this->clear_scheduled_events();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all batches from the queue.
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @param bool $all_blogs_in_network
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
public function clear_queue( $all_blogs_in_network = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->options;
|
||||
$column = 'option_name';
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$table = $wpdb->sitemeta;
|
||||
$column = 'meta_key';
|
||||
}
|
||||
|
||||
$key = $this->identifier . '_batch_';
|
||||
|
||||
if ( ! $all_blogs_in_network ) {
|
||||
$key .= 'blog_id_' . get_current_blog_id() . '_';
|
||||
}
|
||||
|
||||
$key = $wpdb->esc_like( $key ) . '%';
|
||||
|
||||
$result = $wpdb->query( $wpdb->prepare( "
|
||||
DELETE FROM {$table}
|
||||
WHERE {$column} LIKE %s
|
||||
", $key ) );
|
||||
|
||||
$this->data = array();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* Override this method to perform any actions required on each
|
||||
* queue item. Return the modified item for further processing
|
||||
* in the next pass through. Or, return false to remove the
|
||||
* item from the queue.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $item Queue item to iterate over.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function task( $item );
|
||||
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Background_Processing;
|
||||
|
||||
/**
|
||||
* Abstract WP_Async_Request class.
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
abstract class WP_Async_Request {
|
||||
|
||||
/**
|
||||
* Prefix
|
||||
*
|
||||
* (default value: 'wp')
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $prefix = 'wp';
|
||||
|
||||
/**
|
||||
* Action
|
||||
*
|
||||
* (default value: 'async_request')
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $action = 'async_request';
|
||||
|
||||
/**
|
||||
* Identifier
|
||||
*
|
||||
* @var mixed
|
||||
* @access protected
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* Data
|
||||
*
|
||||
* (default value: array())
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* Initiate new async request
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->identifier = $this->prefix . '_' . $this->action;
|
||||
|
||||
add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
|
||||
add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set data used during the request
|
||||
*
|
||||
* @param array $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function data( $data ) {
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the async request
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function dispatch() {
|
||||
$url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
|
||||
$args = $this->get_post_args();
|
||||
|
||||
return wp_remote_post( esc_url_raw( $url ), $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_query_args() {
|
||||
if ( property_exists( $this, 'query_args' ) ) {
|
||||
return $this->query_args;
|
||||
}
|
||||
|
||||
return array(
|
||||
'action' => $this->identifier,
|
||||
'nonce' => wp_create_nonce( $this->identifier ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query URL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_query_url() {
|
||||
if ( property_exists( $this, 'query_url' ) ) {
|
||||
return $this->query_url;
|
||||
}
|
||||
|
||||
return admin_url( 'admin-ajax.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_post_args() {
|
||||
if ( property_exists( $this, 'post_args' ) ) {
|
||||
return $this->post_args;
|
||||
}
|
||||
|
||||
return array(
|
||||
'timeout' => 0.01,
|
||||
'blocking' => false,
|
||||
'body' => $this->data,
|
||||
'cookies' => $_COOKIE,
|
||||
'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe handle
|
||||
*
|
||||
* Check for correct nonce and pass to handler.
|
||||
*/
|
||||
public function maybe_handle() {
|
||||
// Don't lock up other requests while processing
|
||||
session_write_close();
|
||||
|
||||
check_ajax_referer( $this->identifier, 'nonce' );
|
||||
|
||||
$this->handle();
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle
|
||||
*
|
||||
* Override this method to perform any actions required
|
||||
* during the async request.
|
||||
*/
|
||||
abstract protected function handle();
|
||||
|
||||
}
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Cache;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
|
||||
/**
|
||||
*
|
||||
* Notes:
|
||||
* 1. The WordPress Transients API does not support boolean
|
||||
* values so boolean values should be converted to integers
|
||||
* or arrays before setting the values as persistent.
|
||||
*
|
||||
* 2. The transients API only deletes the transient from the database
|
||||
* when the transient is accessed after it has expired. WordPress doesn't
|
||||
* do any garbage collection of transients.
|
||||
*
|
||||
*/
|
||||
class Cache {
|
||||
|
||||
/**
|
||||
* @var Common
|
||||
*/
|
||||
protected $common;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Common $common
|
||||
*/
|
||||
public function __construct( $common ) {
|
||||
$this->common = $common;
|
||||
}
|
||||
|
||||
const KEY_CRON_EVENTS = 'cron_events_log';
|
||||
|
||||
private static $_transient_prefix = 'GFCache_';
|
||||
private static $_cache = array();
|
||||
|
||||
/**
|
||||
* Get a value from cache.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
* @param $found
|
||||
* @param $is_persistent
|
||||
*
|
||||
* @return false|mixed|string|null
|
||||
*/
|
||||
public function get( $key, &$found = null, $is_persistent = true ) {
|
||||
global $blog_id;
|
||||
if ( is_multisite() ) {
|
||||
$key = $blog_id . ':' . $key;
|
||||
}
|
||||
|
||||
if ( isset( self::$_cache[ $key ] ) ) {
|
||||
$found = true;
|
||||
$data = $this->common->rgar( self::$_cache[ $key ], 'data' );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//If set to not persistent, do not check transient for performance reasons
|
||||
if ( ! $is_persistent ) {
|
||||
$found = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = self::get_transient( $key );
|
||||
|
||||
if ( false === ( $data ) ) {
|
||||
$found = false;
|
||||
|
||||
return false;
|
||||
} else {
|
||||
self::$_cache[ $key ] = array( 'data' => $data, 'is_persistent' => true );
|
||||
$found = true;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value in the cache.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
* @param $data
|
||||
* @param $is_persistent
|
||||
* @param $expiration_seconds
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set( $key, $data, $is_persistent = false, $expiration_seconds = 0 ) {
|
||||
global $blog_id;
|
||||
$success = true;
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$key = $blog_id . ':' . $key;
|
||||
}
|
||||
|
||||
if ( $is_persistent ) {
|
||||
$success = self::set_transient( $key, $data, $expiration_seconds );
|
||||
}
|
||||
|
||||
self::$_cache[ $key ] = array( 'data' => $data, 'is_persistent' => $is_persistent );
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a value from cache.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete( $key ) {
|
||||
global $blog_id;
|
||||
$success = true;
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$key = $blog_id . ':' . $key;
|
||||
}
|
||||
|
||||
if ( isset( self::$_cache[ $key ] ) ) {
|
||||
if ( self::$_cache[ $key ]['is_persistent'] ) {
|
||||
$success = self::delete_transient( $key );
|
||||
}
|
||||
|
||||
unset( self::$_cache[ $key ] );
|
||||
} else {
|
||||
$success = self::delete_transient( $key );
|
||||
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* FLush the cache.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $flush_persistent
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function flush( $flush_persistent = false ) {
|
||||
global $wpdb;
|
||||
|
||||
self::$_cache = array();
|
||||
|
||||
if ( false === $flush_persistent ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$sql = $wpdb->prepare( "
|
||||
DELETE FROM $wpdb->sitemeta
|
||||
WHERE meta_key LIKE %s OR
|
||||
meta_key LIKE %s
|
||||
",
|
||||
'\_site\_transient\_timeout\_GFCache\_%',
|
||||
'_site_transient_GFCache_%'
|
||||
);
|
||||
} else {
|
||||
$sql = $wpdb->prepare( "
|
||||
DELETE FROM $wpdb->options
|
||||
WHERE option_name LIKE %s OR
|
||||
option_name LIKE %s
|
||||
",
|
||||
'\_transient\_timeout\_GFCache\_%',
|
||||
'_transient_GFCache_%'
|
||||
);
|
||||
}
|
||||
|
||||
$rows_deleted = $wpdb->query( $sql );
|
||||
|
||||
$success = $rows_deleted !== false ? true : false;
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a transient by its key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
private function delete_transient( $key ) {
|
||||
if ( ! function_exists( 'wp_hash' ) ) {
|
||||
return false;
|
||||
}
|
||||
$key = self::$_transient_prefix . wp_hash( $key );
|
||||
if ( is_multisite() ) {
|
||||
$success = delete_site_transient( $key );
|
||||
} else {
|
||||
$success = delete_transient( $key );
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a transient by its key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
* @param $data
|
||||
* @param $expiration
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
private function set_transient( $key, $data, $expiration ) {
|
||||
if ( ! function_exists( 'wp_hash' ) ) {
|
||||
return false;
|
||||
}
|
||||
$key = self::$_transient_prefix . wp_hash( $key );
|
||||
if ( is_multisite() ) {
|
||||
$success = set_site_transient( $key, $data, $expiration );
|
||||
} else {
|
||||
$success = set_transient( $key, $data, $expiration );
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a transient by its key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
private function get_transient( $key ) {
|
||||
if ( ! function_exists( 'wp_hash' ) ) {
|
||||
return false;
|
||||
}
|
||||
$key = self::$_transient_prefix . wp_hash( $key );
|
||||
if ( is_multisite() ) {
|
||||
$data = get_site_transient( $key );
|
||||
} else {
|
||||
$data = get_transient( $key );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+94
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Config;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Config_Collection;
|
||||
use Gravity_Forms\Gravity_Tools\Config;
|
||||
|
||||
/**
|
||||
* Config items for app registration, including helper methods.
|
||||
*/
|
||||
class App_Config extends Config {
|
||||
|
||||
/**
|
||||
* The name of the app, in slug form.
|
||||
*
|
||||
* @var string $app_name
|
||||
*/
|
||||
private $app_name;
|
||||
|
||||
/**
|
||||
* The condition for enqueuing the app data.
|
||||
*
|
||||
* @var bool|callable $display_condition
|
||||
*/
|
||||
private $display_condition;
|
||||
|
||||
/**
|
||||
* The CSS assets to enqueue.
|
||||
*
|
||||
* @var array $css_asset
|
||||
*/
|
||||
private $css_asset;
|
||||
|
||||
/**
|
||||
* The relative path to the chunk in JS.
|
||||
*
|
||||
* @var string $chunk
|
||||
*/
|
||||
private $chunk;
|
||||
|
||||
/**
|
||||
* The root element to use to load the app.
|
||||
*
|
||||
* @var string $root_element
|
||||
*/
|
||||
private $root_element;
|
||||
|
||||
/**
|
||||
* Set the data for this app config.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $data
|
||||
*/
|
||||
public function set_data( $data ) {
|
||||
$this->name = $data['object_name'];
|
||||
$this->script_to_localize = $data['script_name'];
|
||||
$this->app_name = $data['app_name'];
|
||||
|
||||
$this->display_condition = $data['enqueue'];
|
||||
$this->chunk = $data['chunk'];
|
||||
$this->root_element = $data['root_element'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we should enqueue this data.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function should_enqueue() {
|
||||
return is_admin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Config data.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function data() {
|
||||
return array(
|
||||
'apps' => array(
|
||||
$this->app_name => array(
|
||||
'should_display' => is_callable( $this->display_condition ) ? call_user_func( $this->display_condition ) : $this->display_condition,
|
||||
'chunk_path' => $this->chunk,
|
||||
'root_element' => $this->root_element,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Data;
|
||||
|
||||
class Transient_Strategy {
|
||||
|
||||
/**
|
||||
* Get transient value.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get( $key ) {
|
||||
return get_transient( $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set transient value.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @param $timeout
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set( $key, $value, $timeout ) {
|
||||
return set_transient( $key, $value, $timeout );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete transient value.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete( $key ) {
|
||||
return delete_transient( $key );
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Data;
|
||||
|
||||
interface Oauth_Data_Handler {
|
||||
|
||||
public function get( $key, $namespace = 'config' );
|
||||
|
||||
public function save( $key, $value, $namespace = 'config' );
|
||||
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Data_Import\Sources;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Data_Import\Record;
|
||||
use Gravity_Forms\Gravity_Tools\Data_Import\Source;
|
||||
|
||||
class CSV_Source implements Source {
|
||||
|
||||
private $raw_data;
|
||||
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Parse and store the passed CSV data.
|
||||
*
|
||||
* @param string $data - The raw CSV string data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_data( $data ) {
|
||||
$this->raw_data = $data;
|
||||
$rows = array_map( 'str_getcsv', $data );
|
||||
$header = array_shift( $rows );
|
||||
$csv = array();
|
||||
|
||||
foreach ( $rows as $row ) {
|
||||
$csv[] = array_combine( $header, $row );
|
||||
}
|
||||
|
||||
$this->data = $csv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the available keys from the CSV headers.
|
||||
*
|
||||
* @param array $args - An array of additional args, info, or data needed
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function keys( $args = array() ) {
|
||||
$data = $this->data;
|
||||
|
||||
if ( empty( $data ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$entry = array_shift( $data );
|
||||
|
||||
return array_keys( $entry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this CSV has a given key.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_key( $key ) {
|
||||
return in_array( $key, $this->keys() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rows for this CSV.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return Record[]
|
||||
*/
|
||||
public function records( $args = array() ) {
|
||||
$records = array();
|
||||
|
||||
foreach ( $this->data as $row ) {
|
||||
$records[] = new Record( $row );
|
||||
}
|
||||
|
||||
return $records;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the row count for this CSV.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count( $args = array() ) {
|
||||
return count( $this->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific slice of rows from this CSV.
|
||||
*
|
||||
* @param int $count
|
||||
* @param int $offset
|
||||
* @param array $additional_args
|
||||
*
|
||||
* @return Record[]
|
||||
*/
|
||||
public function slice( $count, $offset, $additional_args = array() ) {
|
||||
return array_slice( $this->data, $offset, $count, true );
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Data_Import;
|
||||
|
||||
class Import_Handler {
|
||||
|
||||
/**
|
||||
* @var Source
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* @var Destination
|
||||
*/
|
||||
protected $destination;
|
||||
|
||||
public function __construct( Source $source, Destination $destination ) {
|
||||
$this->source = $source;
|
||||
$this->destination = $destination;
|
||||
}
|
||||
|
||||
public function handle( $data, $map, $additional_args = array(), $count = -1, $offset = -1 ) {
|
||||
$this->source->set_data( $data );
|
||||
|
||||
$records = $count === -1 ? $this->source->records( $additional_args ) : $this->source->slice( $count, $offset, $additional_args );
|
||||
$to_be_inserted = array();
|
||||
|
||||
foreach ( $records as $record ) {
|
||||
$to_be_inserted[] = $this->map_single_record( $record, $map );
|
||||
}
|
||||
|
||||
$this->destination->store( $to_be_inserted );
|
||||
}
|
||||
|
||||
protected function map_single_record( Record $record, $map ) {
|
||||
$insertion_data = array();
|
||||
|
||||
foreach ( $map as $source_key => $destination_key ) {
|
||||
if ( ! $this->destination->has_key( $destination_key ) ) {
|
||||
throw new \InvalidArgumentException( sprintf( 'Attempting to map key %s to invalid destination field %s.', $source_key, $destination_key ) );
|
||||
}
|
||||
|
||||
if ( ! $this->source->has_key( $source_key ) ) {
|
||||
throw new \InvalidArgumentException( sprintf( 'Attempting to map invalid source key %s.', $source_key ) );
|
||||
}
|
||||
|
||||
$insertion_data[ $destination_key ] = $record->value_for_key( $source_key );
|
||||
}
|
||||
|
||||
return $insertion_data;
|
||||
}
|
||||
}
|
||||
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Data_Import;
|
||||
|
||||
/**
|
||||
* Record
|
||||
*
|
||||
* A Record represents a single piece of information from a Source. In a CSV import
|
||||
* it would represent a row, in a WP Post import it would represent a single Post object,
|
||||
* and so on.
|
||||
*/
|
||||
class Record {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Record constructor
|
||||
*
|
||||
* @param array $data - The data for this record.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $data ) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the $data property.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from this record for the given key.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function value_for_key( $key ) {
|
||||
if ( ! $this->has_key( $key ) ) {
|
||||
throw new \InvalidArgumentException( sprintf( 'Key %s does not exist on current record.', $key ) );
|
||||
}
|
||||
|
||||
return $this->data[ $key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the keys for this record.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function keys() {
|
||||
return array_keys( $this->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this record has the given key.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_key( $key ) {
|
||||
return array_key_exists( $key, $this->data );
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Data_Import;
|
||||
|
||||
/**
|
||||
* Destination Interface
|
||||
*
|
||||
* A Destination is any system/context to which the imported data can be sent.
|
||||
*/
|
||||
interface Destination {
|
||||
|
||||
/**
|
||||
* Get the valid keys for this Destination.
|
||||
*
|
||||
* @param array @args
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function keys( $args = array() );
|
||||
|
||||
/**
|
||||
* Determine if this Destination has the given key.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_key( $key );
|
||||
|
||||
/**
|
||||
* Store the given array of records into this Destination.
|
||||
*
|
||||
* @param Record[] $records
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function store( $records );
|
||||
|
||||
/**
|
||||
* Check for duplicate records already existing within this Destination.
|
||||
*
|
||||
* @param Record $record
|
||||
* @param string $check_key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check_for_duplicates( $record, $check_key );
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Data_Import;
|
||||
|
||||
/**
|
||||
* Source Interface
|
||||
*
|
||||
* A Source is any collection of data from which values can be mapped. In the case of a CSV import,
|
||||
* this would represent the CSV, for instance. This interface provides the contract for all of the functionality
|
||||
* required of a valid Source.
|
||||
*/
|
||||
interface Source {
|
||||
|
||||
/**
|
||||
* Set the internal $data property to whatever is passed.
|
||||
*
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_data( $data );
|
||||
|
||||
/**
|
||||
* Get all of the valid/available keys for this source.
|
||||
*
|
||||
* In something like a CSV, this would be the column headers. For a WP Post,
|
||||
* it would be the various field key names, etc.
|
||||
*
|
||||
* @param array $args - An array of additional args, info, or data needed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function keys( $args = array() );
|
||||
|
||||
/**
|
||||
* Determine if this source has a given key.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_key( $key );
|
||||
|
||||
/**
|
||||
* Get the records for this source.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return Record[]
|
||||
*/
|
||||
public function records( $args = array() );
|
||||
|
||||
/**
|
||||
* Get the record count for this source.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count( $args = array() );
|
||||
|
||||
/**
|
||||
* Get a specific slice of records from this source.
|
||||
*
|
||||
* @param int $count
|
||||
* @param int $offset
|
||||
* @param array $additional_args
|
||||
*
|
||||
* @return Record[]
|
||||
*/
|
||||
public function slice( $count, $offset, $additional_args = array() );
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Emails;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Bettarray;
|
||||
|
||||
/**
|
||||
* Email_Templatizer
|
||||
*
|
||||
* For the given email markup, take find any placeholder tokens and replace them with values from
|
||||
* the provided $data. Can be used for any markup.
|
||||
*/
|
||||
class Email_Templatizer {
|
||||
|
||||
protected $email_template = '';
|
||||
protected $open_delin;
|
||||
protected $close_delin;
|
||||
|
||||
/**
|
||||
* @param string $email_template The markup to parse
|
||||
* @param string $open_delin The string to use for the opening delimiter for tokens. Defaults to '{{'.
|
||||
* @param string $close_delin The string to use for the closing delimiter for tokens. Defaults to '}}'.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $email_template, $open_delin = '{{', $close_delin = '}}' ) {
|
||||
$this->email_template = $email_template;
|
||||
$this->open_delin = $open_delin;
|
||||
$this->close_delin = $close_delin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the stored markup and render it with the given placeholder values.
|
||||
*
|
||||
* @param array|Bettarray $data the data to use with the placeholders
|
||||
* @param int $max_length the maximum length, in characters, for the markup
|
||||
* @param bool $echo whether to echo the markup (if false, markup will be returned)
|
||||
*
|
||||
* @return string|void
|
||||
*/
|
||||
public function render( $data, $max_length = false, $echo = false ) {
|
||||
// Cast to Bettarray to allow dot navigation.
|
||||
if ( ! is_a( $data, Bettarray::class ) ) {
|
||||
$data = new Bettarray( $data );
|
||||
}
|
||||
|
||||
$rendered = $this->handle_loops( $data );
|
||||
$rendered = $this->handle_conditionals( $data, $rendered );
|
||||
$rendered = $this->handle_placeholders( $data, $rendered );
|
||||
|
||||
if ( $max_length ) {
|
||||
$rendered = $this->truncate_markup( $rendered, $max_length );
|
||||
}
|
||||
|
||||
if ( $echo ) {
|
||||
echo $rendered;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return $rendered;
|
||||
}
|
||||
|
||||
private function handle_loops( $data, $markup = false ) {
|
||||
if ( ! $markup ) {
|
||||
$markup = $this->email_template;
|
||||
}
|
||||
|
||||
$pattern = sprintf( '/(%s\|for[^\|]+\|%s)([^\|]+)(%s\|endfor\|%s)/', preg_quote( $this->open_delin ), preg_quote( $this->close_delin ), preg_quote( $this->open_delin ), preg_quote( $this->close_delin ) );
|
||||
|
||||
return preg_replace_callback( $pattern, function ( $matches ) use ( $data ) {
|
||||
// Something has gone terribly awry, just return the original text.
|
||||
if ( count( $matches ) !== 4 ) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$opening = $matches[1];
|
||||
$contents = $matches[2];
|
||||
|
||||
$loop = str_replace( $this->open_delin . '|for', '', $opening );
|
||||
$loop = str_replace( '|' . $this->close_delin, '', $loop );
|
||||
$loop = trim( $loop );
|
||||
$loop_parts = explode( ' ', $loop );
|
||||
|
||||
// Loop has invalid syntax. Bail.
|
||||
if ( count( $loop_parts ) !== 3 ) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$item_name = $loop_parts[0];
|
||||
$item_value_string = $loop_parts[2];
|
||||
|
||||
$item_values = $data->get_raw( $item_value_string );
|
||||
|
||||
if ( ! is_array( $item_values ) ) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$loop_data = new Bettarray( $data->all() );
|
||||
$loop_data->delete( $item_value_string );
|
||||
|
||||
$return = '';
|
||||
|
||||
foreach( $item_values as $item_value ) {
|
||||
$loop_data->set( $item_name, $item_value );;
|
||||
$template = new Email_Templatizer( $contents );
|
||||
$return .= $template->render( $loop_data );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}, $markup );
|
||||
|
||||
}
|
||||
/**
|
||||
* Process the markup to replace placeholders with data.
|
||||
*
|
||||
* @param Bettarray $data the data containing the placeholder values
|
||||
* @param string $markup if passed, the markup to act upon
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function handle_placeholders( $data, $markup = false ) {
|
||||
if ( ! $markup ) {
|
||||
$markup = $this->email_template;
|
||||
}
|
||||
|
||||
$pattern = sprintf( '/%s[^%s]*%s/', preg_quote( $this->open_delin ), preg_quote( $this->close_delin ), preg_quote( $this->close_delin ) );
|
||||
|
||||
return preg_replace_callback( $pattern, function ( $matches ) use ( $data ) {
|
||||
$cleaned = str_replace( $this->open_delin, '', $matches[0] );
|
||||
$cleaned = str_replace( $this->close_delin, '', $cleaned );
|
||||
$search = trim( $cleaned );
|
||||
|
||||
$replacement = $data->get_raw( $search );
|
||||
|
||||
if ( ! is_string( $replacement ) && ! is_numeric( $replacement ) ) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$sanitized = wp_kses_post( $replacement );
|
||||
|
||||
return $sanitized;
|
||||
}, $markup );
|
||||
}
|
||||
|
||||
private function handle_conditionals( $data, $markup = false ) {
|
||||
if ( ! $markup ) {
|
||||
$markup = $this->email_template;
|
||||
}
|
||||
|
||||
$pattern = sprintf( '/(%s\|if[^\|]+\|%s)([^\|]+)(%s\|endif\|%s)/', preg_quote( $this->open_delin ), preg_quote( $this->close_delin ), preg_quote( $this->open_delin ), preg_quote( $this->close_delin ) );
|
||||
|
||||
return preg_replace_callback( $pattern, function ( $matches ) use ( $data ) {
|
||||
// Something has gone terribly awry, just return the original text.
|
||||
if ( count( $matches ) !== 4 ) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$opening = $matches[1];
|
||||
$contents = $matches[2];
|
||||
|
||||
$condition = str_replace( $this->open_delin . '|if', '', $opening );
|
||||
$condition = str_replace( '|' . $this->close_delin, '', $condition );
|
||||
$condition = trim( $condition );
|
||||
|
||||
$check_val = $data->get_raw( $condition );
|
||||
|
||||
if ( empty( $check_val ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}, $markup );
|
||||
}
|
||||
|
||||
/**
|
||||
* A basic method to truncate the markup to $max_length characters.
|
||||
*
|
||||
* @todo Update to handle tags more gracefully to ensure none get truncated.
|
||||
*
|
||||
* @param string $markup the markup to modify
|
||||
* @param int $max_length the number of characters to which the markup should be limited
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function truncate_markup( $markup, $max_length ) {
|
||||
return substr( $markup, 0, $max_length );
|
||||
}
|
||||
}
|
||||
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Endpoints;
|
||||
|
||||
abstract class Endpoint {
|
||||
|
||||
protected $required_params = array();
|
||||
|
||||
protected $minimum_cap = 'manage_options';
|
||||
|
||||
abstract public function handle();
|
||||
|
||||
/**
|
||||
* Default nonce.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_nonce_name() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default validation, checks ajax referer and verifies required params.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function validate() {
|
||||
check_ajax_referer( $this->get_nonce_name(), 'security' );
|
||||
|
||||
if ( ! current_user_can( $this->minimum_cap ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach( $this->required_params as $param ) {
|
||||
if ( ! isset( $_REQUEST[ $param ] ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Enum;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Booliesh;
|
||||
|
||||
/**
|
||||
* Field Type Validation Enum
|
||||
*
|
||||
* This class provides defined, explicit methods for validating and sanitizing values
|
||||
* before storing them in the database.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* $validated_value = Field_Type_Validation_Enum::validate( Field_Type_Validation_Enum::STRING, 'foobar' );
|
||||
*
|
||||
* Actual validation methods can be called directly as well:
|
||||
*
|
||||
* $validated_string = Field_Type_Validation_Enum::validate_string( 'foobar' );
|
||||
*/
|
||||
class Field_Type_Validation_Enum {
|
||||
|
||||
const STRING = 'string';
|
||||
const INT = 'int';
|
||||
const FLOAT = 'float';
|
||||
const BOOLEAN = 'boolean';
|
||||
const DATE = 'date';
|
||||
const OBJECT = 'object';
|
||||
const ARR = 'array';
|
||||
const EMAIL = 'email';
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array mapping field types to their validation callbacks;
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
private static function validation_map() {
|
||||
return array(
|
||||
self::STRING => array( self::class, 'validate_string' ),
|
||||
self::INT => array( self::class, 'validate_int' ),
|
||||
self::FLOAT => array( self::class, 'validate_float' ),
|
||||
self::BOOLEAN => array( self::class, 'validate_bool' ),
|
||||
self::DATE => array( self::class, 'validate_date' ),
|
||||
self::OBJECT => array( self::class, 'validate_object' ),
|
||||
self::ARR => array( self::class, 'validate_array' ),
|
||||
self::EMAIL => array( self::class, 'validate_email' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a given value based on the field type.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $type The field type to be used for validation.
|
||||
* @param mixed $value The actual value to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function validate( $type, $value ) {
|
||||
if ( ! is_string( $type ) && is_callable( $type ) ) {
|
||||
return call_user_func( $type, $value );
|
||||
}
|
||||
|
||||
if ( ! array_key_exists( $type, self::validation_map() ) ) {
|
||||
$error_string = sprintf( 'Field type %s is not valid.', $type );
|
||||
throw new \InvalidArgumentException( $error_string, 480 );
|
||||
}
|
||||
|
||||
$validated_value = call_user_func( self::validation_map()[ $type ], $value );
|
||||
|
||||
return $validated_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a string and adds slashes for DB storage.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function validate_string( $value ) {
|
||||
if ( ! is_string( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return addslashes( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an integer.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public static function validate_int( $value ) {
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (integer) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a float.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return float|null
|
||||
*/
|
||||
public static function validate_float( $value ) {
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (float) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a boolean.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
public static function validate_bool( $value ) {
|
||||
return Booliesh::get( $value, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a date string.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function validate_date( $value ) {
|
||||
if ( ! is_string( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$check = strtotime( $value );
|
||||
|
||||
if ( ! $check ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an object.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
public static function validate_object( $value ) {
|
||||
if ( ! is_object( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public static function validate_array( $value ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an email.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function validate_email( $value ) {
|
||||
return filter_var( $value, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE );
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+213
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Models;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship_Collection;
|
||||
|
||||
/**
|
||||
* Model
|
||||
*
|
||||
* This provides the base abstract contract for Models in Hermes. A Model is responsible
|
||||
* for defining all of the fields, relationships, and permissions surrounding a given
|
||||
* object/data type.
|
||||
*/
|
||||
abstract class Model {
|
||||
|
||||
/**
|
||||
* The type of object this model represents.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = '';
|
||||
|
||||
/**
|
||||
* The minimum capability required for a given user to be able to access
|
||||
* this object's data. If defined, will override individual permissions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $access_cap = '';
|
||||
|
||||
/**
|
||||
* The minimum capability required for a given user to perform specific CRUD
|
||||
* tasks against this model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $access_cap_view = '';
|
||||
protected $access_cap_edit = '';
|
||||
protected $access_cap_create = '';
|
||||
protected $access_cap_delete = '';
|
||||
|
||||
/**
|
||||
* If a model needs to support ad-hoc defined meta fields (i.e., fields that
|
||||
* are defined by the user and are not defined explicitly in the model), set
|
||||
* this to true.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $supports_ad_hoc_fields = false;
|
||||
|
||||
/**
|
||||
* If your model needs to use an explicit/non-standard table, set it here.
|
||||
* Do not include the DB prefix in the table name.
|
||||
*
|
||||
* @var bool|string
|
||||
*/
|
||||
protected $forced_table_name = false;
|
||||
|
||||
|
||||
/**
|
||||
* If your model supports Full Text search fields, list them here.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchable_fields = array();
|
||||
|
||||
/**
|
||||
* Concrete Models must implement the public ::relationships() method
|
||||
* in order to define any relationships this object type may have.
|
||||
*
|
||||
* @return Relationship_Collection
|
||||
*/
|
||||
abstract public function relationships();
|
||||
|
||||
/**
|
||||
* Determine if this model supports ad hoc field
|
||||
* definitions.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function supports_ad_hoc_fields() {
|
||||
return $this->supports_ad_hoc_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for forced_table_name.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function forced_table_name() {
|
||||
return $this->forced_table_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the type property
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function type() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for $searchable_fields
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function searchable_fields() {
|
||||
return $this->searchable_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete Models must define the specific Fields and Field Types this
|
||||
* object type has. Any request regarding this object type will use this
|
||||
* array to determine if a given field should be evaluated, and how to
|
||||
* validate it.
|
||||
*
|
||||
* In the Database design, tables for this object type should have columns
|
||||
* that strictly match the field names outlined here. For instance, if a field
|
||||
* called "first_name" is defined here, a column of "first_name" must exist in
|
||||
* the DB table for this object.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete Models must define the specific Fields and Field Types this object
|
||||
* type supports for *meta* fields. Meta fields differ from typical fields in that
|
||||
* they do not require specific columns in the base Database table but are rather stored
|
||||
* in a meta table. This allows for flexibility in adding new fields to a given object type
|
||||
* after code has been deployed to production while avoiding having to modify DB tables.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function meta_fields() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current user's access for this object type.Typically this should
|
||||
* not be overwritten in the concrete Model, except for cases in which custom
|
||||
* access functionality is required.
|
||||
*
|
||||
* @param string $action - The specific CRUD action being checked.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_access( $action = 'view' ) {
|
||||
if ( ! empty( $this->access_cap ) ) {
|
||||
return current_user_can( $this->access_cap );
|
||||
}
|
||||
|
||||
switch ( $action ) {
|
||||
case 'view':
|
||||
return current_user_can( $this->access_cap_view );
|
||||
|
||||
case 'edit':
|
||||
return current_user_can( $this->access_cap_edit );
|
||||
|
||||
case 'create':
|
||||
return current_user_can( $this->access_cap_create );
|
||||
|
||||
case 'delete':
|
||||
return current_user_can( $this->access_cap_delete );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete Models may define various transformations that can be applied to queried data. This
|
||||
* is useful in situations where the data being stored for a given model's field needs to be returned
|
||||
* in various formats. For instance, the data stored could be a post ID, and the transformation could return
|
||||
* various aspects of that post, such as the Post Title, Description, etc. Other use-cases are things such as
|
||||
* converting to all-caps, translating strings to other languages, or converting currencies.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function transformations() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the given transformation type, pass a value through a transformation and return the result. The
|
||||
* given transformation must be present in the transformations() array of this model.
|
||||
*
|
||||
* @param string $transformation_name
|
||||
* @param mixed $transformation_arg
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle_transformation( $transformation_name, $transformation_arg, $value ) {
|
||||
if ( ! isset( $this->transformations()[ $transformation_name ] ) ) {
|
||||
throw new \InvalidArgumentException( 'Attempting to call invalid transformation type ' . $transformation_name . ' on object type ' . $this->type );
|
||||
}
|
||||
|
||||
$transformation = $this->transformations()[ $transformation_name ];
|
||||
|
||||
if ( empty( $transformation_arg ) ) {
|
||||
return call_user_func( $transformation, $value );
|
||||
}
|
||||
|
||||
if ( is_array( $transformation_arg ) ) {
|
||||
return call_user_func( $transformation, $value, ...$transformation_arg );
|
||||
}
|
||||
|
||||
return call_user_func( $transformation, $value, $transformation_arg );
|
||||
}
|
||||
}
|
||||
+554
@@ -0,0 +1,554 @@
|
||||
# Project Hermes
|
||||
|
||||
__A Query Architecture for dynamic, performant, client-controlled data handling and processing.__
|
||||
|
||||
## AJAX, GraphQL, and The Problem of Query Structures
|
||||
|
||||
In our typical product configuration, bespoke endpoints are setup and maintained for each unique type
|
||||
of query that might come from the Client. Need to get a list of users? That's an endpoint. Get the companies users
|
||||
belong to? Another endpoint.
|
||||
Save a setting, get a setting, update a field, get a field - all individual endpoints.
|
||||
|
||||
Oftentimes, this paradigm is more than acceptable. The total number of query types being handled is typically low, and
|
||||
the
|
||||
need for net-new endpoints rarely occurs.
|
||||
|
||||
But what about situations in which there are many, many types of data to query, in all sorts of various configurations?
|
||||
What if the
|
||||
application is a single-page React app, where all the data comes view queries and nothing exists on page load? What if a
|
||||
given data type
|
||||
or object model requires a new piece of data? Suddenly we're not just spinning up unique endpoints for each situation,
|
||||
but also having to
|
||||
update/modify/drop database tables as well (something that has caused countless headaches for Plugin products like
|
||||
ours).
|
||||
|
||||
Enter GraphQL, an alternative Query standard to REST/AJAX. GraphQL differs from traditional REST architecture primarily
|
||||
in how
|
||||
query structures and data shapes are controlled. In REST, you retrieve a specific object from a specific endpoint. "
|
||||
Users" are queried via "/json/users".
|
||||
"Companies" are queried via "json/companies". If you need both, or need to get Users categorized by a given Company,
|
||||
it's two separate queries,
|
||||
while necessitating that values from the first are saved and passed to the second. In simple contexts, this is fine, but
|
||||
as complexity grows,
|
||||
so do the headaches around this.
|
||||
|
||||
GraphQL tackles this by having the Server simply establish a structured schema of Object Types, along with their
|
||||
relationships, fields, and other criteria. The Client can then use this schema to query *anything it needs*, all at a
|
||||
single endpoint.
|
||||
|
||||
## That's great, but what are you talking about?
|
||||
|
||||
Let's look at a typical example: retrieving a list of companies, the departments at said company, and the employees
|
||||
assigned to each department. In REST, that
|
||||
would be 3 separate requests, like the following pseudo-code:
|
||||
|
||||
```js
|
||||
const companies = request( { dataType: 'company' } );
|
||||
|
||||
for ( company in companies ) {
|
||||
const departments = request( { dataType: 'department', companyId: company.id } );
|
||||
|
||||
for ( department in departments ) {
|
||||
const employees = request( { dataType: 'employee', departmentId: department.id } );
|
||||
department.employees = employees;
|
||||
}
|
||||
|
||||
company.departments = departments;
|
||||
}
|
||||
|
||||
return companies;
|
||||
```
|
||||
|
||||
Not terrible, but if more nesting/relationships were required, things would quickly balloon out of control.
|
||||
Not to mention we're making 3 distinct requests to the server, requiring more time and bandwidth.
|
||||
|
||||
Now let's look at how this would work in GraphQL:
|
||||
|
||||
```js
|
||||
const query = `company {
|
||||
id,
|
||||
name,
|
||||
address,
|
||||
department {
|
||||
id,
|
||||
name,
|
||||
employeeNames: employee {
|
||||
id,
|
||||
first_name,
|
||||
last_name
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
const companies = request( { query } );
|
||||
```
|
||||
|
||||
Not only do we reduce the total number of requests to one, we also have
|
||||
complete, full control over the data shape returned to us. We can even alias the various
|
||||
field values (like we do here by aliasing `employee` to `employeeNames` ). This results in substantially
|
||||
decreased overhead for the server, as new data structures don't require any updates. It also makes architecting
|
||||
the client-side system easier, as dynamic queries can be made simply by traversing the schema provided
|
||||
by the server and selecting which fields/related objects to query.
|
||||
|
||||
Magic!
|
||||
|
||||
## Monkey wrench: GraphQL is enormé.
|
||||
|
||||
This is all good and well, but how do we take advantage of GraphQL? On the plus side, it's an open-source
|
||||
system that is actively-maintained and provided by some incredible engineers at Facebook/Meta.
|
||||
|
||||
Unfortunately, it's also absolutely gigantic. Including the library required to run a functioning GraphQL server
|
||||
in PHP is dozens of additional MB of file bloat, all replete with opportunities for conflicts with other plugins
|
||||
which may use GraphQL. Includig it in a distributed plugin is a non-starter, full-stop.
|
||||
|
||||
So are we out of luck?
|
||||
|
||||
## Solution: just write our own
|
||||
|
||||
Given the limited file size constraints and variety in hosting platforms, we decided the best approach
|
||||
would be to adopt GraphQL's syntax and functionality, but hand-roll our own server for parsing GraphQL
|
||||
queries into SQL statements that we can execute against the database.
|
||||
|
||||
And thus, Project Hermes was born!
|
||||
|
||||
## The Bits and Bobs
|
||||
|
||||
Fundamentally, Hermes consists of four mechanisms: `Models`, `Handlers`, `Tokens`, and `Runners`.
|
||||
During a given request, the `Models` registered to the system are referenced by a `Handler`, which takes the Query
|
||||
String
|
||||
and lexes the string into defined `Tokens`, each of which are classes holding the
|
||||
structured data needed for the various `Runners` to execute the query.
|
||||
|
||||
That's a lot, but let's look at them one by one:
|
||||
|
||||
### Models: The Backbone of Hermes Data
|
||||
|
||||
`Models` are responsible for describing all of the various object types available for
|
||||
querying and mutation. A given `Model` defines:
|
||||
|
||||
- The fields available for the object type
|
||||
- The meta fields available to assign to the object type
|
||||
- The minimum Capability required for they querying user to access the object type
|
||||
- The relationships a given object type has to _other_ object types.
|
||||
|
||||
When a query is executed, the registered `Models` are referenced to ensure the data being
|
||||
requested exists, that the data is available to the user, and the various tables required
|
||||
for querying.
|
||||
|
||||
Consider the following:
|
||||
|
||||
```php
|
||||
class FakeContactModel extends \Gravity_Forms\Gravity_Tools\Hermes\Models\Model {
|
||||
|
||||
protected $type = 'contact';
|
||||
|
||||
protected $access_cap = 'manage_options';
|
||||
|
||||
public function fields() {
|
||||
return array(
|
||||
'id' => Field_Type_Validation_Enum::INT,
|
||||
'first_name' => Field_Type_Validation_Enum::STRING,
|
||||
'last_name' => Field_Type_Validation_Enum::STRING,
|
||||
'email' => Field_Type_Validation_Enum::EMAIL,
|
||||
'phone' => Field_Type_Validation_Enum::STRING,
|
||||
'foobar' => function ( $value ) {
|
||||
if ( $value === 'foo' ) {
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public function meta_fields() {
|
||||
return array(
|
||||
'secondary_phone' => Field_Type_Validation_Enum::STRING,
|
||||
'alternate_website' => Field_Type_Validation_Enum::STRING,
|
||||
);
|
||||
}
|
||||
|
||||
public function relationships() {
|
||||
return new \Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship_Collection(
|
||||
array(
|
||||
new \Gravity_Forms\Gravity_Tools\Hermes\Utils\Relationship( 'group', 'contact', 'manage_options', true )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This code would register a new `Model` for an object type named `contact`. It defines several fields
|
||||
that a `contact` can have, as well as any `meta` fields that might be assignable to it. The `fields`
|
||||
should exist in the related DB table as columns, while `meta` fields can be added ad-hoc and are stored
|
||||
in the separate `meta` lookup table.
|
||||
|
||||
Each field, whether meta or local, references a specific Field Validation Type, either by directly referencing
|
||||
one of the Field Validation Type Enum values, or by providing a custom callback. This determines how values
|
||||
will be validated and sanitized before being inserted into the database.
|
||||
|
||||
Finally, it establishes a relationship to another `Model`, `Group`. Since the table connects Groups _to_ Contacts,
|
||||
this `Model` designates the relationship as `reversed`, telling the system to look in the `group_contact` table.
|
||||
|
||||
With this `Model` in-hand, you can register it to a `Model_Collection` by simply using:
|
||||
|
||||
```php
|
||||
$contact = new FakeContactModel();
|
||||
$collection = new Model_Collection();
|
||||
|
||||
$collection->add( 'contact', $contact );
|
||||
```
|
||||
|
||||
### Handlers and Tokens: Hermes' traffic coordinator
|
||||
|
||||
When a Query is sent to the system (typically through a registered AJAX endpoint or REST route), it's passed to a
|
||||
`Handler`, either the `Query_Handler` for _query_ calls or
|
||||
the `Mutation_Handler` for mutation calls (Insert, Update, Delete, Connect).
|
||||
|
||||
This `Handler` then kicks off the process by passing the Query string to a set of `Tokens`, each of which take
|
||||
the string (or portions of the string) and lex it into usable objects (or `Tokens`) holding all of the data needed
|
||||
for the specific operation being handled.
|
||||
|
||||
To accomplish this, each `Token` defines a series of key/value pairs, where the `key` represents a regex `MARK` for
|
||||
identifying the
|
||||
path taken in the regular expression, and the `value` is the pattern to match against while running the expression.
|
||||
These are passed to a call to
|
||||
`preg_match_all()` against the Query string.
|
||||
|
||||
This results in an array of `MARK` designators along with a matching array containing the matched results. These pairs
|
||||
are evaluated
|
||||
and either stored to the `Token` as data or (when the `Token` is identified as requiring further lexing) passed along to
|
||||
another `Token` for
|
||||
processing.
|
||||
|
||||
### Runners: Hermes' Bravest Little Soldiers
|
||||
|
||||
Once all the various `Tokens` have been generated, we're left with a structured set of PHP Objects, each containing the
|
||||
data
|
||||
necessary for performing the Query. With these in hand, the system then passes them on to a series of `Runners`. These
|
||||
clases
|
||||
are responsible for processing the stack of `Tokens`, taking their various bits of data, and converting it into SQL
|
||||
statements
|
||||
which can then be executed against the Databse.
|
||||
|
||||
Once these SQL statements are executed, the results are collated and - when applicable - the structure outlined
|
||||
in the original Query request is returned. (Note: Delete and Connect mutations don't have a bespoke return structure.
|
||||
The response from
|
||||
such operations will be consistent).
|
||||
|
||||
## Implementing Hermes in New Projects
|
||||
|
||||
Let's go over a sample of how to implement Hermes in a new project. This example will assume that you are
|
||||
using the standard Service Provider pattern we use in other products, but if not you simple need to move the
|
||||
code to whatever bootstrapping/provider paradigm you are using.
|
||||
|
||||
### Setting up Models
|
||||
|
||||
First, you need to register a `Model_Collection` to your provider and add some `Models` to it based on what your
|
||||
data needs are. We'll register a single `Contact` model.
|
||||
|
||||
```php
|
||||
|
||||
$container->add( self::CONTACT_MODEL, function() {
|
||||
// Assume this Model exists elsewhere in the codebase.
|
||||
return new Contact_Model;
|
||||
});
|
||||
|
||||
$container->add( self::MODEL_COLLECTION, function() use ( $container ) {
|
||||
$collection = new Model_Collection();
|
||||
$collection->add( 'contact', $container->get( self::CONTACT_MODEL ) );
|
||||
});
|
||||
```
|
||||
|
||||
### Configuring the Handlers
|
||||
|
||||
Next, we need to configure the `Handlers` for use in this system. To do this,
|
||||
we'll need a couple pieces: a string representing the `db_namespace` used in this product,
|
||||
and the `Model_Collection` we registered earlier. The `db_namespace` should be unique to
|
||||
the product, and is used when generating table names.
|
||||
|
||||
```php
|
||||
$container->add( self::QUERY_HANDLER, function() use ( $container ) {
|
||||
$db_namespace = 'gravitytools';
|
||||
$model_collection = $container->get( self::MODEL_COLLECTION );
|
||||
return new Query_Handler( $db_namespace, $model_collection );
|
||||
});
|
||||
```
|
||||
|
||||
The `Mutation_Handler` is a bit more involved, as we'll also need to determine
|
||||
which Mutation types we want to support, and pass the related `Runners` to our `Handler`.
|
||||
|
||||
Typically you'll need to support Insert, Update, Connect, and Delete operations.
|
||||
|
||||
```php
|
||||
|
||||
$container->add( self::MUTATION_HANDLER, function() use ( $container ) {
|
||||
$db_namespace = 'gravitytools';
|
||||
$model_collection = $container->get( self::MODEL_COLLECTION );
|
||||
$query_handler = $container->get( self::QUERY_HANDLER );
|
||||
$runners = array(
|
||||
'insert' => new Insert_Runner( $db_namespace, $query_handler ),
|
||||
'delete' => new Delete_Runner( $db_namespace, $query_handler ),
|
||||
'connect' => new Connect_Runner( $db_namespace, $query_handler ),
|
||||
'update' => new Update_Runner( $db_namespace, $query_handler ),
|
||||
);
|
||||
return new Mutation_Handler( $db_namespace, $model_collection, $query_handler, $runners );
|
||||
});
|
||||
```
|
||||
|
||||
With that, the system now has all the information it needs to start handling Queries!
|
||||
|
||||
### Adding Endpoints
|
||||
|
||||
Finally, you'll need to add endpoints to handle the Query requests. Typically you'll want to
|
||||
register 2 endpoints, one for Query and one for Mutation, but depending on your needs you may also
|
||||
use a single endpoint and handle routing internally. For this example, we'll register 2 endpoints via
|
||||
WordPress's AJAX system.
|
||||
|
||||
```php
|
||||
add_action( 'wp_ajax_hermes_query', function() use ( $container ) {
|
||||
$query_string = filter_input( INPUT_POST, 'query', FILTER_DEFAULT );
|
||||
|
||||
// The handlers call wp_send_json() at the end, so no exit is required.
|
||||
$container->get( self::QUERY_HANDLER )->handle_query( $query_string );
|
||||
} );
|
||||
|
||||
add_action( 'wp_ajax_hermes_mutation', function() use ( $container ) {
|
||||
$query_string = filter_input( INPUT_POST, 'mutation', FILTER_DEFAULT );
|
||||
|
||||
// The handlers call wp_send_json() at the end, so no exit is required.
|
||||
$container->get( self::MUTATION_HANDLER )->handle_mutation( $query_string );
|
||||
} );
|
||||
|
||||
```
|
||||
|
||||
With that in place, `POST` requests to `/wp-admin/admin-ajax.php?action=hermes_query` will trigger a Query
|
||||
request, and `POST` requests to `/wp-admin/admin-ajax.php?action=hermes_mutation` will trigger a Mutation.
|
||||
|
||||
In actual production environments, you'll want to make sure to add in authentication via nonces/keys/some
|
||||
other mechanism, but at this point you have a functioning Hermes system!
|
||||
|
||||
## Database Table Setup
|
||||
|
||||
In the future, the sytem will reference any registered `Models` and automatically generate DB tables based
|
||||
on their information. For now, however, the table setup is a manual process.
|
||||
|
||||
The most-important aspect of table setup is that you follow the explicit naming convention required. The convention
|
||||
is as follows:
|
||||
|
||||
#### For Objects
|
||||
`$wpdb->prefix + '_' + $db_namespace + '_' + $object_type`
|
||||
|
||||
An object type named `contact` in a product with a namespace of `gravitytools` will need a table named `wp_gravitytools_contact`.
|
||||
|
||||
#### For Lookup Tables
|
||||
`$wpdb->prefix + '_' + $db_namespace + '_' + $from_object_type + '_' + $to_object_type`
|
||||
|
||||
A table connecting a `contact` to `group` in a product with a namespace of `gravitytools` will need a table named `wp_gravitytools_contact_group`.
|
||||
|
||||
Columns should be `id`, `$from_object_id`, and `$to_object_id`.
|
||||
|
||||
So our `contact` to `group` table would have columns of `id`, `contact_id`, and `group_id`.
|
||||
|
||||
#### For the Meta Table
|
||||
`$wpdb->prefix + '_' + $db_namespace + '_' + 'meta`
|
||||
|
||||
A meta table in a product with a namespace of `gravitytools` will need a table named `wp_gravitytools_meta`.
|
||||
|
||||
## Using Hermes
|
||||
|
||||
Once you've gotten Hermes set up in your environment (and created the related DB tables), you're ready to start
|
||||
querying it.
|
||||
|
||||
There are two fundamental types of interactions you can have with Hermes: `query` and `mutation`.
|
||||
|
||||
### Queries
|
||||
|
||||
Queries are the mechanism used to _retrieve_ data from the server. In a REST paradigm, this would be your
|
||||
`GET` requests. They don't modify any existing data, they simply retrieve data from the server in the shape
|
||||
sent in the query.
|
||||
|
||||
#### Basic Query
|
||||
|
||||
Let's look at a very basic example. Imagine you need to retrieve all of the `company` records from the server,
|
||||
and that you want to have the `id`, `name`, and `address` fields returned for each record. The query would look
|
||||
something like this:
|
||||
|
||||
```graphql
|
||||
{
|
||||
company {
|
||||
id,
|
||||
name,
|
||||
address
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Adding Arguments
|
||||
|
||||
That works great, but it's rare that you need to retrieve every single record of a given type in a single query.
|
||||
Instead, let's add `limit` as an `argument` so we only retreive the first 10 records:
|
||||
|
||||
```graphql
|
||||
{
|
||||
company( limit: 10 ) {
|
||||
id,
|
||||
name,
|
||||
address
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`Arguments` can be combined by passing multiple comma-delineated pairs:
|
||||
|
||||
```graphql
|
||||
{
|
||||
company( limit: 10, offset: 5, is_operational: true ) {
|
||||
id,
|
||||
name,
|
||||
address
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here we provided three `arguments`: we limite the results to 10, offset the results by 5, and restrict
|
||||
the results to only those records in which the field `is_operational` is `true`.
|
||||
|
||||
#### Argument Operators
|
||||
|
||||
By default, an argument will be evaluated as `=` (e.g. `limit: 10` becomes `limit = 10` ). Other operator types
|
||||
can be indicated by suffixing the argument's field name with the operator type you wish to use. See the following table
|
||||
for all the supported operators.
|
||||
|
||||
| Operator Type | Suffix | Example |
|
||||
|---------------|-------------|---------------------------|
|
||||
| `=` | `No Suffix` | `length: 10` |
|
||||
| `!=` | `_ne` | `length_ne: 10` |
|
||||
| `>` | `_gt` | `length_gt: 10` |
|
||||
| `<` | `_lt` | `length_lt: 10` |
|
||||
| `>=` | `_gte` | `length_gte: 10` |
|
||||
| `<=` | `_lte` | `length_lte: 10` |
|
||||
| `IN/CONTAINS` | `_in` | `length_in: 10\|20\|30\|` |
|
||||
|
||||
|
||||
#### Related Object Records
|
||||
|
||||
We can also query for records related to the main object type we're retrieving. For instance, if we wanted to
|
||||
retrieve all of the `departments` in each `company`, we can simply add it like so:
|
||||
|
||||
```graphql
|
||||
{
|
||||
company( limit: 10 ) {
|
||||
id,
|
||||
name,
|
||||
address,
|
||||
department {
|
||||
id,
|
||||
name,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Queries can be infinitely-nested, and each level can utilize arguments and fields just like a non-nested query. Do note, however,
|
||||
that higher levels of nesting will result in more-complex queries, and on larger datasets the query time can balloon. Using `limits` and
|
||||
other `argument` types can help alleviate this, but always use caution when heavily-nesting your queries.
|
||||
|
||||
#### Aliasing
|
||||
|
||||
Sometimes, the field names we use in the database don't work particularly well in client applications. Rather than forcing
|
||||
the client application to traverse the resulting records and rename fields as needed, we can simply alias the field names directly
|
||||
in the query:
|
||||
|
||||
```graphql
|
||||
{
|
||||
first_ten_companies: company( limit: 10 ) {
|
||||
id,
|
||||
business_name: name,
|
||||
address
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This would alias `company` to `first_ten_companies`, and the field `name` to `business_name` in the resulting data. Any level of the query
|
||||
can be aliased, whether it's a field or a nested query.
|
||||
|
||||
### Mutations
|
||||
|
||||
In addition to retrieving data, we can also use Hermes to modify, create, or remove existing data. These types of operations
|
||||
are called `mutations`, and come in four varieties. The type of mutation can be defined by prefixing the `object type` with the type
|
||||
of `mutation` you wish to run.
|
||||
|
||||
#### Insert
|
||||
|
||||
An `insert` mutation inserts a new record into the database. It consists of two parts: the objects to insert, and the values to return once
|
||||
they have been inserted:
|
||||
|
||||
```graphql
|
||||
{
|
||||
insert_company( objects: [{ name: "My Business", address: "1234 Pine Drive" }]) {
|
||||
returning {
|
||||
id,
|
||||
name,
|
||||
address
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The above `mutation` would result in our record being added to the database, and the `id`, `name`, and `address` fields being returned for our new record.
|
||||
|
||||
Multiple records can be inserted at a time, and the returned values will include every record created.
|
||||
|
||||
#### Update
|
||||
|
||||
An `update` mutation modifies an existing record with new values. Similar to the `insert` mutation, we also define what data shape we want to be returned
|
||||
once the update is complete. Unlike `insert` mutations, only a single record can be updated at a time.
|
||||
|
||||
```graphql
|
||||
{
|
||||
update_company( id: 5, name: "My Updated Company Name" ){
|
||||
returning {
|
||||
id,
|
||||
name,
|
||||
address
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The above mutation would update the record with an `id` of `5` with the new name `My Updated Company Name`.
|
||||
|
||||
**Note**: every `update` mutation _must_ include an `id` so that the server knows which record to update. Updates
|
||||
based on other column values are not currently supported.
|
||||
|
||||
#### Delete
|
||||
|
||||
A `delete` mutation simply removes the provided record from the database. No returning data shape is defined, as there
|
||||
is no data to return.
|
||||
|
||||
```graphql
|
||||
{
|
||||
delete_company( id: 10 ){}
|
||||
}
|
||||
```
|
||||
|
||||
The above `mutation` would result in the company record with an id of `10` being deleted from the database.
|
||||
|
||||
**Note**: as with `update` mutations, you must pass the `id` of the record you wish to delete.
|
||||
|
||||
#### Connect
|
||||
|
||||
A `connect` mutation creates a relationship between two `object types` (if such a relationship is defined in
|
||||
the appropriate object `models`). We don't define a resulting data shape; instead the server simply returns a
|
||||
basic success/failure response.
|
||||
|
||||
```graphql
|
||||
{
|
||||
connect_company_department( from : 1, to: 3 ){}
|
||||
}
|
||||
```
|
||||
|
||||
The above `mutation` would result in the `company` with an `id` of `1` to be related to the `department` with
|
||||
an `id` of `3`.
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Runners;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Connect\Connect_Mutation_Token;
|
||||
|
||||
/**
|
||||
* A concrete implementation of Runner which handles database operations connecting
|
||||
* two object types to one another via a lookup table.
|
||||
*/
|
||||
class Connect_Runner extends Runner {
|
||||
|
||||
/**
|
||||
* Using the data provided by the Mutation_Token, this determines the correct
|
||||
* DB table for the connection and inserts the appropriate IDs into the table.
|
||||
*
|
||||
* This also checks permissions for both object types to ensure that the user has
|
||||
* the appropriate capabilities for running this connect mutation.
|
||||
*
|
||||
* @param Connect_Mutation_Token $mutation
|
||||
* @param Model $object_model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run( $mutation, $object_model, $return = false ) {
|
||||
$from_object = $mutation->from_object();
|
||||
$to_object = $mutation->to_object();
|
||||
$pairs = $mutation->pairs();
|
||||
|
||||
foreach ( $pairs as $pair ) {
|
||||
$to_id = $pair['to'];
|
||||
$from_id = $pair['from'];
|
||||
|
||||
$this->run_single( $from_object, $to_object, $from_id, $to_id, $object_model );
|
||||
}
|
||||
|
||||
$response = sprintf( '%s connections from %s to %s created.', count( $pairs ), $from_object, $to_object );
|
||||
|
||||
if ( $return ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
wp_send_json_success( $response );
|
||||
}
|
||||
|
||||
public function run_single( $from_object, $to_object, $from_id, $to_id, $object_model ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $object_model->relationships()->has( $to_object ) ) {
|
||||
$error_message = sprintf( 'Relationship from %s to %s does not exist.', $from_object, $to_object );
|
||||
throw new \InvalidArgumentException( $error_message, 455 );
|
||||
}
|
||||
|
||||
if ( ! $object_model->relationships()->get( $to_object )->has_access( 'edit' ) ) {
|
||||
$error_message = sprintf( 'Attempting to access forbidden object type %s.', $to_object );
|
||||
throw new \InvalidArgumentException( $error_message, 403 );
|
||||
}
|
||||
|
||||
$relationship = $object_model->relationships()->get( $to_object );
|
||||
|
||||
if ( $relationship->is_one_to_many() ) {
|
||||
$this->handle_otm_connection( $from_object, $to_object, $from_id, $to_id, $relationship );
|
||||
return;
|
||||
}
|
||||
|
||||
$table_name = sprintf( '%s%s_%s_%s', $wpdb->prefix, $this->db_namespace, $from_object, $to_object );
|
||||
$check_sql = sprintf( 'SELECT * FROM %s WHERE %s_id = "%s" AND %s_id = "%s"', $table_name, $from_object, $from_id, $to_object, $to_id );
|
||||
$existing = $wpdb->get_results( $check_sql );
|
||||
|
||||
if ( empty( $existing ) ) {
|
||||
$connect_sql = sprintf( 'INSERT INTO %s ( %s_id, %s_id ) VALUES( "%s", "%s" )', $table_name, $from_object, $to_object, $from_id, $to_id );
|
||||
}
|
||||
|
||||
$wpdb->query( $connect_sql );
|
||||
}
|
||||
|
||||
private function handle_otm_connection( $from_object, $to_object, $from_id, $to_id, $relationship ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = sprintf( '%s%s_%s', $wpdb->prefix, $this->db_namespace, $relationship->is_reverse() ? $from_object : $to_object );
|
||||
$id_string = sprintf( '%sId', $relationship->is_reverse() ? $to_object : $from_object );
|
||||
$check_sql = sprintf( 'SELECT * FROM %s WHERE %s = "%s" AND id = "%s"', $table_name, $id_string, $relationship->is_reverse() ? $to_id : $from_id, $relationship->is_reverse() ? $from_id : $to_id );
|
||||
$existing = $wpdb->get_results( $check_sql );
|
||||
|
||||
if ( ! empty( $existing ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connect_sql = sprintf( 'UPDATE %s SET %s = "%s" WHERE id = "%s"', $table_name, $id_string, $relationship->is_reverse() ? $to_id : $from_id, $relationship->is_reverse() ? $from_id : $to_id );
|
||||
|
||||
$wpdb->query( $connect_sql );
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Runners;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Delete\Delete_Mutation_Token;
|
||||
|
||||
/**
|
||||
* A concrete implementation of Runner which handles database operations for
|
||||
* deleting an object from the appropriate tables.
|
||||
*/
|
||||
class Delete_Runner extends Runner {
|
||||
|
||||
/**
|
||||
* Using the data provided by the Mutation_Token, this determines the correct
|
||||
* DB table for the deletion action and removes the record.
|
||||
*
|
||||
*
|
||||
* @param Delete_Mutation_Token $mutation
|
||||
* @param Model $object_model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run( $mutation, $object_model, $return = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$ids_to_delete = $mutation->ids_to_delete();
|
||||
$ids_to_delete = array_map( function( $id ) {
|
||||
return esc_sql( $id );
|
||||
}, $ids_to_delete );
|
||||
|
||||
$table_name = sprintf( '%s%s_%s', $wpdb->prefix, $this->db_namespace, $object_model->type() );
|
||||
|
||||
do_action( 'gt_hermes_before_delete', $ids_to_delete, $table_name, $object_model->type() );
|
||||
|
||||
if ( in_array( 'all', $ids_to_delete ) ) {
|
||||
$delete_sql = sprintf( 'DELETE FROM %s', $table_name );
|
||||
$ids_to_delete = array( 'all' );
|
||||
} else {
|
||||
$in_clause = sprintf( '(%s)', implode( ', ', $ids_to_delete ) );
|
||||
$delete_sql = sprintf( 'DELETE FROM %s WHERE id IN %s', $table_name, $in_clause );
|
||||
}
|
||||
|
||||
$wpdb->query( $delete_sql );
|
||||
|
||||
|
||||
if( $return ) {
|
||||
return $ids_to_delete;
|
||||
}
|
||||
|
||||
wp_send_json_success( array( 'deleted_ids' => $ids_to_delete ) );
|
||||
}
|
||||
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Runners;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Connect\Connect_Mutation_Token;
|
||||
|
||||
/**
|
||||
* A concrete implementation of Runner which handles database operations disconnecting
|
||||
* two object types from one another via a lookup table.
|
||||
*/
|
||||
class Disconnect_Runner extends Runner {
|
||||
|
||||
/**
|
||||
* Using the data provided by the Mutation_Token, this determines the correct
|
||||
* DB table for the connection and inserts the appropriate IDs into the table.
|
||||
*
|
||||
* This also checks permissions for both object types to ensure that the user has
|
||||
* the appropriate capabilities for running this connect mutation.
|
||||
*
|
||||
* @param Connect_Mutation_Token $mutation
|
||||
* @param Model $object_model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run( $mutation, $object_model, $return = false ) {
|
||||
$from_object = $mutation->from_object();
|
||||
$to_object = $mutation->to_object();
|
||||
$pairs = $mutation->pairs();
|
||||
|
||||
foreach ( $pairs as $pair ) {
|
||||
$to_id = $pair['to'];
|
||||
$from_id = $pair['from'];
|
||||
|
||||
$this->run_single( $from_object, $to_object, $from_id, $to_id, $object_model );
|
||||
}
|
||||
|
||||
$response = sprintf( '%s connections from %s to %s removed.', count( $pairs ), $from_object, $to_object );
|
||||
|
||||
if ( $return ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
wp_send_json_success( $response );
|
||||
}
|
||||
|
||||
public function run_single( $from_object, $to_object, $from_id, $to_id, $object_model ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $object_model->relationships()->has( $to_object ) ) {
|
||||
$error_message = sprintf( 'Relationship from %s to %s does not exist.', $from_object, $to_object );
|
||||
throw new \InvalidArgumentException( $error_message, 455 );
|
||||
}
|
||||
|
||||
if ( ! $object_model->relationships()->get( $to_object )->has_access( 'edit' ) ) {
|
||||
$error_message = sprintf( 'Attempting to access forbidden object type %s.', $to_object );
|
||||
throw new \InvalidArgumentException( $error_message, 403 );
|
||||
}
|
||||
|
||||
$relationship = $object_model->relationships()->get( $to_object );
|
||||
|
||||
if ( $relationship->is_one_to_many() ) {
|
||||
$this->run_otm_single( $from_object, $to_object, $from_id, $to_id, $relationship );
|
||||
return;
|
||||
}
|
||||
|
||||
$table_name = sprintf( '%s%s_%s_%s', $wpdb->prefix, $this->db_namespace, $from_object, $to_object );
|
||||
|
||||
$disconnect_sql = sprintf( 'DELETE FROM %s WHERE %s_id = "%s" AND %s_id = "%s"', $table_name, $from_object, $from_id, $to_object, $to_id );
|
||||
|
||||
$wpdb->query( $disconnect_sql );
|
||||
}
|
||||
|
||||
public function run_otm_single( $from_object, $to_object, $from_id, $to_id, $relationship ) {
|
||||
global $wpdb;
|
||||
$table_name = sprintf( '%s%s_%s', $wpdb->prefix, $this->db_namespace, $relationship->is_reverse() ? $from_object : $to_object );
|
||||
$id_string = sprintf( '%sId', $to_object );
|
||||
|
||||
$disconnect_sql = sprintf( 'UPDATE %s SET %s = "0" WHERE id = "%s"', $table_name, $id_string, $relationship->is_reverse() ? $to_id : $from_id );
|
||||
$wpdb->query( $disconnect_sql );
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Runners;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Insert\Insert_Mutation_Token;
|
||||
|
||||
/**
|
||||
* A concrete implementation of Runner which handles database operations required
|
||||
* to insert a set of objects into the appropriate tables.
|
||||
*/
|
||||
class Insert_Runner extends Runner {
|
||||
|
||||
/**
|
||||
* @var Connect_Runner
|
||||
*/
|
||||
protected $connect_runner;
|
||||
|
||||
public function __construct( $db_namespace, $query_handler, $model_collection, $connect_runner ) {
|
||||
parent::__construct( $db_namespace, $query_handler, $model_collection );
|
||||
|
||||
$this->connect_runner = $connect_runner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the data provided by the Mutation_Token, this determines the correct
|
||||
* DB table for the insertion and adds the records one-by-one.
|
||||
*
|
||||
* This also checks permissions for the object type to ensure that the user has
|
||||
* the appropriate capabilities for running this insert mutation. If any meta fields
|
||||
* are defined in the mutation, those values are inserted into the meta table with
|
||||
* the appropriate values.
|
||||
*
|
||||
* @param Insert_Mutation_Token $mutation
|
||||
* @param Model $object_model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run( $mutation, $object_model, $return = false ) {
|
||||
$insertion_objects = $mutation->children();
|
||||
$inserted_ids = array();
|
||||
$child_ids = array();
|
||||
|
||||
foreach ( $insertion_objects->children() as $idx => $object ) {
|
||||
if ( ! $this->models->has( $object->object_type() ) ) {
|
||||
throw new \InvalidArgumentException( sprintf( 'Object type %s does not exist.', $object->object_type() ) );
|
||||
}
|
||||
|
||||
$fields = $object->children();
|
||||
$object_model = $this->models->get( $object->object_type() );
|
||||
$categorized_fields = $this->categorize_fields( $object_model, $fields );
|
||||
|
||||
// Make sure to set the correct timestamps for created and updated.
|
||||
$categorized_fields['local']['dateCreated'] = gmdate( 'Y-m-d H:i:s', time() );
|
||||
$categorized_fields['local']['dateUpdated'] = gmdate( 'Y-m-d H:i:s', time() );
|
||||
|
||||
$inserted_id = $this->handle_single_insert( $object_model, $categorized_fields );
|
||||
if ( $object->is_child() ) {
|
||||
|
||||
if ( ! isset( $child_ids[ $object->parent_object_type() ] ) ) {
|
||||
$child_ids[ $object->parent_object_type() ] = array();
|
||||
}
|
||||
|
||||
if ( ! isset( $child_ids[ $object->parent_object_type() ][ $object->object_type() ] ) ) {
|
||||
$child_ids[ $object->parent_object_type() ][ $object->object_type() ] = array();
|
||||
}
|
||||
|
||||
$child_ids[ $object->parent_object_type() ][ $object->object_type() ][] = $inserted_id;
|
||||
}
|
||||
|
||||
if ( ! empty( $child_ids[ $object->object_type() ] ) ) {
|
||||
foreach ( $child_ids[ $object->object_type() ] as $child_type => $children ) {
|
||||
foreach( $children as $child_id ) {
|
||||
$this->connect_runner->run_single( $object->object_type(), $child_type, $inserted_id, $child_id, $object_model );
|
||||
}
|
||||
}
|
||||
|
||||
$child_ids[ $object->object_type() ] = array();
|
||||
}
|
||||
|
||||
if ( ! $object->is_child() ) {
|
||||
$inserted_ids[] = $inserted_id;
|
||||
}
|
||||
}
|
||||
|
||||
$objects_gql = sprintf( '{ %s: %s(id_in: %s){ %s }', $object_model->type(), $object_model->type(), implode( '|', $inserted_ids ), $mutation->return_fields() );
|
||||
|
||||
$data = $this->query_handler->handle_query( $objects_gql, $return );
|
||||
|
||||
if ( $return ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
wp_send_json_success( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to handle an individual insertion action from the array of objects to insert.
|
||||
*
|
||||
* @param Model $object_model
|
||||
* @param array $categorized_fields
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function handle_single_insert( $object_model, $categorized_fields ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = sprintf( '%s%s_%s', $wpdb->prefix, $this->db_namespace, $object_model->type() );
|
||||
$field_list = $this->get_field_name_list_from_fields( $categorized_fields['local'] );
|
||||
$values_list = $this->get_field_values_list_from_fields( $categorized_fields['local'] );
|
||||
$sql = sprintf( 'INSERT INTO %s (%s) VALUES (%s)', $table_name, $field_list, $values_list );
|
||||
|
||||
$wpdb->query( $sql );
|
||||
$object_id = $wpdb->insert_id;
|
||||
|
||||
if ( ! empty( $categorized_fields['meta'] ) ) {
|
||||
foreach ( $categorized_fields['meta'] as $key => $value ) {
|
||||
$meta_table_name = sprintf( '%s%s_meta', $wpdb->prefix, $this->db_namespace );
|
||||
$insert_fields_string = 'object_type, object_id, meta_name, meta_value';
|
||||
$insert_values_string = sprintf( '"%s", "%s", "%s", "%s"', $object_model->type(), $object_id, $key, $value );
|
||||
$meta_sql = sprintf( 'INSERT INTO %s (%s) VALUES (%s)', $meta_table_name, $insert_fields_string, $insert_values_string );
|
||||
|
||||
$wpdb->query( $meta_sql );
|
||||
}
|
||||
}
|
||||
|
||||
return $object_id;
|
||||
}
|
||||
}
|
||||
wp-content/plugins/gravitysmtp/vendor/gravityforms/gravity-tools/src/Hermes/Runners/class-runner.php
Vendored
+197
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Runners;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Enum\Field_Type_Validation_Enum;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Query_Handler;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutation_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Utils\Model_Collection;
|
||||
|
||||
/**
|
||||
* Runner
|
||||
*
|
||||
* This provides the abstract contract for a Runner.
|
||||
*
|
||||
* Runners are the classes responsible for actually running a given mutation type.
|
||||
* The majority of the logic already exists in this abstract class, so all a concrete
|
||||
* need do is implement the public ::run() method to take the mutation values and
|
||||
* handle the database interactions.
|
||||
*/
|
||||
abstract class Runner {
|
||||
|
||||
/**
|
||||
* The namespace to use for DB tables. This is used between the
|
||||
* $wpdb->prefix value and the DB table name.
|
||||
*
|
||||
* Example: passing 'gravitytools' here would result in tables such
|
||||
* as 'wp_gravitytools_meta', etc.
|
||||
*
|
||||
* This is typically defined a single time in a service provider and passed
|
||||
* to the various classes which need it, such as this Runner.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $db_namespace;
|
||||
|
||||
/**
|
||||
* The Query Handler is used to form response objects for Insert and Update operations.
|
||||
* Using it instead of direct SQL calls ensures that aliases, field validation, etc, are
|
||||
* all applied to the response just like a normal Query would.
|
||||
*
|
||||
* @var Query_Handler
|
||||
*/
|
||||
protected $query_handler;
|
||||
|
||||
/**
|
||||
* The collection of models currently available to the system.
|
||||
*
|
||||
* @var Model_Collection
|
||||
*/
|
||||
protected $models;
|
||||
|
||||
/**
|
||||
* See property descriptions for more information about these arguments and their usage.
|
||||
*
|
||||
* @param string $db_namespace
|
||||
* @param Query_Handler $query_handler
|
||||
* @param Model_Collection $model_collection
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $db_namespace, $query_handler, $model_collection ) {
|
||||
$this->db_namespace = $db_namespace;
|
||||
$this->query_handler = $query_handler;
|
||||
$this->models = $model_collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the actual mutation action against the database.
|
||||
*
|
||||
* Concrete Runners will implement this method in order to handle all
|
||||
* of the database transactions for this mutation type.
|
||||
*
|
||||
* This method should have no return value, as it is intended to be the final
|
||||
* process called before echoing the JSON to return to the client. As such, this method
|
||||
* should always end with either wp_json_send_success() or wp_json_send_error() to ensure
|
||||
* that values are echoed correctly and that the request doesn't continue after processing.
|
||||
*
|
||||
* @param Mutation_Token $mutation
|
||||
* @param Model $object_model
|
||||
* @param bool $return
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function run( $mutation, $object_model, $return = false );
|
||||
|
||||
/**
|
||||
* Helper method to take an array of fields and return a comma-delimited
|
||||
* list for use in INSERT column statements.
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_field_name_list_from_fields( $fields ) {
|
||||
return implode( ', ', array_keys( $fields ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to take an array of fields and return a comma-delimited
|
||||
* list of their values for use in an INSERT VALUES() statement.
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_field_values_list_from_fields( $fields ) {
|
||||
$values = array_values( $fields );
|
||||
foreach ( $values as $key => $value ) {
|
||||
$values[ $key ] = sprintf( '"%s"', $value );
|
||||
}
|
||||
|
||||
return implode( ', ', $values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to take an array of fields and return a set of
|
||||
* comma-delimited pairs of 'key = value' strings for usage in
|
||||
* UPDATE statements.
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_update_field_list( $fields ) {
|
||||
$pairs = array();
|
||||
|
||||
foreach ( $fields as $key => $value ) {
|
||||
if ( $key === 'id' ) {
|
||||
continue;
|
||||
}
|
||||
$pairs[] = sprintf( '%s = "%s"', $key, $value );
|
||||
}
|
||||
|
||||
return implode( ', ', $pairs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an object model and array of fields to process and categorizes them into
|
||||
* 'local' (aka, existing in the database as columns) fields and 'meta' fields. This
|
||||
* also uses the Model to check permissions for the given object type, and ensures
|
||||
* that all referenced fields are properly defined in the Model.
|
||||
*
|
||||
* @param Model $object_model
|
||||
* @param array $fields_to_process
|
||||
*
|
||||
* @return array|array[]
|
||||
*/
|
||||
protected function categorize_fields( $object_model, $fields_to_process ) {
|
||||
$categorized = array(
|
||||
'meta' => array(),
|
||||
'local' => array(),
|
||||
);
|
||||
|
||||
foreach ( $fields_to_process as $field_name => $value ) {
|
||||
|
||||
// Sometimes parsed empty arrays get misidentified as columnar fields. We need to disregard them.
|
||||
if ( is_array( $value ) && empty( $value ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! $object_model->supports_ad_hoc_fields() && ! array_key_exists( $field_name, $object_model->fields() ) && ! array_key_exists( $field_name, $object_model->meta_fields() ) ) {
|
||||
$error_string = sprintf( 'Attempting to access invalid field %s on object type %s', $field_name, $object_model->type() );
|
||||
throw new \InvalidArgumentException( $error_string, 450 );
|
||||
}
|
||||
|
||||
if ( array_key_exists( $field_name, $object_model->fields() ) ) {
|
||||
$field_validation_type = $object_model->fields()[ $field_name ];
|
||||
$validated = Field_Type_Validation_Enum::validate( $field_validation_type, $value );
|
||||
|
||||
if ( ! is_null( $value ) && is_null( $validated ) ) {
|
||||
$field_type_string = is_string( $field_validation_type ) ? $field_validation_type : 'callback';
|
||||
$error_string = sprintf( 'Invalid field value %s sent to field %s with a type of %s.', $value, $field_name, $field_type_string );
|
||||
throw new \InvalidArgumentException( $error_string, 451 );
|
||||
}
|
||||
|
||||
$categorized['local'][ $field_name ] = $validated;
|
||||
}
|
||||
|
||||
if ( array_key_exists( $field_name, $object_model->meta_fields() ) ) {
|
||||
$field_validation_type = $object_model->meta_fields()[ $field_name ];
|
||||
|
||||
$validated = Field_Type_Validation_Enum::validate( $field_validation_type, $value );
|
||||
|
||||
if ( ! is_null( $value ) && is_null( $validated ) ) {
|
||||
$error_string = sprintf( 'Invalid field value %s sent to field %s with a type of %s.', $value, $field_name, (string) $field_validation_type );
|
||||
throw new \InvalidArgumentException( $error_string, 451 );
|
||||
}
|
||||
|
||||
$categorized['meta'][ $field_name ] = $validated;
|
||||
}
|
||||
}
|
||||
|
||||
return $categorized;
|
||||
}
|
||||
}
|
||||
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Runners;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Data_Object_From_Array_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Field_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Utils\Model_Collection;
|
||||
|
||||
class Schema_Runner {
|
||||
|
||||
/**
|
||||
* @var Model_Collection
|
||||
*/
|
||||
protected $models;
|
||||
|
||||
private $available_fields = array(
|
||||
'name',
|
||||
'fields',
|
||||
'metaFields',
|
||||
'relationships',
|
||||
);
|
||||
|
||||
private $sub_fields_map = array(
|
||||
'fields' => array(
|
||||
'name',
|
||||
'type',
|
||||
),
|
||||
'meta_fields' => array(
|
||||
'name',
|
||||
'type',
|
||||
),
|
||||
'relationships' => array(
|
||||
'to',
|
||||
'accessCap',
|
||||
),
|
||||
);
|
||||
|
||||
public function __construct( $models ) {
|
||||
$this->models = $models;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the process for gathering info about the schema.
|
||||
*
|
||||
* @var Data_Object_From_Array_Token $object
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function run( $object ) {
|
||||
$data = array();
|
||||
foreach ( $this->models->all() as $model ) {
|
||||
$data[] = $this->get_data_for_model( $object->children(), $model );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get model data for a single model using the given fields.
|
||||
*
|
||||
* @param array $fields
|
||||
* @param Model $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_data_for_model( $fields, $model ) {
|
||||
$data = array();
|
||||
|
||||
foreach ( $fields as $field ) {
|
||||
$check_val = is_a( $field, Field_Token::class ) ? $field->name() : $field->object_type();
|
||||
|
||||
if ( ! in_array( $check_val, $this->available_fields ) ) {
|
||||
throw new \InvalidArgumentException( sprintf( 'Attempting to access invalid schema field %s', $check_val ) );
|
||||
}
|
||||
|
||||
if ( is_a( $field, Data_Object_From_Array_Token::class ) ) {
|
||||
$subfields_to_include = $this->get_field_names_from_token( $field );
|
||||
}
|
||||
|
||||
switch ( $check_val ) {
|
||||
case 'name':
|
||||
$data[ $check_val ] = $model->type();
|
||||
break;
|
||||
case 'fields':
|
||||
$row_data = array();
|
||||
foreach( $model->fields() as $field_name => $field_type ) {
|
||||
if ( ! is_string( $field_type ) ) {
|
||||
$field_type = 'custom';
|
||||
}
|
||||
$row_subdata = array();
|
||||
if ( in_array( 'name', $subfields_to_include ) ) {
|
||||
$row_subdata['name'] = $field_name;
|
||||
}
|
||||
if ( in_array( 'type', $subfields_to_include ) ) {
|
||||
$row_subdata['type'] = $field_type;
|
||||
}
|
||||
$row_data[] = $row_subdata;
|
||||
}
|
||||
$data[ $check_val ] = $row_data;
|
||||
break;
|
||||
case 'metaFields':
|
||||
$row_data = array();
|
||||
foreach( $model->meta_fields() as $field_name => $field_type ) {
|
||||
if( ! is_string( $field_type ) ) {
|
||||
$field_type = 'custom';
|
||||
}
|
||||
$row_subdata = array();
|
||||
if ( in_array( 'name', $subfields_to_include ) ) {
|
||||
$row_subdata['name'] = $field_name;
|
||||
}
|
||||
if ( in_array( 'type', $subfields_to_include ) ) {
|
||||
$row_subdata['type'] = $field_type;
|
||||
}
|
||||
|
||||
$row_data[] = $row_subdata;
|
||||
}
|
||||
$data[ $check_val ] = $row_data;
|
||||
break;
|
||||
case 'relationships':
|
||||
$row_data = array();
|
||||
foreach( $model->relationships()->all() as $relationship ) {
|
||||
$row_subdata = array();
|
||||
if ( in_array( 'to', $subfields_to_include ) ) {
|
||||
$row_subdata['to'] = $relationship->to();
|
||||
}
|
||||
if( in_array( 'accessCap', $subfields_to_include ) ) {
|
||||
$row_subdata['accessCap'] = $relationship->cap();
|
||||
}
|
||||
$row_data[] = $row_subdata;
|
||||
}
|
||||
$data[ $check_val ] = $row_data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get individual field names from a given token.
|
||||
*
|
||||
* @param Data_Object_From_Array_Token $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_field_names_from_token( $token ) {
|
||||
$fields = array();
|
||||
|
||||
foreach( $token->fields() as $field ) {
|
||||
$fields[] = $field->name();
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Runners;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Update\Update_Mutation_Token;
|
||||
|
||||
/**
|
||||
* A concrete implementation of Runner which handles database operations required
|
||||
* to insert a set of objects into the appropriate tables.
|
||||
*/
|
||||
class Update_Runner extends Runner {
|
||||
|
||||
/**
|
||||
* Using the data provided by the Mutation_Token, this determines the correct
|
||||
* DB table for the update and updates the record identified by the ID column.
|
||||
*
|
||||
* This also checks permissions for the object type to ensure that the user has
|
||||
* the appropriate capabilities for running this update mutation. If any meta fields
|
||||
* are defined in the mutation, those values are inserted into the meta table with
|
||||
* the appropriate values.
|
||||
*
|
||||
* @param Update_Mutation_Token $mutation
|
||||
* @param Model $object_model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run( $mutation, $object_model, $return = false ) {
|
||||
$fields_to_update = $mutation->children()->children();
|
||||
|
||||
if ( ! array_key_exists( 'id', $fields_to_update ) ) {
|
||||
$error_string = sprintf( 'Update mutations must contain an id in the fields list. Fields provided: %s', json_encode( array_keys( $fields_to_update ) ) );
|
||||
throw new \InvalidArgumentException( $error_string, 452 );
|
||||
}
|
||||
|
||||
$object_id = $fields_to_update['id'];
|
||||
|
||||
$categorized_fields = $this->categorize_fields( $object_model, $fields_to_update );
|
||||
|
||||
// Set dateUpdated with current time
|
||||
$categorized_fields['local']['dateUpdated'] = gmdate( 'Y-m-d H:i:s', time() );
|
||||
|
||||
$this->handle_single_update( $object_model, $categorized_fields, $object_id );
|
||||
|
||||
$objects_gql = sprintf( '{ %s: %s(id: %s){ %s }', $object_model->type(), $object_model->type(), $object_id, $mutation->return_fields() );
|
||||
|
||||
$data = $this->query_handler->handle_query( $objects_gql, $return );
|
||||
|
||||
if ( $return ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
wp_send_json_success( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to handle an individual update action from the array of objects to update.
|
||||
*
|
||||
* @param Model $object_model
|
||||
* @param array $categorized_fields
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function handle_single_update( $object_model, $categorized_fields, $object_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = sprintf( '%s%s_%s', $wpdb->prefix, $this->db_namespace, $object_model->type() );
|
||||
$field_list = $this->get_update_field_list( $categorized_fields['local'] );
|
||||
$sql = sprintf( 'UPDATE %s SET %s WHERE id = "%s"', $table_name, $field_list, $object_id );
|
||||
|
||||
$wpdb->query( $sql );
|
||||
|
||||
if ( ! empty( $categorized_fields['meta'] ) ) {
|
||||
foreach ( $categorized_fields['meta'] as $key => $value ) {
|
||||
$meta_table_name = sprintf( '%s%s_meta', $wpdb->prefix, $this->db_namespace );
|
||||
|
||||
$delete_sql = sprintf( 'DELETE FROM %s WHERE meta_name = "%s" AND object_id = "%s"', $meta_table_name, $key, $object_id );
|
||||
$wpdb->query( $delete_sql );
|
||||
|
||||
$insert_fields_string = 'object_type, object_id, meta_name, meta_value';
|
||||
$insert_values_string = sprintf( '"%s", "%s", "%s", "%s"', $object_model->type(), $object_id, $key, $value );
|
||||
$meta_sql = sprintf( 'INSERT INTO %s (%s) VALUES (%s)', $meta_table_name, $insert_fields_string, $insert_values_string );
|
||||
|
||||
$wpdb->query( $meta_sql );
|
||||
}
|
||||
}
|
||||
|
||||
return $object_id;
|
||||
}
|
||||
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Connect;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutation_Token;
|
||||
|
||||
/**
|
||||
* Connect Mutation Token
|
||||
*
|
||||
* A token containing information for perfoming a Connect Mutation.
|
||||
*/
|
||||
class Connect_Mutation_Token extends Mutation_Token {
|
||||
|
||||
protected $operation = 'connect';
|
||||
|
||||
/**
|
||||
* A token containing the IDs to connect.
|
||||
*
|
||||
* @var Connection_Values_Token
|
||||
*/
|
||||
protected $connection_ids;
|
||||
|
||||
/**
|
||||
* The object type to connect from.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $from_object;
|
||||
|
||||
/**
|
||||
* The object type to connect to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $to_object;
|
||||
|
||||
/**
|
||||
* Public $from_object accessor.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function from_object() {
|
||||
return $this->from_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public $to_object accessor.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function to_object() {
|
||||
return $this->to_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public $pairs accessor.
|
||||
*
|
||||
* $return array
|
||||
*/
|
||||
public function pairs() {
|
||||
return $this->connection_ids->pairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class properties as an array when children() is called.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function children() {
|
||||
return array(
|
||||
'from_object' => $this->from_object(),
|
||||
'to_object' => $this->to_object(),
|
||||
'pairs' => $this->pairs(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $results );
|
||||
$this->tokenize( $results );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given REGEX matches to generate the appropriate tokens for this mutation.
|
||||
*
|
||||
* @param array $parts - An array resulting from preg_match_all() with this class's regex values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tokenize( $parts ) {
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
$data = array();
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'operation_alias':
|
||||
$objects = str_replace( 'connect_', '', $value );
|
||||
$object_parts = explode( '_', $objects );
|
||||
|
||||
if ( count( $object_parts ) !== 2 ) {
|
||||
throw new \InvalidArgumentException( 'Error parsing connection object types.', 480 );
|
||||
}
|
||||
|
||||
$data['from_object'] = $object_parts[0];
|
||||
$data['to_object'] = $object_parts[1];
|
||||
$data['alias'] = $value;
|
||||
break;
|
||||
case 'arg_group':
|
||||
$data['connection_ids'] = new Connection_Values_Token( $value );
|
||||
break;
|
||||
case 'alias':
|
||||
$has_alias = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $data['connection_ids'] ) || empty( $data['from_object'] ) ) {
|
||||
throw new \InvalidArgumentException( 'Connect payload malformed. Check values and try again.', 485 );
|
||||
}
|
||||
|
||||
$this->set_properties( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the parsed tokens data to set the class properties.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function set_properties( $data ) {
|
||||
$this->alias = $data['alias'];
|
||||
$this->connection_ids = $data['connection_ids'];
|
||||
$this->object_type = $data['from_object'];
|
||||
$this->from_object = $data['from_object'];
|
||||
$this->to_object = $data['to_object'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function regex_types() {
|
||||
return array(
|
||||
'operation_alias' => 'connect_[^\(]*',
|
||||
'arg_group' => '\[[^\]]+\]',
|
||||
'alias' => '[_A-Za-z][_0-9A-Za-z]*:',
|
||||
'open_bracket' => '{',
|
||||
'close_bracket' => '}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Connect;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Token;
|
||||
|
||||
/**
|
||||
* Connection Values Token
|
||||
*
|
||||
* Used to hold the IDs to use for a given Connect mutation.
|
||||
*/
|
||||
class Connection_Values_Token extends Token {
|
||||
|
||||
protected $type = 'Connection_Values';
|
||||
|
||||
/**
|
||||
* An array of sub-arrays, each consisting of a `to` and `from` index.
|
||||
*
|
||||
* @var array[]
|
||||
*/
|
||||
protected $pairs = array();
|
||||
|
||||
public function pairs() {
|
||||
return $this->pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the $to and $from values as children.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function children() {
|
||||
return $this->pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $results );
|
||||
|
||||
$matches = $results[0];
|
||||
$marks = $results['MARK'];
|
||||
$state = array();
|
||||
$data = array();
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'argument_pair':
|
||||
$parts = explode( ':', $value );
|
||||
|
||||
if ( count( $parts ) < 2 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$key = trim( $parts[0] );
|
||||
$this_value = trim( $parts[1] );
|
||||
|
||||
if ( ! in_array( $key, array( 'to', 'from' ) ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$state[ $key ] = trim( $this_value, ' "' );
|
||||
break;
|
||||
|
||||
case 'splitter':
|
||||
// We don't have a to and from, bail.
|
||||
if ( empty( $state['to'] ) || empty( $state['from'] ) ) {
|
||||
$state = array();
|
||||
break;
|
||||
}
|
||||
|
||||
$data[] = $state;
|
||||
$state = array();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $state['to'] ) && ! empty( $state['from'] ) ) {
|
||||
$data[] = $state;
|
||||
$state = array();
|
||||
}
|
||||
|
||||
$this->pairs = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function regex_types() {
|
||||
return array(
|
||||
'argument_pair' => '([a-zA-z0-9_-]*):([^,\}\)]+)',
|
||||
'splitter' => '\},',
|
||||
);
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Connect;
|
||||
|
||||
class Disconnect_Mutation_Token extends Connect_Mutation_Token {
|
||||
|
||||
protected $operation = 'disconnect';
|
||||
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Delete;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutation_Token;
|
||||
|
||||
/**
|
||||
* Delete Mutation Token
|
||||
*
|
||||
* Contains the values for executing a Delete mutation.
|
||||
*/
|
||||
class Delete_Mutation_Token extends Mutation_Token {
|
||||
|
||||
protected $operation = 'delete';
|
||||
|
||||
/**
|
||||
* Token holding the ID to delete.
|
||||
*
|
||||
* @var ID_To_Delete_Token
|
||||
*/
|
||||
protected $id_to_delete;
|
||||
|
||||
/**
|
||||
* Public accessor for the ID to delete.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function ids_to_delete() {
|
||||
return $this->id_to_delete->ids();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through the children from the $id_to_delete token.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function children() {
|
||||
return $this->id_to_delete->children();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $results );
|
||||
$this->tokenize( $results );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given REGEX matches to generate the appropriate tokens for this mutation.
|
||||
*
|
||||
* @param array $parts - An array resulting from preg_match_all() with this class's regex values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tokenize( $parts ) {
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
$data = array();
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'operation_alias':
|
||||
$data['object_type'] = str_replace( 'delete_', '', $value );
|
||||
$data['alias'] = $value;
|
||||
break;
|
||||
case 'arg_group':
|
||||
$data['id_to_delete'] = new ID_To_Delete_Token( $value );
|
||||
break;
|
||||
case 'alias':
|
||||
$has_alias = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $data['id_to_delete'] ) || empty( $data['object_type'] ) ) {
|
||||
throw new \InvalidArgumentException( 'Delete payload malformed. Check values and try again.', 490 );
|
||||
}
|
||||
|
||||
$this->set_properties( $data );
|
||||
}
|
||||
|
||||
protected function set_properties( $data ) {
|
||||
$this->alias = $data['alias'];
|
||||
$this->object_type = $data['object_type'];
|
||||
$this->id_to_delete = $data['id_to_delete'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function regex_types() {
|
||||
return array(
|
||||
'operation_alias' => 'delete_[^\(]*',
|
||||
'arg_group' => '\([^\)]+\)',
|
||||
'alias' => '[_A-Za-z][_0-9A-Za-z]*:',
|
||||
'open_bracket' => '{',
|
||||
'close_bracket' => '}',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Delete;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Token;
|
||||
|
||||
/**
|
||||
* ID To Delete Token
|
||||
*
|
||||
* Stores the ID to delete for a Delete mutation.
|
||||
*/
|
||||
class ID_To_Delete_Token extends Token {
|
||||
|
||||
protected $type = 'IDs_To_Delete';
|
||||
|
||||
/**
|
||||
* The IDs to delete.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $ids;
|
||||
|
||||
/**
|
||||
* Public accessor for $id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function ids() {
|
||||
return $this->ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID as an array as children.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function children() {
|
||||
return $this->ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $results );
|
||||
|
||||
$matches = $results[0];
|
||||
$marks = $results['MARK'];
|
||||
$data = array();
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'ids':
|
||||
$data['ids'] = json_decode( $value );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $data['ids'] ) ) {
|
||||
throw new \InvalidArgumentException( 'Delete payload malformed. Check values and try again.', 490 );
|
||||
}
|
||||
|
||||
$this->ids = $data['ids'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function regex_types() {
|
||||
return array(
|
||||
'ids' => '\[[^\]]+\]',
|
||||
);
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Insert;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutation_Token;
|
||||
|
||||
/**
|
||||
* Insert Mutation Token
|
||||
*
|
||||
* Holds the values for an Insert mutation.
|
||||
*/
|
||||
class Insert_Mutation_Token extends Mutation_Token {
|
||||
|
||||
protected $operation = 'insert';
|
||||
|
||||
/**
|
||||
* An string of fields to return after the mutation is performed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $return_fields = '';
|
||||
|
||||
/**
|
||||
* A token holding the various objects to insert during this mutation.
|
||||
*
|
||||
* @var Insertion_Objects_Token
|
||||
*/
|
||||
protected $objects_to_insert;
|
||||
|
||||
/**
|
||||
* Public accessor for $return_fields.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function return_fields() {
|
||||
return $this->return_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return $objects_to_insert as children.
|
||||
*
|
||||
* @return Insertion_Objects_Token
|
||||
*/
|
||||
public function children() {
|
||||
return $this->objects_to_insert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
$contents = preg_replace( "/\r|\n|\t/", '', $contents );
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $results );
|
||||
$this->tokenize( $results );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given REGEX matches to generate the appropriate tokens for this mutation.
|
||||
*
|
||||
* @param array $parts - An array resulting from preg_match_all() with this class's regex values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tokenize( $parts ) {
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
$data = array();
|
||||
|
||||
$next_is_return = false;
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'returning_def':
|
||||
$cleaned_return_def = preg_replace( "/\r|\n|\t/", '', $value );
|
||||
$cleaned_return_def = str_replace( 'returning {', '', $cleaned_return_def );
|
||||
$cleaned_return_def = substr( $cleaned_return_def, 0, -3 );
|
||||
$data['return_fields'] = $cleaned_return_def;
|
||||
break;
|
||||
case 'operation_alias':
|
||||
$data['object_type'] = str_replace( 'insert_', '', $value );
|
||||
$data['alias'] = $value;
|
||||
break;
|
||||
case 'arg_group':
|
||||
$data['objects_to_insert'] = new Insertion_Objects_Token( $value, array( 'object_type' => $data['object_type'] ) );
|
||||
break;
|
||||
case 'alias':
|
||||
$has_alias = $value;
|
||||
break;
|
||||
case 'identifier':
|
||||
break;
|
||||
case 'close_bracket':
|
||||
if ( $next_is_return ) {
|
||||
$next_is_return = false;
|
||||
break;
|
||||
} else {
|
||||
$this->set_properties( $data );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->set_properties( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the parsed tokens data to set the class properties.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function set_properties( $data ) {
|
||||
$this->alias = $data['alias'];
|
||||
$this->object_type = $data['object_type'];
|
||||
$this->objects_to_insert = $data['objects_to_insert'];
|
||||
$this->return_fields = $data['return_fields'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function regex_types() {
|
||||
return array(
|
||||
'returning_def' => 'returning {[^\%]+',
|
||||
'operation_alias' => 'insert_[^\(]*',
|
||||
'arg_group' => '\(\s*objects:.*\)\s*\{',
|
||||
'alias' => '[_A-Za-z][_0-9A-Za-z]*:',
|
||||
'identifier' => '[_A-Za-z][_0-9A-Za-z]*',
|
||||
'open_bracket' => '{',
|
||||
'close_bracket' => '}',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Insert;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Token_From_Array;
|
||||
|
||||
/**
|
||||
* Insertion Object Token
|
||||
*
|
||||
* A token holding the values for an object to be inserted into the Database.
|
||||
*/
|
||||
class Insertion_Object_Token extends Token_From_Array {
|
||||
|
||||
protected $type = 'insertion_object';
|
||||
|
||||
/**
|
||||
* The fields to insert for this object.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
protected $object_type;
|
||||
|
||||
protected $is_child;
|
||||
|
||||
protected $parent_object_type;
|
||||
|
||||
/**
|
||||
* Return $items as children.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function children() {
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function object_type() {
|
||||
return $this->object_type;
|
||||
}
|
||||
|
||||
public function is_child() {
|
||||
return $this->is_child;
|
||||
}
|
||||
|
||||
public function parent_object_type() {
|
||||
return $this->parent_object_type;
|
||||
}
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( &$matches, &$marks, $additional_args = array() ) {
|
||||
$fields = $additional_args['fields'];
|
||||
$this->items = $fields;
|
||||
$this->object_type = $additional_args['object_type'];
|
||||
$this->is_child = $additional_args['is_child'];
|
||||
$this->parent_object_type = $additional_args['parent_object_type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function regex_types() {
|
||||
return array(
|
||||
'relatedObject' => '',
|
||||
'value' => ':[^,\}]+',
|
||||
'key' => '[a-zA-Z0-9_\-]+',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Insert;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Token;
|
||||
|
||||
/**
|
||||
* Insertion Objects Token
|
||||
*
|
||||
* A token holding a series of Insertion Object Tokens containing the various items to insert during this mutation.
|
||||
*/
|
||||
class Insertion_Objects_Token extends Token {
|
||||
|
||||
protected $type = 'insertion_objects';
|
||||
|
||||
/**
|
||||
* @var Insertion_Object_Token[]
|
||||
*/
|
||||
protected $objects;
|
||||
|
||||
/**
|
||||
* Return the array of Insertion Object Tokens as children.
|
||||
*
|
||||
* @return Insertion_Object_Token[]
|
||||
*/
|
||||
public function children() {
|
||||
return $this->objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
$contents = preg_replace( "/\r|\n|\t/", '', $contents );
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $parts );
|
||||
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
$current_object_type = $args['object_type'];
|
||||
$organized_data[ $current_object_type ] = $this->recursively_organize_tokens( $matches, $marks, $current_object_type );
|
||||
$organized_objects = array();
|
||||
$this->recursively_convert_tokens_to_objects( $organized_objects, $organized_data[ $current_object_type ]['objects'], $current_object_type, false, false );
|
||||
|
||||
$this->objects = $organized_objects;
|
||||
}
|
||||
|
||||
private function recursively_organize_tokens( &$matches, &$marks, $object_type ) {
|
||||
$data = array();
|
||||
$current_field_key = false;
|
||||
$is_child = false;
|
||||
$is_array_value = false;
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'closingArray':
|
||||
if ( $is_array_value ) {
|
||||
$is_array_value = false;
|
||||
}
|
||||
break;
|
||||
case 'key':
|
||||
if ( $is_array_value ) {
|
||||
$data[ $current_field_key ][] = $value;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $marks[0] === 'openingArray' ) {
|
||||
$object_type = $value;
|
||||
|
||||
if ( $marks[1] !== 'openingObject' ) {
|
||||
$is_array_value = true;
|
||||
$current_field_key = $value;
|
||||
}
|
||||
|
||||
if ( ! isset( $data[ $value ] ) ) {
|
||||
$data[ $value ] = array();
|
||||
|
||||
if ( $marks[1] === 'openingObject' && $object_type !== 'objects' ) {
|
||||
$data[ $value ]['isChild'] = true;
|
||||
}
|
||||
|
||||
$is_child = ( $marks[1] === 'openingObject' );
|
||||
}
|
||||
break;
|
||||
}
|
||||
$current_field_key = $value;
|
||||
break;
|
||||
case 'openingObject':
|
||||
if ( $is_child ) {
|
||||
$data[ $object_type ][] = $this->recursively_organize_tokens( $matches, $marks, $object_type );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'closingObject':
|
||||
return $data;
|
||||
case 'value':
|
||||
$field_value = trim( $value, ': ' );
|
||||
if ( $current_field_key ) {
|
||||
$data[ $current_field_key ] = $field_value;
|
||||
$current_field_key = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function recursively_convert_tokens_to_objects( &$organized_objects, $data, $current_object_type, $parent_object_type = false, $is_child = false ) {
|
||||
$fields = array();
|
||||
$marks = array();
|
||||
$matches = array();
|
||||
|
||||
foreach ( $data as $object_idx => $object_data ) {
|
||||
// Avoid bad data.
|
||||
if ( ! is_array( $object_data ) || empty( $object_data ) ) {
|
||||
continue;
|
||||
}
|
||||
foreach ( $object_data as $key => $value ) {
|
||||
if ( is_array( $value ) && isset( $value['isChild'] ) ) {
|
||||
unset( $value['isChild'] );
|
||||
$this->recursively_convert_tokens_to_objects( $organized_objects, $value, $key, $current_object_type, true );
|
||||
continue;
|
||||
}
|
||||
|
||||
$field_key = $key;
|
||||
$fields[ $field_key ] = is_string( $value ) ? trim( $value, ': "' ) : $value;
|
||||
}
|
||||
|
||||
$organized_objects[] = new Insertion_Object_Token(
|
||||
$marks,
|
||||
$matches,
|
||||
array(
|
||||
'object_type' => $current_object_type,
|
||||
'fields' => $fields,
|
||||
'is_child' => $is_child,
|
||||
'parent_object_type' => $parent_object_type,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function regex_types() {
|
||||
// (?|(*MARK:openingArray)\[|(*MARK:openingObject)\{|(*MARK:closingObject)\}|(*MARK:closingArray)\]|(*MARK:value):\s*"[^"]+\s*"|(*MARK:key)[a-zA-Z0-9_\-]+)
|
||||
return array(
|
||||
'openingArray' => '\[',
|
||||
'openingObject' => '\{',
|
||||
'closingObject' => '\}',
|
||||
'closingArray' => '\]',
|
||||
'value' => ':\s*"[^"]+\s*"',
|
||||
'key' => '[a-zA-Z0-9_\-]+',
|
||||
);
|
||||
}
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Update;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Token;
|
||||
|
||||
/**
|
||||
* Fields to Update Token
|
||||
*
|
||||
* A token holding the fields to update during this Mutation.
|
||||
*/
|
||||
class Fields_To_Update_Token extends Token {
|
||||
|
||||
protected $type = 'Fields_To_Update';
|
||||
|
||||
/**
|
||||
* The fields to update.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $items = array();
|
||||
|
||||
/**
|
||||
* Public accessor for $items.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function items() {
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return $items as children.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function children() {
|
||||
return $this->items();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $results );
|
||||
$this->tokenize( $results );
|
||||
}
|
||||
|
||||
private function reset_state( &$state ) {
|
||||
$state = array(
|
||||
'is_text_block' => false,
|
||||
'key_found' => '',
|
||||
'value_found' => '',
|
||||
);
|
||||
}
|
||||
|
||||
protected function tokenize( $parts ) {
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
$state = array(
|
||||
'is_text_block' => false,
|
||||
'key_found' => '',
|
||||
'value_found' => '',
|
||||
);
|
||||
$data = array();
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'string':
|
||||
if ( ! $state['key_found'] && ! $state['is_text_block'] ) {
|
||||
$state['key_found'] = trim( $value, ': )' );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $state['key_found'] && ! $state['is_text_block'] && ! $state['value_found'] ) {
|
||||
$state['value_found'] = trim( $value, ': )' );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $state['is_text_block'] ) {
|
||||
$state['value_found'] = $state['value_found'] . $value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'comma':
|
||||
if ( $state['is_text_block'] ) {
|
||||
$state['value_found'] = $state['value_found'] . $value;
|
||||
break;
|
||||
}
|
||||
|
||||
// End of key/value pair
|
||||
$data[ $state['key_found'] ] = $state['value_found'];
|
||||
|
||||
$this->reset_state( $state );
|
||||
break;
|
||||
|
||||
case 'colon':
|
||||
case 'comma':
|
||||
if ( $state['is_text_block'] ) {
|
||||
$state['value_found'] = $state['value_found'] . $value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'quote':
|
||||
// Start of text block.
|
||||
if ( ! $state['is_text_block'] ) {
|
||||
$state['is_text_block'] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// End of text block.
|
||||
$data[ $state['key_found'] ] = $state['value_found'];
|
||||
|
||||
$this->reset_state( $state );
|
||||
break;
|
||||
|
||||
case 'num':
|
||||
if ( $state['key_found'] && ! $state['is_text_block'] ) {
|
||||
$state['value_found'] = $value;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $state['is_text_block'] ) {
|
||||
$state['value_found'] = $state['value_found'] . $value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'esc_quote':
|
||||
if ( $state['is_text_block'] ) {
|
||||
$state['value_found'] = $state['value_found'] . '"';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $state['key_found'] && $state['value_found'] ) {
|
||||
$data[ $state['key_found'] ] = $state['value_found'];
|
||||
}
|
||||
|
||||
$data = array_filter( $data, function ( $item, $key ) {
|
||||
if ( $item === 0 || $item === '0' ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( empty( $key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $item !== false && $item !== null;
|
||||
}, ARRAY_FILTER_USE_BOTH );
|
||||
|
||||
$this->set_properties( $data );
|
||||
}
|
||||
|
||||
private function set_properties( $data ) {
|
||||
$this->items = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function regex_types() {
|
||||
return array(
|
||||
'opening_par' => '\(',
|
||||
'comma' => ',',
|
||||
'bool' => 'true|false',
|
||||
'colon' => ':',
|
||||
'comma' => ',',
|
||||
'string' => '[a-zA-Z_\s\'\.$&+;=?@#|<>.\^*()%!-]+',
|
||||
'num' => '[0-9]+',
|
||||
'quote' => '[\"\\\']',
|
||||
'esc_quote' => '\\\\"',
|
||||
'closing_para' => '\\)',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Update;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutation_Token;
|
||||
|
||||
/**
|
||||
* Update Mutation Token
|
||||
*
|
||||
* Contains the values needed for executing an Update Mutation.
|
||||
*/
|
||||
class Update_Mutation_Token extends Mutation_Token {
|
||||
|
||||
protected $operation = 'update';
|
||||
|
||||
/**
|
||||
* The fields to return after the Update has been performed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $return_fields = '';
|
||||
|
||||
/**
|
||||
* The fields to update during the mutation.
|
||||
*
|
||||
* @var Fields_To_Update_Token
|
||||
*/
|
||||
protected $fields_to_update;
|
||||
|
||||
/**
|
||||
* Public accessor for $return_fields
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function return_fields() {
|
||||
return $this->return_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public acessor for $fields_to_update.
|
||||
*
|
||||
* @return Fields_To_Update_Token
|
||||
*/
|
||||
public function fields_to_update() {
|
||||
return $this->fields_to_update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return $fields_to_update as children.
|
||||
*
|
||||
* @return Fields_To_Update_Token
|
||||
*/
|
||||
public function children() {
|
||||
return $this->fields_to_update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $results );
|
||||
$this->tokenize( $results );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given REGEX matches to generate the appropriate tokens for this mutation.
|
||||
*
|
||||
* @param array $parts - An array resulting from preg_match_all() with this class's regex values.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tokenize( $parts ) {
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
$data = array(
|
||||
'return_fields' => '',
|
||||
);
|
||||
|
||||
$next_is_return = false;
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'returning_def':
|
||||
$cleaned_return_def = preg_replace( "/\r|\n|\t/", '', $value );
|
||||
$cleaned_return_def = str_replace( 'returning {', '', $cleaned_return_def );
|
||||
$cleaned_return_def = substr( $cleaned_return_def, 0, -3 );
|
||||
$data['return_fields'] = $cleaned_return_def;
|
||||
break;
|
||||
case 'operation_alias':
|
||||
$data['object_type'] = str_replace( 'update_', '', $value );
|
||||
$data['alias'] = $value;
|
||||
break;
|
||||
case 'arg_group':
|
||||
$data['fields_to_update'] = new Fields_To_Update_Token( $value );
|
||||
break;
|
||||
case 'alias':
|
||||
$has_alias = $value;
|
||||
break;
|
||||
case 'identifier':
|
||||
if ( ! $next_is_return ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$data['return_fields'][] = $value;
|
||||
break;
|
||||
case 'close_bracket':
|
||||
if ( $next_is_return ) {
|
||||
$next_is_return = false;
|
||||
break;
|
||||
} else {
|
||||
$this->set_properties( $data );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->set_properties( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the parsed tokens data to set the class properties.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function set_properties( $data ) {
|
||||
$this->alias = $data['alias'];
|
||||
$this->object_type = $data['object_type'];
|
||||
$this->fields_to_update = $data['fields_to_update'];
|
||||
$this->return_fields = $data['return_fields'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function regex_types() {
|
||||
return array(
|
||||
'returning_def' => 'returning {[^\%]+',
|
||||
'operation_alias' => 'update_[^\(]*',
|
||||
'arg_group' => '\([^\)]+\)\s?{',
|
||||
'alias' => '[_A-Za-z][_0-9A-Za-z]*:',
|
||||
'identifier' => '[_A-Za-z][_0-9A-Za-z]*',
|
||||
'open_bracket' => '{',
|
||||
'close_bracket' => '}',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutation_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Insert\Insert_Mutation_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Update\Update_Mutation_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Delete\Delete_Mutation_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Connect\Connect_Mutation_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Connect\Disconnect_Mutation_Token;
|
||||
|
||||
/**
|
||||
* Generic Mutation Token
|
||||
*
|
||||
* A token used to take a given Mutation string and determing the specific Mutatin type to execute.
|
||||
*
|
||||
* This is the top-level entry point when dealing with a Mutation.
|
||||
*/
|
||||
class Generic_Mutation_Token extends Mutation_Token {
|
||||
|
||||
protected $type = 'generic_mutation';
|
||||
|
||||
/**
|
||||
* The type of this mutation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $mutation_type;
|
||||
|
||||
/**
|
||||
* A specific Mutation_Token for the type of mutation being executed.
|
||||
*
|
||||
* @var Mutation_Token
|
||||
*/
|
||||
protected $typed_token;
|
||||
|
||||
/**
|
||||
* Public accessor for $mutation_type;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mutation_type() {
|
||||
return $this->mutation_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public accessor for $typed_token.
|
||||
*
|
||||
* @return Mutation_Token
|
||||
*/
|
||||
public function mutation() {
|
||||
return $this->typed_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the $typed_token as children.
|
||||
*
|
||||
* @return Mutation_Token
|
||||
*/
|
||||
public function children() {
|
||||
return $this->typed_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string contents to values.
|
||||
*
|
||||
* @param string $contents
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $parts );
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
$typed_token = false;
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
if ( $mark_type !== 'operation' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$cleaned = trim( $value, '{ (' );
|
||||
|
||||
if ( strpos( $cleaned, 'insert_' ) !== false ) {
|
||||
$typed_token = new Insert_Mutation_Token( $contents );
|
||||
$this->mutation_type = 'insert';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( strpos( $cleaned, 'update_' ) !== false ) {
|
||||
$typed_token = new Update_Mutation_Token( $contents );
|
||||
$this->mutation_type = 'update';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( strpos( $cleaned, 'delete_' ) !== false ) {
|
||||
$typed_token = new Delete_Mutation_Token( $contents );
|
||||
$this->mutation_type = 'delete';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( strpos( $cleaned, 'disconnect_' ) !== false ) {
|
||||
$typed_token = new Disconnect_Mutation_Token( $contents );
|
||||
$this->mutation_type = 'disconnect';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( strpos( $cleaned, 'connect_' ) !== false ) {
|
||||
$typed_token = new Connect_Mutation_Token( $contents );
|
||||
$this->mutation_type = 'connect';
|
||||
continue;
|
||||
}
|
||||
|
||||
$typed_token = apply_filters( 'gravitytools_hermes_mutation_type_token', $typed_token, $cleaned, $contents );
|
||||
$this->mutation_type = apply_filters( 'gravitytools_hermes_mutation_type', false, $typed_token );
|
||||
}
|
||||
|
||||
if ( empty( $typed_token ) ) {
|
||||
throw new \InvalidArgumentException( 'Invalid operation type passed to mutation.', 475 );
|
||||
}
|
||||
|
||||
$this->typed_token = $typed_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* The regex types to use while parsing.
|
||||
*
|
||||
* $key represents the MARK type, while the $value represents the REGEX string to use.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function regex_types() {
|
||||
return array(
|
||||
'operation' => '\{[^\(]+\(',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens;
|
||||
|
||||
class Arguments_Token extends Token {
|
||||
|
||||
protected $type = 'Arguments';
|
||||
|
||||
protected $items = array();
|
||||
|
||||
private $comparator_strings = array(
|
||||
'_gte' => '>=',
|
||||
'_lte' => '<=',
|
||||
'_ne' => '!=',
|
||||
'_gt' => '>',
|
||||
'_lt' => '<',
|
||||
'_in' => 'in',
|
||||
);
|
||||
|
||||
public function items() {
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $parts );
|
||||
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
|
||||
// Tracking values.
|
||||
$in_text = false;
|
||||
$current_value = '';
|
||||
$current_key = '';
|
||||
$is_key = true;
|
||||
$is_value = false;
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'quote':
|
||||
$in_text = ! $in_text;
|
||||
|
||||
if ( ! $in_text ) {
|
||||
$is_key = true;
|
||||
$is_value = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'colon':
|
||||
if ( $in_text ) {
|
||||
$current_value .= $value;
|
||||
break;
|
||||
}
|
||||
$is_key = false;
|
||||
$is_value = true;
|
||||
break;
|
||||
|
||||
case 'comma':
|
||||
if ( $in_text ) {
|
||||
$current_value .= $value;
|
||||
break;
|
||||
}
|
||||
$condition_data = $this->get_condition_data_from_key( $current_key );
|
||||
$data[] = array(
|
||||
'key' => trim( $condition_data['key'], '" \'' ),
|
||||
'comparator' => $condition_data['comparator'],
|
||||
'value' => $this->parse_value( $current_value ),
|
||||
);
|
||||
|
||||
$current_key = '';
|
||||
$current_value = '';
|
||||
$is_key = true;
|
||||
$is_value = false;
|
||||
break;
|
||||
|
||||
case 'value':
|
||||
if ( $is_key ) {
|
||||
$current_key .= $value;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $is_value ) {
|
||||
$current_value .= $value;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $current_value ) && ! empty( $current_value ) ) {
|
||||
$condition_data = $this->get_condition_data_from_key( $current_key );
|
||||
$data[] = array(
|
||||
'key' => trim( $condition_data['key'], '" \'' ),
|
||||
'comparator' => $condition_data['comparator'],
|
||||
'value' => $this->parse_value( $current_value ),
|
||||
);
|
||||
}
|
||||
|
||||
$this->items = $data;
|
||||
}
|
||||
|
||||
private function parse_value( $value ) {
|
||||
$value = trim( $value, '" \'' );
|
||||
|
||||
if ( strpos( $value, '|' ) === false ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return explode( '|', $value );
|
||||
}
|
||||
|
||||
public function regex_types() {
|
||||
return array(
|
||||
'quote' => '[\'"]',
|
||||
'comma' => ',',
|
||||
'colon' => ':',
|
||||
'value' => '[\|\sa-zA-Z0-9_-]',
|
||||
);
|
||||
}
|
||||
|
||||
public function children() {
|
||||
return $this->items();
|
||||
}
|
||||
|
||||
private function get_condition_data_from_key( $key_to_check ) {
|
||||
$comparator = '=';
|
||||
$key = $key_to_check;
|
||||
|
||||
foreach ( $this->comparator_strings as $check => $result ) {
|
||||
if ( strpos( $key_to_check, $check ) !== false ) {
|
||||
$key = str_replace( $check, '', $key_to_check );
|
||||
$comparator = $result;
|
||||
|
||||
return array(
|
||||
'comparator' => $comparator,
|
||||
'key' => $key,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'comparator' => $comparator,
|
||||
'key' => $key,
|
||||
);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens;
|
||||
|
||||
abstract class Base_Token {
|
||||
|
||||
protected $type;
|
||||
|
||||
protected $parent;
|
||||
|
||||
public function type() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function parent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function set_parent( Base_Token $parent ) {
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
abstract public function children();
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens;
|
||||
|
||||
class Data_Object_From_Array_Token extends Token_From_Array {
|
||||
|
||||
protected $type = 'Data_Object';
|
||||
|
||||
protected $object_type;
|
||||
|
||||
protected $fields;
|
||||
|
||||
protected $arguments;
|
||||
|
||||
protected $alias;
|
||||
|
||||
public function object_type() {
|
||||
return $this->object_type;
|
||||
}
|
||||
|
||||
public function arguments() {
|
||||
if ( ! empty( $this->arguments ) ) {
|
||||
return $this->arguments->items();
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function fields() {
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
public function alias() {
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function parse( &$matches, &$marks, $additional_args = array() ) {
|
||||
$data = array(
|
||||
'object_type' => $additional_args['object_type'],
|
||||
'alias' => trim( $additional_args['alias'], ' :' ),
|
||||
'arguments' => false,
|
||||
'fields' => array(),
|
||||
);
|
||||
|
||||
$has_alias = false;
|
||||
|
||||
while ( ! empty( $matches ) ) {
|
||||
$value = array_shift( $matches );
|
||||
$mark_type = array_shift( $marks );
|
||||
|
||||
switch ( $mark_type ) {
|
||||
case 'arg_group':
|
||||
$data['arguments'] = new Arguments_Token( $value );
|
||||
$data['arguments']->set_parent( $this );
|
||||
break;
|
||||
case 'alias':
|
||||
$has_alias = $value;
|
||||
break;
|
||||
case 'identifier':
|
||||
if ( $marks[0] === 'open_bracket' || ( $marks[0] === 'arg_group' && $marks[1] === 'open_bracket' ) ) {
|
||||
$data_object = new self( $matches, $marks, array(
|
||||
'object_type' => $value,
|
||||
'alias' => $has_alias ? $has_alias : $value,
|
||||
) );
|
||||
$data_object->set_parent( $this );
|
||||
$data['fields'][] = $data_object;
|
||||
$has_alias = false;
|
||||
break;
|
||||
}
|
||||
|
||||
$field_data = array(
|
||||
'name' => $value,
|
||||
'alias' => trim( $has_alias, ' :' ),
|
||||
);
|
||||
|
||||
if ( $marks[0] === 'arg_group' ) {
|
||||
$args = array_shift( $matches );
|
||||
$mark = array_shift( $marks );
|
||||
$field_data['arguments'] = new Arguments_Token( $args );
|
||||
$field_data['arguments']->set_parent( $this );
|
||||
}
|
||||
|
||||
$field_token = new Field_Token( $matches, $marks, $field_data );
|
||||
$field_token->set_parent( $this );
|
||||
$data['fields'][] = $field_token;
|
||||
$has_alias = false;
|
||||
break;
|
||||
case 'close_bracket':
|
||||
$this->set_properties( $data );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->set_properties( $data );
|
||||
}
|
||||
|
||||
private function set_properties( $data ) {
|
||||
$this->fields = $data['fields'];
|
||||
$this->arguments = $data['arguments'];
|
||||
$this->object_type = $data['object_type'];
|
||||
$this->alias = $data['alias'];
|
||||
}
|
||||
|
||||
public function children() {
|
||||
return $this->fields();
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens;
|
||||
|
||||
class Field_Token extends Token_From_Array {
|
||||
|
||||
protected $type = 'Field';
|
||||
|
||||
protected $name;
|
||||
|
||||
protected $alias;
|
||||
|
||||
protected $arguments;
|
||||
|
||||
public function name() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function alias() {
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function object_type() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function arguments() {
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
public function parse( &$matches, &$marks, $additional_args = array() ) {
|
||||
$this->name = $additional_args['name'];
|
||||
$this->alias = $additional_args['alias'];
|
||||
|
||||
if ( isset( $additional_args['arguments'] ) ) {
|
||||
$this->arguments = $additional_args['arguments'];
|
||||
}
|
||||
}
|
||||
|
||||
public function children() {
|
||||
return $this->arguments();
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens;
|
||||
|
||||
abstract class Mutation_Token extends Token {
|
||||
|
||||
protected $type = 'Mutation';
|
||||
|
||||
protected $object_type;
|
||||
|
||||
protected $operation;
|
||||
|
||||
protected $alias;
|
||||
|
||||
public function object_type() {
|
||||
return $this->object_type;
|
||||
}
|
||||
|
||||
public function operation() {
|
||||
return $this->operation;
|
||||
}
|
||||
|
||||
public function alias() {
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens;
|
||||
|
||||
class Query_Token extends Token {
|
||||
|
||||
protected $type = 'Query';
|
||||
|
||||
protected $arguments;
|
||||
|
||||
protected $object_type;
|
||||
|
||||
protected $items;
|
||||
|
||||
protected $alias;
|
||||
|
||||
public function object_type() {
|
||||
return $this->object_type;
|
||||
}
|
||||
|
||||
public function items() {
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function alias() {
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function parse( $contents, $args = array() ) {
|
||||
preg_match_all( $this->get_parsing_regex(), $contents, $results );
|
||||
|
||||
$values = $this->tokenize( $results );
|
||||
|
||||
$this->object_type = 'query';
|
||||
$this->items = $values->fields();
|
||||
}
|
||||
|
||||
private function tokenize( $parts ) {
|
||||
$matches = $parts[0];
|
||||
$marks = $parts['MARK'];
|
||||
$data = array();
|
||||
|
||||
$data = new Data_Object_From_Array_Token( $matches, $marks, array( 'object_type' => $this->type, 'alias' => false ) );
|
||||
$data->set_parent( $this );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function regex_types() {
|
||||
//(?| (*MARK:arg_group)\([^\)]+\) | (*MARK:identifier)[_A-Za-z][_0-9A-Za-z]* | (*MARK:open_bracket){ | (*MARK:close_bracket)} )
|
||||
return array(
|
||||
'arg_group' => '\([^\)]+\)',
|
||||
'alias' => '[_A-Za-z][_0-9A-Za-z]*:',
|
||||
'identifier' => '[_A-Za-z][_0-9A-Za-z]*',
|
||||
'open_bracket' => '{',
|
||||
'close_bracket' => '}',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Data_Object_From_Array_Token[]
|
||||
*/
|
||||
public function children() {
|
||||
return $this->items();
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens;
|
||||
|
||||
abstract class Token_From_Array extends Base_Token {
|
||||
|
||||
public function __construct( &$matches, &$marks, $additional_args = array() ) {
|
||||
$this->parse( $matches, $marks, $additional_args );
|
||||
}
|
||||
|
||||
abstract public function parse( &$matches, &$marks, $additional_args = array() );
|
||||
}
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Tokens;
|
||||
|
||||
abstract class Token extends Base_Token {
|
||||
|
||||
protected $args = array();
|
||||
|
||||
public function __construct( $contents, $args = array() ) {
|
||||
$this->parse( $contents, $args );
|
||||
}
|
||||
|
||||
protected function regex_types() {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function get_parsing_regex() {
|
||||
$clauses = array();
|
||||
|
||||
foreach ( $this->regex_types() as $type => $pattern ) {
|
||||
$clauses[] = sprintf( '(*MARK:%s)%s', $type, $pattern );
|
||||
}
|
||||
|
||||
$clauses_concat = implode( '|', $clauses );
|
||||
|
||||
return sprintf( '/(?|%s)/m', $clauses_concat );
|
||||
}
|
||||
|
||||
abstract public function parse( $contents, $args = array() );
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Utils;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
|
||||
/**
|
||||
* Model Collection
|
||||
*
|
||||
* A simple collection class for storing registered Models in the system.
|
||||
*/
|
||||
class Model_Collection {
|
||||
|
||||
/**
|
||||
* @var Model[]
|
||||
*/
|
||||
protected $models = array();
|
||||
|
||||
/**
|
||||
* Register a model type.
|
||||
*
|
||||
* @param string $type
|
||||
* @param Model $model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add( $type, Model $model ) {
|
||||
$this->models[ $type ] = $model;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unregister/remove a Model type.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function remove( $type ) {
|
||||
unset( $this->models[ $type ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Model of a given type exists in the collection.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has( $type ) {
|
||||
return array_key_exists( $type, $this->models );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Model from the collection by its type.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Model|null
|
||||
*/
|
||||
public function get( $type ) {
|
||||
if ( ! $this->has( $type ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->models[ $type ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered models from collection.
|
||||
*
|
||||
* @return Model[]
|
||||
*/
|
||||
public function all() {
|
||||
return $this->models;
|
||||
}
|
||||
}
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Utils;
|
||||
|
||||
/**
|
||||
* Relationshp Collection
|
||||
*
|
||||
* A simple collection handling Relationship objects.
|
||||
*/
|
||||
class Relationship_Collection {
|
||||
|
||||
/**
|
||||
* @var Relationship[]
|
||||
*/
|
||||
protected $relationships;
|
||||
|
||||
/**
|
||||
* @param Relationship[] $relationships
|
||||
*/
|
||||
public function __construct( $relationships = array() ) {
|
||||
$this->relationships = $relationships;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Relationship to the collection.
|
||||
*
|
||||
* @param Relationship $relationship
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add( Relationship $relationship ) {
|
||||
$this->relationships[] = $relationship;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a given Relationship by the related object.
|
||||
*
|
||||
* @param string $related_object
|
||||
*
|
||||
* @return Relationship|mixed|null
|
||||
*/
|
||||
public function get( $related_object ) {
|
||||
if ( ! $this->has( $related_object ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$relationship = array_filter( $this->relationships, function ( $relationship ) use ( $related_object ) {
|
||||
return $relationship->to() === $related_object;
|
||||
} );
|
||||
|
||||
return array_shift( $relationship );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the collection contains a relationship for the given object type.
|
||||
*
|
||||
* @param string $related_object
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has( $related_object ) {
|
||||
$relationship = array_filter( $this->relationships, function ( $relationship ) use ( $related_object ) {
|
||||
return $relationship->to() === $related_object;
|
||||
} );
|
||||
|
||||
return ! empty( $relationship );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the relationships currently registered to collection.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all() {
|
||||
return $this->relationships;
|
||||
}
|
||||
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes\Utils;
|
||||
|
||||
/**
|
||||
* Relationship
|
||||
*
|
||||
* Defines relationships between two object types.
|
||||
*
|
||||
* $from - The object to connect from
|
||||
* $to = The object to connect to
|
||||
* $cap - The minimum capability required for accessing this relationship.
|
||||
* $is_reverse - used to indicate that the relationship should use a reversed table name
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $group_contact = new Relationship( 'group', 'contact', 'manage_options', false )
|
||||
*
|
||||
* This would result in a relationship from groups to contacts, and ensure that only
|
||||
* users with the `manage_options` capability are able to access it. When the relationship
|
||||
* is queried, the system will look in a table with `_group_contact` as the suffix.
|
||||
*
|
||||
*
|
||||
* Example 2:
|
||||
*
|
||||
* $contact_group = new Relationship( 'contact', 'group', 'manage_options', true )
|
||||
*
|
||||
* This would result in a relationship from contacts to groups, again restricted to users
|
||||
* with the `manage_options` capability. Since $is_reverse is `true`, queries would continue
|
||||
* to look for a table with `_group_contact` as the suffix, when normally it would attempt to
|
||||
* locate a table with the suffix of `_contact_group`. This setup allows you to use a single
|
||||
* lookup table for both directions of the relationship.
|
||||
*/
|
||||
class Relationship {
|
||||
|
||||
/**
|
||||
* @var string The object type to connect from.
|
||||
*/
|
||||
protected $from;
|
||||
|
||||
/**
|
||||
* @var string The object type to connect to.
|
||||
*/
|
||||
protected $to;
|
||||
|
||||
/**
|
||||
* @var string The minimum WordPress role or capability required for accessing this relationship
|
||||
* from within Queries and Mutations.
|
||||
*/
|
||||
protected $cap;
|
||||
|
||||
/**
|
||||
* @var boolean Indicates if this relationship is the reversal of another relationship and should
|
||||
* use the original's lookup table for queries.
|
||||
*/
|
||||
protected $is_reverse;
|
||||
|
||||
/**
|
||||
* @var string Indicates the type of relationship - default is many_to_many, but can be one_to_many instead.
|
||||
*/
|
||||
protected $relationship_type;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param $from
|
||||
* @param $to
|
||||
* @param $cap
|
||||
* @param $is_reverse
|
||||
*/
|
||||
public function __construct( $from, $to, $cap, $is_reverse = false, $relationship_type = 'many_to_many' ) {
|
||||
$this->from = $from;
|
||||
$this->to = $to;
|
||||
$this->cap = $cap;
|
||||
$this->is_reverse = $is_reverse;
|
||||
$this->relationship_type = $relationship_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public $from accessor.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function from() {
|
||||
return $this->from;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public $to accessor.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function to() {
|
||||
return $this->to;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Public $cap accessor.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function cap() {
|
||||
return $this->cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public $is_reverse accessor
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function is_reverse() {
|
||||
return $this->is_reverse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user can access this relationship. (Uses current_user_can() by default).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_access() {
|
||||
return current_user_can( $this->cap );
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of relationship this is (many_to_many or one_to_many)
|
||||
*
|
||||
* return string
|
||||
*/
|
||||
public function relationship_type() {
|
||||
return $this->relationship_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this relationship is one-to-many
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_one_to_many() {
|
||||
return $this->relationship_type === 'one_to_many';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the correct table suffix when querying lookup tables.
|
||||
*
|
||||
* When $is_reverse is `true`, the suffix has the object type slugs swapped.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_table_suffix() {
|
||||
if ( $this->relationship_type() === 'one_to_many' ) {
|
||||
return $this->is_reverse ? $this->to : $this->from;
|
||||
}
|
||||
|
||||
if ( $this->is_reverse ) {
|
||||
return sprintf( '%s_%s', $this->to, $this->from );
|
||||
}
|
||||
|
||||
return sprintf( '%s_%s', $this->from, $this->to );
|
||||
}
|
||||
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Runners\Connect_Runner;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Runners\Delete_Runner;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Runners\Disconnect_Runner;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Runners\Insert_Runner;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Runners\Runner;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Runners\Update_Runner;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Mutations\Generic_Mutation_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Utils\Model_Collection;
|
||||
|
||||
/**
|
||||
* The initial entry point for handling Mutation requests. For Query handling, see Query_Handler.
|
||||
*/
|
||||
class Mutation_Handler {
|
||||
|
||||
/**
|
||||
* The namespace to use when querying DB tables. The namespace is used after the $wpdb->prefix
|
||||
* value and before the actual table name.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Passing `gravitytools` would result in a meta table name of `wp_gravitytools_meta`..
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $db_namespace;
|
||||
|
||||
/**
|
||||
* The collection of models supported for queries.
|
||||
*
|
||||
* @var Model_Collection
|
||||
*/
|
||||
protected $models;
|
||||
|
||||
/**
|
||||
* A valid Query Handler for retrieving the resulting objects after an insert/update.
|
||||
*
|
||||
* @var Query_Handler
|
||||
*/
|
||||
protected $query_handler;
|
||||
|
||||
/**
|
||||
* The Runner for handling Insert mutations.
|
||||
*
|
||||
* @var Insert_Runner
|
||||
*/
|
||||
protected $insert_runner;
|
||||
|
||||
/**
|
||||
* The Runner for handling Delete mutations.
|
||||
*
|
||||
* @var Delete_Runner
|
||||
*/
|
||||
protected $delete_runner;
|
||||
|
||||
/**
|
||||
* The Runner for handling Update mutations.
|
||||
*
|
||||
* @var Update_Runner
|
||||
*/
|
||||
protected $update_runner;
|
||||
|
||||
/**
|
||||
* The Runner for handling Connect mutations.
|
||||
*
|
||||
* @var Connect_Runner
|
||||
*/
|
||||
protected $connect_runner;
|
||||
|
||||
/**
|
||||
* The Runner for handling Disconnect mutations.
|
||||
*
|
||||
* @var Disconnect_Runner
|
||||
*/
|
||||
protected $disconnect_runner;
|
||||
|
||||
/**
|
||||
* All runners registered to handler.
|
||||
*
|
||||
* @var Runner[]
|
||||
*/
|
||||
protected $all_runners;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $db_namespace
|
||||
* @param Model_Collection $models
|
||||
* @param Query_Handler $query_handler
|
||||
* @param Runner[] $runners
|
||||
*/
|
||||
public function __construct( $db_namespace, $models, $query_handler, $runners ) {
|
||||
$this->db_namespace = $db_namespace;
|
||||
$this->models = $models;
|
||||
$this->query_handler = $query_handler;
|
||||
$this->insert_runner = $runners['insert'];
|
||||
$this->delete_runner = $runners['delete'];
|
||||
$this->update_runner = $runners['update'];
|
||||
$this->connect_runner = $runners['connect'];
|
||||
$this->disconnect_runner = $runners['disconnect'];
|
||||
$this->all_runners = $runners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the provided Mutation string and execute the appropriate SQL queries to perform the
|
||||
* mutation.
|
||||
*
|
||||
* @param string $mutation_string
|
||||
* @param bool $return
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_mutation( $mutation_string, $return = false ) {
|
||||
global $wpdb;
|
||||
|
||||
// Pass the string to the Generic Mutation token to determine the specific mutation type.
|
||||
$generic_mutation = new Generic_Mutation_Token( $mutation_string );
|
||||
|
||||
/**
|
||||
* Mutation_Token $mutation
|
||||
*/
|
||||
$mutation = $generic_mutation->mutation();
|
||||
|
||||
// Ensure the object type in question is registered in our Model Collection.
|
||||
if ( ! $this->models->has( $mutation->object_type() ) ) {
|
||||
$error_message = sprintf( 'Mutation attempted with invalid object type: %s', $mutation->object_type() );
|
||||
throw new \InvalidArgumentException( $error_message, 470 );
|
||||
}
|
||||
|
||||
$object_model = $this->models->get( $mutation->object_type() );
|
||||
|
||||
switch( $mutation->operation() ) {
|
||||
case 'insert':
|
||||
$action_check = 'create';
|
||||
break;
|
||||
case 'update':
|
||||
$action_check = 'edit';
|
||||
break;
|
||||
case 'delete':
|
||||
$action_check = 'delete';
|
||||
break;
|
||||
case 'connect':
|
||||
$action_check = 'edit';
|
||||
break;
|
||||
case 'disconnect':
|
||||
$action_check = 'edit';
|
||||
break;
|
||||
default:
|
||||
$action_check = 'view';
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure the querying user has the appropriate permissions to access data for this object.
|
||||
if ( ! $object_model->has_access( $action_check ) ) {
|
||||
$error_message = sprintf( 'Access not allowed for object type %s', $mutation->object_type() );
|
||||
throw new \InvalidArgumentException( $error_message, 403 );
|
||||
}
|
||||
|
||||
// Handle the actual mutation based on the identified mutation type by calling its appropriate Runner.
|
||||
switch ( $mutation->operation() ) {
|
||||
case 'insert':
|
||||
return $this->insert_runner->run( $mutation, $object_model, $return );
|
||||
break;
|
||||
case 'update':
|
||||
return $this->update_runner->run( $mutation, $object_model, $return );
|
||||
break;
|
||||
case 'delete':
|
||||
return $this->delete_runner->run( $mutation, $object_model, $return );
|
||||
break;
|
||||
case 'connect':
|
||||
return $this->connect_runner->run( $mutation, $object_model, $return );
|
||||
break;
|
||||
case 'disconnect':
|
||||
return $this->disconnect_runner->run( $mutation, $object_model, $return );
|
||||
break;
|
||||
default:
|
||||
if ( array_key_exists( $mutation->operation(), $this->all_runners ) ) {
|
||||
return $this->all_runners[ $mutation->operation() ]->run( $mutation, $object_model, $return );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+920
@@ -0,0 +1,920 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Hermes;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Models\Model;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Runners\Schema_Runner;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Data_Object_From_Array_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Tokens\Query_Token;
|
||||
use Gravity_Forms\Gravity_Tools\Hermes\Utils\Model_Collection;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Query Handler
|
||||
*
|
||||
* The entry point for parsing queries made to Hermes. For Mutations, see Mutation_Handler.
|
||||
*/
|
||||
class Query_Handler {
|
||||
|
||||
/**
|
||||
* The namespace to use when querying DB tables. The namespace is used after the $wpdb->prefix
|
||||
* value and before the actual table name.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Passing `gravitytools` would result in a meta table name of `wp_gravitytools_meta`..
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $db_namespace;
|
||||
|
||||
/**
|
||||
* The collection of models supported for queries.
|
||||
*
|
||||
* @var Model_Collection
|
||||
*/
|
||||
protected $models;
|
||||
|
||||
/**
|
||||
* @var Schema_Runner
|
||||
*/
|
||||
protected $schema_runner;
|
||||
|
||||
/**
|
||||
* Any fields that are global to all queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $global_fields = array(
|
||||
'aggregate',
|
||||
);
|
||||
|
||||
/**
|
||||
* Tracks any objects which use filtered data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $overridden_objects = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $db_namespace
|
||||
*/
|
||||
public function __construct( $db_namespace, Model_Collection $models, Schema_Runner $schema_runner ) {
|
||||
$this->db_namespace = $db_namespace;
|
||||
$this->models = $models;
|
||||
$this->schema_runner = $schema_runner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given query string text and perform the appropriate database queries to return
|
||||
* the requested data structure.
|
||||
*
|
||||
* @param string $query_string
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function handle_query( $query_string, $return = false ) {
|
||||
global $wpdb;
|
||||
|
||||
// Parse to token array
|
||||
$query_token = new Query_Token( $query_string );
|
||||
$data = array();
|
||||
|
||||
// Use the Token to generate recursive SQL.
|
||||
foreach ( $query_token->children() as $object ) {
|
||||
$object_name = ! empty( $object->alias() ) ? $object->alias() : $object->object_type();
|
||||
|
||||
$custom_data = apply_filters( 'gt_hermes_custom_object_data_' . $object->object_type(), null, $object );
|
||||
|
||||
if ( ! is_null( $custom_data ) ) {
|
||||
$this->overridden_objects[] = $object_name;
|
||||
$data[ $object_name ] = $custom_data;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $object->object_type() === '__schema' ) {
|
||||
$data[ $object_name ] = $this->get_schema_values_for_query( $object );
|
||||
continue;
|
||||
}
|
||||
|
||||
$sql = $this->recursively_generate_sql( $object );
|
||||
$transformations = $this->recursively_get_transformations( $object );
|
||||
$data[ $object_name ] = array(
|
||||
'sql' => sprintf( 'SELECT %s', $sql ),
|
||||
'transformations' => $transformations,
|
||||
'object' => $object,
|
||||
);
|
||||
}
|
||||
|
||||
$results = array();
|
||||
|
||||
// Decode the results and set them up for return.
|
||||
foreach ( $data as $data_group_name => $data_group_values ) {
|
||||
// Schema values do not need to be queried; just return the rows as-is.
|
||||
if ( isset( $data_group_values['schema'] ) ) {
|
||||
$results[ $data_group_name ] = $data_group_values['schema'];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Data was overwritten by a filter, return what is there.
|
||||
if ( in_array( $data_group_name, $this->overridden_objects ) ) {
|
||||
$results[ $data_group_name ] = $data_group_values;
|
||||
continue;
|
||||
}
|
||||
|
||||
$query_results = $wpdb->get_results( $data_group_values['sql'], ARRAY_A );
|
||||
$rows = array();
|
||||
|
||||
foreach ( $query_results as $query_result ) {
|
||||
$json_data = array_shift( $query_result );
|
||||
$decoded_data = json_decode( $json_data, true );
|
||||
$rows[] = $decoded_data;
|
||||
}
|
||||
|
||||
$rows = $this->recursively_apply_transformations( $rows, $data_group_values['transformations'] );
|
||||
|
||||
/**
|
||||
* Allows third-parties to modify the rows returned from a query.
|
||||
*
|
||||
* @param array $rows the current result for the query
|
||||
* @param string $data_group_name the name of the object being queried
|
||||
* @param array $data_group_values all of the various values relevant to this request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
$rows = apply_filters( 'gt_hermes_query_results', $rows, $data_group_name, $data_group_values );
|
||||
|
||||
$results[ $data_group_name ] = $rows;
|
||||
}
|
||||
|
||||
if ( $return ) {
|
||||
return $results;
|
||||
}
|
||||
|
||||
wp_send_json_success( $results );
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through the objects in the Query String and recursively generates the appropriate
|
||||
* SQL for the related query. Supports an infinite level of nesting, but caution should be used when
|
||||
* performing deeply-nested queries as performance may be impacted.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function recursively_generate_sql( Data_Object_From_Array_Token $data, $idx_prefix = null, $parent_table = false, $parent_object_type = false ) {
|
||||
$object_type = $data->object_type();
|
||||
$object_name = ! empty( $data->alias() ) ? $data->alias() : $data->object_type();
|
||||
|
||||
// Ensure the object type being queried exists as a Model.
|
||||
if ( ! $this->models->has( $object_type ) ) {
|
||||
$error_message = sprintf( 'Attempting to access invalid object type %s', $object_type );
|
||||
throw new InvalidArgumentException( $error_message, 460 );
|
||||
}
|
||||
|
||||
$object_model = $this->models->get( $object_type );
|
||||
|
||||
// Ensure that the querying user has the appropriate permissions to access object.
|
||||
if ( ! $object_model->has_access( 'view' ) ) {
|
||||
$error_message = sprintf( 'Access not allowed for object type %s', $object_type );
|
||||
throw new InvalidArgumentException( $error_message, 403 );
|
||||
}
|
||||
|
||||
// Set up values for the table being queried.
|
||||
$table_name = $this->compose_table_name( $object_type );
|
||||
$table_alias = $this->compose_table_alias( $object_name, $parent_table );
|
||||
|
||||
// Categorized queried fields as either local or meta fields for future processing.
|
||||
$fields_to_process = $data->fields();
|
||||
$categorized_fields = $this->categorize_fields( $object_model, $fields_to_process, $table_alias );
|
||||
|
||||
$arguments = $data->arguments();
|
||||
|
||||
// Set up data arrays for holding pieces of the SQL statement for later concatenation.
|
||||
$field_pairs = array();
|
||||
$where_clauses = array();
|
||||
$join_clauses = array();
|
||||
|
||||
$field_sql = null;
|
||||
$from_sql = null;
|
||||
$join_sql = null;
|
||||
$where_sql = null;
|
||||
$group_sql = null;
|
||||
$limit_sql = null;
|
||||
$order_sql = null;
|
||||
$separator_sql = null;
|
||||
|
||||
// Arguments are present; parse them and add them to the appropriate SQL arrays.
|
||||
if ( ! empty( $arguments ) ) {
|
||||
$this->get_where_clauses_from_arguments( $where_clauses, $table_alias, $arguments, $object_model );
|
||||
$limit_sql = $this->get_limit_from_arguments( $arguments );
|
||||
$order_sql = $this->get_order_from_arguments( $arguments, $table_alias );
|
||||
}
|
||||
|
||||
// Loop through each local field and generate the appropriate SQL chunks for retrieving the data.
|
||||
foreach ( $categorized_fields['local'] as $field_name => $field_alias ) {
|
||||
if ( is_a( $field_alias, Data_Object_From_Array_Token::class ) ) {
|
||||
$this_alias = empty( $field_alias->alias() ) ? $field_alias->object_type() : $field_alias->alias();
|
||||
$sub_sql = $this->recursively_generate_sql( $field_alias, null, $table_alias, $object_type );
|
||||
$sub_sql_parts = explode( '|gsmtpfieldsseparator|', $sub_sql );
|
||||
$sub_sql = sprintf( '( SELECT JSON_ARRAYAGG( %s ) %s )', $sub_sql_parts[0], $sub_sql_parts[1] );
|
||||
$field_pairs[] = sprintf( '"%s", %s', $this_alias, $sub_sql );
|
||||
continue;
|
||||
}
|
||||
$field_name = str_replace( $field_alias . '.', '', $field_name );
|
||||
$field_pairs[] = sprintf( '"%s", %s.%s', $field_alias, $table_alias, $field_name );
|
||||
}
|
||||
|
||||
$meta_table_name = $this->compose_table_name( 'meta' );
|
||||
|
||||
// Loop through each meta field and compose the appropriate JOIN query for gathering its data.
|
||||
foreach ( $categorized_fields['meta'] as $field_name => $field_data ) {
|
||||
$value_clause = $parent_table ? sprintf( '%s.meta_value', $field_data['lookup_table_alias'] ) : sprintf( 'MIN(%s.meta_value)', $field_data['lookup_table_alias'] );
|
||||
$field_pairs[] = sprintf( '"%s", %s', $field_data['alias'], $value_clause, $field_name );
|
||||
$join_clauses[] = sprintf(
|
||||
'LEFT JOIN %s AS %s ON %s.object_type = "%s" AND %s.meta_name = "%s" AND %s.object_id = %s.id',
|
||||
$meta_table_name,
|
||||
$field_data['lookup_table_alias'],
|
||||
$field_data['lookup_table_alias'],
|
||||
$object_type,
|
||||
$field_data['lookup_table_alias'],
|
||||
$field_name,
|
||||
$field_data['lookup_table_alias'],
|
||||
$table_alias
|
||||
);
|
||||
}
|
||||
|
||||
// If an aggregate is being called, add it as a subquery with the existing where conditions applied.
|
||||
if ( in_array( 'aggregate', $categorized_fields['global'] ) ) {
|
||||
$agg_alias = $categorized_fields['global']['aggregate'];
|
||||
$agg_sql = sprintf( '"%s", (SELECT COUNT(*) FROM %s', $agg_alias, $table_name );
|
||||
|
||||
if ( ! empty( $where_clauses ) ) {
|
||||
$agg_sql .= sprintf( ' WHERE %s', str_replace( $table_alias, $table_name, implode( ' AND ', $where_clauses ) ) );
|
||||
}
|
||||
|
||||
$agg_sql .= ')';
|
||||
|
||||
$field_pairs[] = $agg_sql;
|
||||
}
|
||||
|
||||
// A parent table exists, meaning this is a nested query and requires a JOIN statement relating it
|
||||
// to the parent table.
|
||||
if ( $parent_table ) {
|
||||
$this->populate_relationship_clauses( $join_clauses, $where_clauses, $parent_object_type, $object_type, $table_alias, $parent_table );
|
||||
}
|
||||
|
||||
// Run all the query params through filters to allow modification.
|
||||
$query_params = array(
|
||||
'field_pairs' => $field_pairs,
|
||||
'where_clauses' => $where_clauses,
|
||||
'join_clauses' => $join_clauses,
|
||||
'limit_sql' => $limit_sql,
|
||||
'order_sql' => $order_sql,
|
||||
);
|
||||
|
||||
$query_params = apply_filters( 'gt_hermes_query_params', $query_params, $object_type, $categorized_fields, $arguments, $table_alias, $parent_table );
|
||||
|
||||
$field_pairs = $query_params['field_pairs'];
|
||||
$where_clauses = $query_params['where_clauses'];
|
||||
$join_clauses = $query_params['join_clauses'];
|
||||
$limit_sql = $query_params['limit_sql'];
|
||||
$order_sql = $query_params['order_sql'];
|
||||
|
||||
// Concatenate each SQL array to generate the final SQL.
|
||||
$field_sql = implode( ', ', $field_pairs );
|
||||
|
||||
$from_sql = sprintf( 'FROM %s AS %s', $table_name, $table_alias );
|
||||
|
||||
$join_sql = implode( ' ', $join_clauses );
|
||||
|
||||
if ( ! empty( $where_clauses ) ) {
|
||||
$where_sql = sprintf( 'WHERE %s', implode( ' AND ', $where_clauses ) );
|
||||
}
|
||||
|
||||
$group_sql = null;
|
||||
|
||||
if ( ! $parent_table ) {
|
||||
$group_sql = sprintf( 'GROUP BY %s.id', $table_alias );
|
||||
}
|
||||
|
||||
if ( $parent_table ) {
|
||||
$separator_sql = '|gsmtpfieldsseparator|';
|
||||
}
|
||||
|
||||
// Return the resulting SQL
|
||||
return sprintf( 'JSON_OBJECT( %s ) %s %s %s %s %s %s %s', $field_sql, $separator_sql, $from_sql, $join_sql, $where_sql, $group_sql, $order_sql, $limit_sql );
|
||||
}
|
||||
|
||||
private function populate_relationship_clauses( &$join_clauses, &$where_clauses, $parent_object_type, $object_type, $table_alias, $parent_table ) {
|
||||
$parent_model = $this->models->get( $parent_object_type );
|
||||
$relationship = $parent_model->relationships()->get( $object_type );
|
||||
|
||||
if ( ! $relationship->has_access() ) {
|
||||
throw new \InvalidArgumentException( 'Attempting to access forbidden relationship ' . $relationship->to() );
|
||||
}
|
||||
|
||||
if ( $relationship->relationship_type() === 'one_to_many' ) {
|
||||
$this->populate_otm_relationship_clauses( $where_clauses, $relationship, $table_alias, $parent_table );
|
||||
return;
|
||||
}
|
||||
|
||||
$lookup_table_name = $this->compose_join_table_name( $relationship->get_table_suffix() );
|
||||
$lookup_table_alias = sprintf( 'join_%s', $table_alias );
|
||||
$id_string = sprintf( '%s_id', $object_type );
|
||||
$parent_id_string = sprintf( '%s_id', $parent_object_type );
|
||||
$join_clauses[] = sprintf( 'LEFT JOIN %s AS %s ON %s.id = %s.%s', $lookup_table_name, $lookup_table_alias, $table_alias, $lookup_table_alias, $id_string );
|
||||
$where_clauses[] = sprintf( '%s.%s = %s.id', $lookup_table_alias, $parent_id_string, $parent_table );
|
||||
}
|
||||
|
||||
private function populate_otm_relationship_clauses( &$where_clauses, $relationship, $table_alias, $parent_table ) {
|
||||
$id_string = $relationship->is_reverse() ? sprintf( '%sId', $relationship->to() ) : sprintf( '%sId', $relationship->from() );
|
||||
$where_clauses[] = sprintf( '%s.id = %s.%s', ! $relationship->is_reverse() ? $parent_table : $table_alias, ! $relationship->is_reverse() ? $table_alias : $parent_table, $id_string );
|
||||
}
|
||||
|
||||
/**
|
||||
* Categorizes fields as either local (i.e., existing as columns within the table for the object) or meta
|
||||
* (i.e., existing as custom values in the meta table).
|
||||
*
|
||||
* @param Model $object_model
|
||||
* @param array $fields_to_process
|
||||
* @param string $table_alias
|
||||
*
|
||||
* @return array|array[]
|
||||
*/
|
||||
protected function categorize_fields( $object_model, $fields_to_process, $table_alias ) {
|
||||
$categorized = array(
|
||||
'meta' => array(),
|
||||
'local' => array(),
|
||||
'global' => array(),
|
||||
);
|
||||
|
||||
foreach ( $fields_to_process as $field ) {
|
||||
if ( is_a( $field, Data_Object_From_Array_Token::class ) ) {
|
||||
$child_type = $field->object_type();
|
||||
|
||||
if ( ! $object_model->relationships()->has( $child_type ) ) {
|
||||
$error_string = sprintf( 'Attempting to access invalid related object %s for object type %s', $child_type, $object_model->type() );
|
||||
throw new InvalidArgumentException( $error_string, 455 );
|
||||
}
|
||||
|
||||
$categorized['local'][ $field->alias() ] = $field;
|
||||
continue;
|
||||
}
|
||||
|
||||
$field_name = $field->name();
|
||||
|
||||
if ( ! in_array( $field_name, $this->global_fields ) && ! array_key_exists( $field_name, $object_model->fields() ) && ! array_key_exists( $field_name, $object_model->meta_fields() ) ) {
|
||||
$error_string = sprintf( 'Attempting to access invalid field %s on object type %s', $field_name, $object_model->type() );
|
||||
throw new InvalidArgumentException( $error_string, 450 );
|
||||
}
|
||||
|
||||
$alias = $field->alias();
|
||||
$identifier = $alias ? $alias : $field_name;
|
||||
|
||||
if ( in_array( $field_name, $this->global_fields ) ) {
|
||||
$categorized['global'][ $field_name ] = $identifier;
|
||||
}
|
||||
|
||||
if ( array_key_exists( $field_name, $object_model->fields() ) ) {
|
||||
$categorized['local'][ $identifier . '.' . $field_name ] = $identifier;
|
||||
}
|
||||
|
||||
if ( array_key_exists( $field_name, $object_model->meta_fields() ) ) {
|
||||
$categorized['meta'][ $field_name ] = array(
|
||||
'alias' => $identifier,
|
||||
'lookup_table_alias' => sprintf( 'meta_%s_%s', $table_alias, $identifier ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $categorized;
|
||||
}
|
||||
|
||||
/**
|
||||
* From the given array of $field_names, build the properly-structured SQL for selecting them.
|
||||
*
|
||||
* If a field is detected as a related object, we treat it as a top-level query and recursively
|
||||
* begin the SQL generation process for it.
|
||||
*
|
||||
* @param array $field_names
|
||||
* @param string $table_alias
|
||||
* @param string $object_type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function build_local_field_select_clauses( $field_names, $table_alias, $object_type ) {
|
||||
$pairs = array();
|
||||
|
||||
foreach ( $field_names as $field_name => $alias ) {
|
||||
if ( is_a( $alias, Data_Object_From_Array_Token::class ) ) {
|
||||
$value = '(' . $this->recursively_generate_sql( $alias, $field_name, $table_alias, $object_type ) . ')';
|
||||
$pairs[] = sprintf( '"%s", %s', $field_name, $value );
|
||||
continue;
|
||||
}
|
||||
|
||||
$pairs[] = sprintf( '"%s", %s.%s', $alias, $table_alias, $field_name );
|
||||
}
|
||||
|
||||
return $pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the appropriate SQL clause(s) for selecting a Meta field. Meta fields exist in a lookup table, and thus require both a SELECT statement to properly
|
||||
* query the fields as well as a JOIN clause to join the meta table with a specific alias.
|
||||
*
|
||||
* @param string $meta_name the name of the field being selected
|
||||
* @param string $alias the alias to use when returning the selected field
|
||||
* @param string $object_type the object type to grab the values from
|
||||
* @param string $parent_table_alias if present, the parent table this nested query belongs to
|
||||
* @param string $idx_prefix If present, the previous IDX prefix used for the parent table.
|
||||
* (to be prenended to this table's alias)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function build_meta_query( $meta_name, $alias, $object_type, $parent_table_alias, $idx_prefix ) {
|
||||
global $wpdb;
|
||||
|
||||
$meta_table_name = $wpdb->prefix . $this->db_namespace . '_' . 'meta';
|
||||
$meta_table_alias = sprintf( 'meta_%s%s', $meta_name, is_null( $idx_prefix ) ? null : '_' . $idx_prefix );
|
||||
|
||||
$select_clause = sprintf(
|
||||
'"%1$s", %2$s.meta_value',
|
||||
$alias,
|
||||
$meta_table_alias
|
||||
);
|
||||
|
||||
$join_clause = sprintf(
|
||||
'LEFT JOIN %1$s AS %2$s ON %3$s.object_id = %4$s.id AND %5$s.object_type = "%6$s" AND %7$s.meta_name = "%8$s"',
|
||||
$meta_table_name,
|
||||
$meta_table_alias,
|
||||
$meta_table_alias,
|
||||
$parent_table_alias,
|
||||
$meta_table_alias,
|
||||
$object_type,
|
||||
$meta_table_alias,
|
||||
$meta_name
|
||||
);
|
||||
|
||||
return array(
|
||||
'select_clause' => $select_clause,
|
||||
'join_clause' => $join_clause,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a SQL WHERE clause from the given set of conditions.
|
||||
*
|
||||
* @param array $conditions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function build_where_clauses( $conditions ) {
|
||||
$clauses = array();
|
||||
|
||||
foreach ( $conditions as $condition ) {
|
||||
$column_name = $condition['key'];
|
||||
$column_value = $condition['value'];
|
||||
$comparator = $condition['comparator'];
|
||||
|
||||
$clauses[] = sprintf( '%1$s %2$s %3$s', $column_name, $comparator, $column_value );
|
||||
}
|
||||
|
||||
return $clauses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose the proper table name for a given object type.
|
||||
*
|
||||
* @param string $object_type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function compose_table_name( $object_type ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $this->models->has( $object_type ) || ! $this->models->get( $object_type )->forced_table_name() ) {
|
||||
return sprintf( '%s%s_%s', $wpdb->prefix, $this->db_namespace, $object_type );
|
||||
}
|
||||
|
||||
$object_model = $this->models->get( $object_type );
|
||||
|
||||
return sprintf( '%s%s', $wpdb->prefix, $object_model->forced_table_name() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose the appropriate join table name for a given suffix.
|
||||
*
|
||||
* @param string $suffix
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function compose_join_table_name( $suffix ) {
|
||||
global $wpdb;
|
||||
|
||||
return sprintf( '%s%s_%s', $wpdb->prefix, $this->db_namespace, $suffix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes a table alias to ensure every table has a unique name in the query.
|
||||
*
|
||||
* @param string $object_name
|
||||
* @param string $parent_table_name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function compose_table_alias( $object_name, $parent_table_name = false ) {
|
||||
if ( ! empty( $parent_table_name ) ) {
|
||||
return sprintf( '%s_%s', $parent_table_name, $object_name );
|
||||
}
|
||||
|
||||
return sprintf( 'table_%s', $object_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search an array of arguments and return the appropriate SQL LIMIT clause from
|
||||
* the values.
|
||||
*
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_limit_from_arguments( $arguments ) {
|
||||
$response = '';
|
||||
|
||||
$limit = array_values(
|
||||
array_filter(
|
||||
$arguments,
|
||||
function ( $item ) {
|
||||
return $item['key'] === 'limit';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$offset = array_values(
|
||||
array_filter(
|
||||
$arguments,
|
||||
function ( $item ) {
|
||||
return $item['key'] === 'offset';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! empty( $limit ) ) {
|
||||
$response .= sprintf( 'LIMIT %s', $limit[0]['value'] );
|
||||
}
|
||||
|
||||
if ( ! empty( $offset ) ) {
|
||||
$response .= sprintf( ' OFFSET %s', $offset[0]['value'] );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function get_order_from_arguments( $arguments, $table_alias ) {
|
||||
$response = '';
|
||||
|
||||
$order = array_values(
|
||||
array_filter(
|
||||
$arguments,
|
||||
function ( $item ) {
|
||||
return $item['key'] === 'order';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$order_by = array_values(
|
||||
array_filter(
|
||||
$arguments,
|
||||
function ( $item ) {
|
||||
return $item['key'] === 'orderBy';
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
if ( empty( $order_by ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( empty( $order ) ) {
|
||||
$order = array( array( 'value' => 'DESC' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows third-parties to modify the ORDER parameter before being applied.
|
||||
*
|
||||
* @param string The current order direction.
|
||||
* @param array The arguments for this query.
|
||||
*
|
||||
* @return string (either DESC or ASC)
|
||||
*/
|
||||
$order = apply_filters( 'gt_hermes_order_dir', $order[0]['value'], $arguments );
|
||||
|
||||
/**
|
||||
* Allows third-parties to modify the ORDER BY parameter before being applied.
|
||||
*
|
||||
* @param string The current ORDER BY value.
|
||||
* @param array The arguments for this query.
|
||||
*
|
||||
* @return string The new ORDER BY value.
|
||||
*/
|
||||
$order_by = apply_filters( 'gt_hermes_order_value', $order_by[0]['value'], $arguments );
|
||||
|
||||
if ( empty( $order_by ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$response = sprintf( 'ORDER BY %s.%s %s', $table_alias, $order_by, $order );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function recursively_get_model_relationships( Model $object_model ) {
|
||||
$map = array();
|
||||
|
||||
foreach ( $object_model->relationships()->all() as $relationship ) {
|
||||
if ( ! $relationship->has_access() || $relationship->is_reverse() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_object_model = $this->models->get( $relationship->to() );
|
||||
|
||||
$children = $this->recursively_get_model_relationships( $new_object_model );
|
||||
|
||||
$map[ $new_object_model->type() ] = $children;
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
private function recursively_order_relationship_map( $parent_relationships, $relationship_map ) {
|
||||
$data = array();
|
||||
|
||||
foreach ( $relationship_map as $key => $value ) {
|
||||
$model = $this->models->get( $key );
|
||||
$searchable_fields = $model->searchable_fields();
|
||||
$children = array();
|
||||
|
||||
if ( ! empty( $value ) ) {
|
||||
$child_parent_relationships = $parent_relationships;
|
||||
$child_parent_relationships[] = $key;
|
||||
$children = $this->recursively_order_relationship_map( $child_parent_relationships, $value );
|
||||
}
|
||||
|
||||
$data[ $key ] = array(
|
||||
'parent_relationships' => $parent_relationships,
|
||||
'searchable_fields' => $searchable_fields,
|
||||
'children' => $children,
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function recursively_get_ids_from_relationship_map( &$ids, $search_term, $relationship_map ) {
|
||||
foreach ( $relationship_map as $object_type => $values ) {
|
||||
// Nothing to search for, bail.
|
||||
if ( empty( $values['searchable_fields'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$wpdb_prefix = $wpdb->prefix;
|
||||
$db_namespace = $this->db_namespace;
|
||||
$table_name = sprintf( '%s%s_%s', $wpdb_prefix, $db_namespace, $object_type );
|
||||
$parent_relationships = array_reverse( $values['parent_relationships'] );
|
||||
|
||||
$id_table_alias = $this->get_proper_related_table_id_for_search( $values['parent_relationships'], $object_type );
|
||||
$id_column_alias = $this->get_proper_related_column_alias_for_search( $values['parent_relationships'], $id_table_alias, $object_type );
|
||||
$select_clause = sprintf( 'SELECT %s AS id FROM %s AS mt', $id_column_alias, $table_name );
|
||||
|
||||
$match_statements = array_map( function ( $field_name ) use ( $search_term ) {
|
||||
return sprintf( 'MATCH( mt.%s ) AGAINST( "%s*" IN BOOLEAN MODE )', $field_name, $search_term );
|
||||
}, $values['searchable_fields'] );
|
||||
|
||||
$models = $this->models;
|
||||
|
||||
$join_statements = array_map( function ( $related_type, $idx ) use ( $object_type, $db_namespace, $wpdb_prefix, $parent_relationships, $models ) {
|
||||
$object_model = $models->get( $object_type );
|
||||
$relationship = $object_model->relationships()->get( $related_type );
|
||||
if ( ! $relationship || $relationship->relationship_type() === 'one_to_many' ) {
|
||||
return null;
|
||||
}
|
||||
$joined_type = $idx === 0 ? $object_type : $parent_relationships[ $idx - 1 ];
|
||||
$joined_table_alias = $idx === 0 ? 'mt' : sprintf( 'pt%s', $idx );
|
||||
$joined_table_column = $idx === 0 ? 'id' : sprintf( '%s_id', $parent_relationships[ $idx - 1 ] );
|
||||
$join_table_name = sprintf( '%s%s_%s_%s', $wpdb_prefix, $db_namespace, $related_type, $joined_type );
|
||||
|
||||
return sprintf( 'LEFT JOIN %s AS pt%s ON pt%s.%s_id = %s.%s', $join_table_name, $idx + 1, $idx + 1, $joined_type, $joined_table_alias, $joined_table_column );
|
||||
}, $parent_relationships, array_keys( $parent_relationships ) );
|
||||
|
||||
$join_statements = array_filter( $join_statements );
|
||||
|
||||
$sql = sprintf( '%s %s WHERE %s', $select_clause, implode( ' ', $join_statements ), implode( ' OR ', $match_statements ) );
|
||||
$results = $wpdb->get_results( $sql, ARRAY_A );
|
||||
$result_ids = wp_list_pluck( $results, 'id' );
|
||||
|
||||
$ids[] = $result_ids;
|
||||
|
||||
if ( ! empty( $values['children'] ) ) {
|
||||
$this->recursively_get_ids_from_relationship_map( $ids, $search_term, $values['children'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_proper_related_table_id_for_search( $parent_relationships, $object_type ) {
|
||||
if ( empty( $parent_relationships ) ) {
|
||||
return 'id';
|
||||
}
|
||||
|
||||
$related_type = $parent_relationships[ array_key_last( $parent_relationships ) ];
|
||||
$object_model = $this->models->get( $object_type );
|
||||
$relationship = $object_model->relationships()->get( $related_type );
|
||||
|
||||
if ( $relationship->relationship_type() === 'one_to_many' ) {
|
||||
return 'mt';
|
||||
}
|
||||
|
||||
return sprintf( 'pt%s', count( $parent_relationships ) );
|
||||
}
|
||||
|
||||
private function get_proper_related_column_alias_for_search( $parent_relationships, $id_table_alias, $object_type ) {
|
||||
if ( empty( $parent_relationships ) ) {
|
||||
return 'id';
|
||||
}
|
||||
|
||||
$related_type = $parent_relationships[ array_key_last( $parent_relationships ) ];
|
||||
$object_model = $this->models->get( $object_type );
|
||||
|
||||
$relationship = $object_model->relationships()->get( $related_type );
|
||||
|
||||
if ( $relationship->relationship_type() === 'one_to_many' ) {
|
||||
return sprintf( '%s.%sId', $id_table_alias, $related_type );
|
||||
}
|
||||
|
||||
return sprintf( '%s.%s_id', $id_table_alias, $parent_relationships[0] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IDs for a search term from child objects.
|
||||
*
|
||||
* @param string $search_term
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_aggregate_ids_for_search( $search_term, Model $parent_object_model ) {
|
||||
$relationship_map = array();
|
||||
$relationship_map[ $parent_object_model->type() ] = $this->recursively_get_model_relationships( $parent_object_model );
|
||||
$relationship_map = $this->recursively_order_relationship_map( array(), $relationship_map );
|
||||
$ids = array();
|
||||
|
||||
// $ids passed as reference, so it gets updated with values here.
|
||||
$this->recursively_get_ids_from_relationship_map( $ids, $search_term, $relationship_map );
|
||||
|
||||
$all_ids = array();
|
||||
|
||||
// flatten the multi-level $ids array into a single array of values
|
||||
foreach( $ids as $id_set ) {
|
||||
$all_ids = array_merge( $all_ids, $id_set );
|
||||
}
|
||||
|
||||
// get rid of dupes
|
||||
$all_ids = array_unique( $all_ids );
|
||||
|
||||
// remove empty values
|
||||
return array_filter( $all_ids );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search an array of arguments and compose the appropriate WHERE clause for the values provided.
|
||||
*
|
||||
* @param array $where_clauses
|
||||
* @param string $table_alias
|
||||
* @param array $arguments
|
||||
* @param Model $object_model
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function get_where_clauses_from_arguments( &$where_clauses, $table_alias, $arguments, $object_model ) {
|
||||
foreach ( $arguments as $argument ) {
|
||||
if ( $argument['key'] === 'order' || $argument['key'] === 'orderBy' || $argument['key'] === 'limit' || $argument['key'] === 'offset' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $argument['key'] === 'search' ) {
|
||||
// If a search is present, we need to do some work to get an aggregate based on all the searchable fields.
|
||||
$ids = $this->get_aggregate_ids_for_search( $argument['value'], $object_model );
|
||||
|
||||
// Set the IDs to a single array value of 0 to ensure empty results are returned. (a blank IN statement throws SQL errors).
|
||||
if ( empty( $ids ) ) {
|
||||
$ids = array( 0 );
|
||||
}
|
||||
|
||||
$where_clauses[] = sprintf( '%s.%s IN (%s)', $table_alias, 'id', implode( ', ', $ids ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $argument['comparator'] === 'in' ) {
|
||||
$in_vals = is_array( $argument['value'] ) ? $argument['value'] : explode( '|', $argument['value'] );
|
||||
|
||||
foreach ( $in_vals as $key => $value ) {
|
||||
$in_vals[ $key ] = sprintf( '"%s"', $value );
|
||||
}
|
||||
$in_string = implode( ', ', $in_vals );
|
||||
$clause = sprintf( '%s.%s IN (%s)', $table_alias, $argument['key'], $in_string );
|
||||
$where_clauses[] = $clause;
|
||||
continue;
|
||||
}
|
||||
|
||||
$clause = sprintf( '%s.%s %s "%s"', $table_alias, $argument['key'], $argument['comparator'], $argument['value'] );
|
||||
$where_clauses[] = $clause;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse the Query Object and gather all the transformation arguments into a hierarchical array which can
|
||||
* be used to modify the actual data from the database.
|
||||
*
|
||||
* @param array $transformations
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function recursively_get_transformations( Data_Object_From_Array_Token $data, $transformations = array() ) {
|
||||
foreach ( $data->fields() as $field ) {
|
||||
if ( is_a( $field, Data_Object_From_Array_Token::class ) ) {
|
||||
$this_alias = ! empty( $field->alias() ) ? $field->alias() : $field->object_type();
|
||||
$transformations[ $this_alias ] = $this->recursively_get_transformations( $field, array() );
|
||||
continue;
|
||||
}
|
||||
|
||||
$arguments = $field->arguments( false );
|
||||
|
||||
if ( empty( $arguments ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$transformations[ $field->alias() ] = array(
|
||||
'items' => array(),
|
||||
);
|
||||
|
||||
foreach ( $arguments->items() as $argument ) {
|
||||
if ( strpos( $argument['key'], 'transform' ) !== false ) {
|
||||
$transformations[ $field->alias() ]['items'][ $argument['key'] ] = array(
|
||||
'key' => $argument['key'],
|
||||
'value' => $argument['value'],
|
||||
'object_type' => $data->object_type(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $transformations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse all of the data rows (and the corresponding array of transformations gathered previously) and apply
|
||||
* the transformations to the data.
|
||||
*
|
||||
* @param array $rows
|
||||
* @param array $transformations
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function recursively_apply_transformations( $rows, $transformations ) {
|
||||
foreach ( $rows as $idx => $row ) {
|
||||
foreach ( $row as $key => $value ) {
|
||||
if ( ! array_key_exists( $key, $transformations ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$local_transformations = $transformations[ $key ];
|
||||
|
||||
if ( is_array( $value ) ) {
|
||||
$rows[ $idx ][ $key ] = $this->recursively_apply_transformations( $value, $local_transformations );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( empty( $local_transformations['items'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $local_transformations['items'] as $transformation_name => $transformation_values ) {
|
||||
$object_model = $this->models->get( $transformation_values['object_type'] );
|
||||
$rows[ $idx ][ $key ] = $object_model->handle_transformation( $transformation_name, $transformation_values['value'], $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function get_schema_values_for_query( $object ) {
|
||||
$schema = $this->schema_runner->run( $object );
|
||||
|
||||
return array(
|
||||
'schema' => $schema,
|
||||
'transformations' => array(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Vendored
+244
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\License;
|
||||
|
||||
/**
|
||||
* Class API_Response
|
||||
*
|
||||
* An abstracted Response class used to standardize the responses we send back from an API Connector. Includes
|
||||
* standardized serialization and JSON methods to support saving the class to the Database.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Tools\License
|
||||
*/
|
||||
abstract class API_Response implements \JsonSerializable, \Serializable {
|
||||
|
||||
/**
|
||||
* The data for this response.
|
||||
*
|
||||
* @var array $data
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* The status for this response.
|
||||
*
|
||||
* @var array $status
|
||||
*/
|
||||
protected $status = array();
|
||||
|
||||
/**
|
||||
* The errors (if any) for this response.
|
||||
*
|
||||
* @var array $errors
|
||||
*/
|
||||
protected $errors = array();
|
||||
|
||||
/**
|
||||
* The meta data (if any) for this response.
|
||||
*
|
||||
* @var array $meta
|
||||
*/
|
||||
protected $meta = array();
|
||||
|
||||
/**
|
||||
* Set the status for the response.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $status
|
||||
*/
|
||||
protected function set_status( $status ) {
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data item.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $item
|
||||
*/
|
||||
protected function add_data_item( $item ) {
|
||||
$this->data[] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error message.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $error_message
|
||||
*/
|
||||
protected function add_error( $error_message ) {
|
||||
$this->errors[] = $error_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a meta item to the response.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $key
|
||||
* @param $value
|
||||
*/
|
||||
protected function add_meta_item( $key, $value ) {
|
||||
$this->meta[ $key ] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for this response
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_data() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any errors on this response.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_errors() {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response status.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_status() {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response meta.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_meta() {
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the response has any errors.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_errors() {
|
||||
return ! empty( $this->errors );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific piece of the data.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $name
|
||||
* @param int $index
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get_data_value( $name, $index = 0 ) {
|
||||
if ( ! isset( $this->data[ $index ][ $name ] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->data[ $index ][ $name ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Standardization of the class when serialized and unserialized. Useful for standardizing how it
|
||||
* is stored in the Database.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize() {
|
||||
return serialize( $this->__serialize() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the object for serializing.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __serialize() {
|
||||
return array(
|
||||
'data' => $this->data,
|
||||
'errors' => $this->errors,
|
||||
'status' => $this->status,
|
||||
'meta' => $this->meta,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate the Response data when unserializing.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $serialized
|
||||
*/
|
||||
public function unserialize( $serialized ) {
|
||||
$this->__unserialize( unserialize( $serialized ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates the object when unserializing.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param array $data The unserialized data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __unserialize( $data ) {
|
||||
$this->data = $data['data'];
|
||||
$this->errors = $data['errors'];
|
||||
$this->status = $data['status'];
|
||||
$this->meta = $data['meta'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process data for JSON Encoding.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize() {
|
||||
|
||||
$response = array();
|
||||
|
||||
$response['status'] = $this->status;
|
||||
$response['meta'] = $this->meta;
|
||||
|
||||
if ( empty( $this->errors ) ) {
|
||||
$response['data'] = $this->data;
|
||||
}
|
||||
|
||||
if ( ! empty( $this->errors ) ) {
|
||||
$response['errors'] = $this->errors;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\License;
|
||||
|
||||
use GFCommon;
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
use WP_Error;
|
||||
use Gravity_Forms\Gravity_Tools\License\License_API_Response_Factory;
|
||||
|
||||
/**
|
||||
* Class License_API_Connector
|
||||
*
|
||||
* Connector providing methods to communicate with the License API.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Tools\License
|
||||
*/
|
||||
class License_API_Connector {
|
||||
|
||||
private static $plugins;
|
||||
|
||||
private static $license_info;
|
||||
|
||||
/**
|
||||
* @var \Gravity_Api $strategy
|
||||
*/
|
||||
protected $strategy;
|
||||
|
||||
/**
|
||||
* @var \GFCache $cache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var License_API_Response_Factory $response_factory
|
||||
*/
|
||||
protected $response_factory;
|
||||
|
||||
/**
|
||||
* @var Common
|
||||
*/
|
||||
protected $common;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace;
|
||||
|
||||
public function __construct( $strategy, $cache, License_API_Response_Factory $response_factory, $common, $namespace ) {
|
||||
$this->strategy = $strategy;
|
||||
$this->cache = $cache;
|
||||
$this->response_factory = $response_factory;
|
||||
$this->common = $common;
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cache debug is enabled.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_debug() {
|
||||
return defined( 'GF_CACHE_DEBUG' ) && GF_CACHE_DEBUG;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the site was registered with the legacy process.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_legacy_registration() {
|
||||
return $this->strategy->is_legacy_registration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache for a given key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
public function clear_cache_for_key( $key ) {
|
||||
$this->cache->delete( 'rg_gforms_license_info_' . $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license info.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $key
|
||||
* @param bool $cache
|
||||
*
|
||||
* @return License_API_Response
|
||||
*/
|
||||
public function check_license( $key = false, $cache = true ) {
|
||||
$license_info = false;
|
||||
$key = $key ? trim( $key ) : $this->strategy->get_key();
|
||||
$license_info_data = $this->cache->get( 'rg_gf_license_info_' . $key );
|
||||
|
||||
if ( $this->is_debug() ) {
|
||||
$cache = false;
|
||||
}
|
||||
|
||||
if ( $license_info_data && $cache ) {
|
||||
$license_info = $this->common->safe_unserialize( $license_info_data, License_API_Response::class );
|
||||
if ( $license_info ) {
|
||||
return $license_info;
|
||||
} else {
|
||||
$this->clear_cache_for_key( $key );
|
||||
}
|
||||
}
|
||||
|
||||
$license_info = $this->response_factory->create(
|
||||
$this->strategy->check_license( $key ),
|
||||
false
|
||||
);
|
||||
|
||||
if ( $license_info->can_be_used() ) {
|
||||
$this->cache->set( 'rg_gf_license_info_' . $key, serialize( $license_info ), true, DAY_IN_SECONDS );
|
||||
}
|
||||
|
||||
return $license_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license and plugins information.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param bool $cache If we should use the cached data.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_version_info( $cache = true ) {
|
||||
if ( ! is_null( self::$plugins ) && $cache ) {
|
||||
$plugins = self::$plugins;
|
||||
$license_info = self::$license_info;
|
||||
} else {
|
||||
$plugins = $this->get_plugins( $cache );
|
||||
$license_info = $this->common->get_key() ? $this->check_license( false, $cache ) : new WP_Error( License_Statuses::NO_DATA );
|
||||
self::$plugins = $plugins;
|
||||
self::$license_info = $license_info;
|
||||
}
|
||||
|
||||
return array(
|
||||
'is_valid_key' => ! is_wp_error( $license_info ) && $license_info->can_be_used(),
|
||||
'reason' => $license_info->get_error_message(),
|
||||
'version' => $this->common->rgars( $plugins, 'gravityforms/version' ),
|
||||
'url' => $this->common->rgars( $plugins, 'gravityforms/url' ),
|
||||
'is_error' => is_wp_error( $license_info ) || $license_info->has_errors(),
|
||||
'offerings' => $plugins,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the saved license key is valid.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
public function is_valid_license() {
|
||||
$license_info = $this->check_license();
|
||||
|
||||
return $license_info->is_valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a site to the specified key, or if $new_key is blank, unlinks a key from an existing site.
|
||||
* Requires that the $new_key is saved in options before calling this function
|
||||
*
|
||||
* @since 1.0 Implement the license enforcement process.
|
||||
*
|
||||
* @param string $new_key Unhashed Gravity Forms license key.
|
||||
*
|
||||
* @return GF_License_API_Response
|
||||
*/
|
||||
public function update_site_registration( $new_key, $is_md5 = false ) {
|
||||
// Get new license key information.
|
||||
$version_info = $this->common->get_version_info( false );
|
||||
|
||||
if ( $version_info['is_valid_key'] ) {
|
||||
$data = $this->strategy->check_license( $new_key );
|
||||
|
||||
$result = $this->response_factory->create( $data );
|
||||
} else {
|
||||
|
||||
// Invalid key, do not change site registration.
|
||||
$error = new WP_Error( License_Statuses::INVALID_LICENSE_KEY, License_Statuses::get_message_for_code( License_Statuses::INVALID_LICENSE_KEY ) );
|
||||
|
||||
$result = $this->response_factory->create( $error );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge site credentials if the license info contains certain errors.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_purge_site_credentials() {
|
||||
|
||||
// Check if the license info contains the revoke site error.
|
||||
$license_info = $this->check_license();
|
||||
|
||||
$errors = array(
|
||||
'gravityapi_site_revoked',
|
||||
'gravityapi_fail_authentication',
|
||||
'gravityapi_site_url_changed',
|
||||
);
|
||||
|
||||
if ( is_wp_error( $license_info ) && in_array( $license_info->get_error_code(), $errors, true ) ) {
|
||||
// Purge site data to ensure we can get a fresh start.
|
||||
$this->strategy->purge_site_credentials();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of plugins from the API.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param bool $cache Whether to respect the cached data.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_plugins( $cache = true ) {
|
||||
$cache_key = sprintf( '%s_gforms_plugins', $this->namespace );
|
||||
$plugins = $this->cache->get( $cache_key, $found_in_cache );
|
||||
|
||||
if ( $this->is_debug() ) {
|
||||
$cache = false;
|
||||
}
|
||||
|
||||
if ( $found_in_cache && $cache ) {
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
$plugins = $this->strategy->get_plugins_info();
|
||||
|
||||
$this->cache->set( $cache_key, $plugins, true, DAY_IN_SECONDS );
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\License;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\License\License_API_Response;
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
|
||||
/**
|
||||
* Class License_API_Response_Factory
|
||||
*
|
||||
* Concrete response factory used to return a License API Response
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Tools\License
|
||||
*/
|
||||
class License_API_Response_Factory {
|
||||
|
||||
private $transient_strategy;
|
||||
|
||||
/**
|
||||
* @var Common
|
||||
*/
|
||||
protected $common;
|
||||
|
||||
/**
|
||||
* License_API_Response_Factory constructor
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $transient_strategy
|
||||
*/
|
||||
public function __construct( $transient_strategy, $common ) {
|
||||
$this->transient_strategy = $transient_strategy;
|
||||
$this->common = $common;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new License API Response from the given data.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed ...$args
|
||||
*
|
||||
* @return GF_License_API_Response
|
||||
*/
|
||||
public function create( ...$args ) {
|
||||
$data = $args[0];
|
||||
$validate = isset( $args[1] ) ? $args[1] : true;
|
||||
|
||||
return new License_API_Response( $data, $validate, $this->transient_strategy, $this->common );
|
||||
}
|
||||
|
||||
}
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\License;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Data\Transient_Strategy;
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
|
||||
/**
|
||||
* Class License_API_Response
|
||||
*
|
||||
* Concrete Response class for the GF License API.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Forms\License
|
||||
*/
|
||||
class License_API_Response extends API_Response {
|
||||
|
||||
/**
|
||||
* @var Transient_Strategy
|
||||
*/
|
||||
private $transient_strategy;
|
||||
|
||||
/**
|
||||
* @var Common
|
||||
*/
|
||||
protected $common;
|
||||
|
||||
/**
|
||||
* License_API_Response constructor.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $data The data from the API connector.
|
||||
* @param bool $validate Whether to validate the data passed.
|
||||
* @param Transient_Strategy $transient_strategy The Transient Strategy used to store things in transients.
|
||||
*/
|
||||
public function __construct( $data, $validate, Transient_Strategy $transient_strategy, $common ) {
|
||||
$this->transient_strategy = $transient_strategy;
|
||||
$this->common = $common;
|
||||
|
||||
// Data is a wp_error, parse it to get the correct code and message.
|
||||
if ( is_wp_error( $data ) ) {
|
||||
/**
|
||||
* @var \WP_Error $data
|
||||
*/
|
||||
if ( $data->get_error_code() == 'rest_invalid_param' ) {
|
||||
$this->set_status( License_Statuses::INVALID_LICENSE_KEY );
|
||||
$this->add_error( __( 'The license is invalid.', 'gravityforms' ) );
|
||||
} else {
|
||||
$this->set_status( $data->get_error_code() );
|
||||
$this->add_error( $data->get_error_message() );
|
||||
}
|
||||
|
||||
if ( empty( $data->get_error_data() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$error_data = $data->get_error_data();
|
||||
|
||||
if ( $this->common->rgar( $error_data, 'license' ) ) {
|
||||
$error_data = $this->common->rgar( $error_data, 'license' );
|
||||
}
|
||||
|
||||
$this->add_data_item( $error_data );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Data is somehow broken; set a status for Invalid license keys and bail.
|
||||
if ( ! is_array( $data ) ) {
|
||||
$this->set_status( License_Statuses::INVALID_LICENSE_KEY );
|
||||
$this->add_error( License_Statuses::get_message_for_code( License_Statuses::INVALID_LICENSE_KEY ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set is_valid to true since we are bypassing validation.
|
||||
if ( ! $validate ) {
|
||||
$data['is_valid'] = true;
|
||||
}
|
||||
|
||||
// Data is formatted properly, but the `is_valid` param is false. Return an invalid license key error.
|
||||
if ( isset( $data['is_valid'] ) && ! $data['is_valid'] ) {
|
||||
$this->set_status( License_Statuses::INVALID_LICENSE_KEY );
|
||||
$this->add_error( License_Statuses::get_message_for_code( License_Statuses::INVALID_LICENSE_KEY ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally, the data is correct, so store it and set our status to valid.
|
||||
$this->add_data_item( $data );
|
||||
$this->set_status( License_Statuses::VALID_KEY );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored error for this site license.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return \WP_Error|false
|
||||
*/
|
||||
private function get_stored_error() {
|
||||
return $this->transient_strategy->get( 'rg_gforms_registration_error' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this license key is valid.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_valid() {
|
||||
if ( empty( $this->data ) || $this->get_status() === License_Statuses::NO_DATA ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->has_errors() ) {
|
||||
return (bool) $this->get_data_value( 'is_valid' );
|
||||
}
|
||||
|
||||
return $this->get_status() !== License_Statuses::INVALID_LICENSE_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error message for the response, either the first one by default, or at a specific index.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param int $index The array index to use if mulitple errors exist.
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function get_error_message( $index = 0 ) {
|
||||
if ( ! $this->has_errors() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->errors[ $index ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the human-readable display status for the response.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string|void
|
||||
*/
|
||||
public function get_display_status() {
|
||||
|
||||
if ( $this->max_seats_exceeded() ) {
|
||||
return __( 'Sites Exceeded', 'gravityforms' );
|
||||
}
|
||||
|
||||
switch ( $this->get_status() ) {
|
||||
case License_Statuses::INVALID_LICENSE_KEY:
|
||||
return __( 'Invalid', 'gravityforms' );
|
||||
case License_Statuses::EXPIRED_LICENSE_KEY:
|
||||
return __( 'Expired', 'gravityforms' );
|
||||
case License_Statuses::VALID_KEY:
|
||||
default:
|
||||
return __( 'Active', 'gravityforms' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Licenses can be valid and usable, technically-invalid but still usable, or invalid and unusable.
|
||||
* This will return the correct usability value for this license key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_usability() {
|
||||
if ( $this->get_status() === License_Statuses::VALID_KEY || $this->get_status() === License_Statuses::NO_DATA ) {
|
||||
return License_Statuses::USABILITY_VALID;
|
||||
}
|
||||
|
||||
if ( $this->get_status() === License_Statuses::INVALID_LICENSE_KEY || $this->get_status() === License_Statuses::SITE_REVOKED ) {
|
||||
return License_Statuses::USABILITY_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
return License_Statuses::USABILITY_ALLOWED;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
//---------- Helpers/Utils ---------------
|
||||
//----------------------------------------
|
||||
|
||||
/**
|
||||
* Whether this response has any errors stored as a transient.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function has_stored_error() {
|
||||
return (bool) $this->get_stored_error();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a properly-formatted link to the Upgrade page for this license key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_upgrade_link() {
|
||||
$key = $this->get_data_value( 'license_key_md5' );
|
||||
$type = $this->get_data_value( 'product_code' );
|
||||
|
||||
return sprintf( 'https://www.gravityforms.com/my-account/licenses/?action=upgrade&license_key=%s&license_code=%s&utm_source=gf-admin&utm_medium=upgrade-button&utm_campaign=license-enforcement', $key, $type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CTA information for this license key, if applicable.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_cta() {
|
||||
|
||||
if ( $this->get_status() == License_Statuses::EXPIRED_LICENSE_KEY ) {
|
||||
return array(
|
||||
'type' => 'button',
|
||||
'label' => __( 'Manage', 'gravityforms' ),
|
||||
'link' => 'https://www.gravityforms.com/my-account/licenses/?utm_source=gf-admin&utm_medium=manage-button&utm_campaign=license-enforcement',
|
||||
'class' => 'cog',
|
||||
);
|
||||
} elseif ( $this->max_seats_exceeded() ) {
|
||||
return array(
|
||||
'type' => 'button',
|
||||
'label' => __( 'Upgrade', 'gravityforms' ),
|
||||
'link' => $this->get_upgrade_link(),
|
||||
'class' => 'product',
|
||||
);
|
||||
} else if ( $this->has_expiration() ) {
|
||||
return array(
|
||||
'type' => 'text',
|
||||
'content' => $this->get_data_value( 'days_to_expire' ),
|
||||
);
|
||||
} else {
|
||||
return array(
|
||||
'type' => 'blank',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Some statuses are invalid, but get treated as usable. This determines if they should be displayed as
|
||||
* though they are valid.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function display_as_valid() {
|
||||
|
||||
if ( $this->max_seats_exceeded() ) {
|
||||
return false;
|
||||
}
|
||||
switch ( $this->get_status() ) {
|
||||
case License_Statuses::INVALID_LICENSE_KEY:
|
||||
case License_Statuses::EXPIRED_LICENSE_KEY:
|
||||
return false;
|
||||
case License_Statuses::VALID_KEY:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the license key can be used.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_be_used() {
|
||||
return $this->get_usability() !== License_Statuses::USABILITY_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the contained License Key has an expiration date.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_expiration() {
|
||||
return $this->get_data_value( 'date_expires' ) && ! $this->get_data_value( 'renewal_date' ) && ! $this->get_data_value( 'is_perpetual' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text for the renewal message.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function renewal_text() {
|
||||
if ( $this->get_status() === License_Statuses::EXPIRED_LICENSE_KEY ) {
|
||||
return __( 'Expired On', 'gravityforms' );
|
||||
}
|
||||
|
||||
$has_subscription = (bool) $this->get_data_value( 'renewal_date' );
|
||||
$cancelled = (bool) $this->get_data_value( 'is_subscription_canceled' );
|
||||
|
||||
if ( $has_subscription && ! $cancelled ) {
|
||||
return __( 'Renews On', 'gravityforms' );
|
||||
}
|
||||
|
||||
return __( 'Expires On', 'gravityforms' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the license renewal or expiry date or the doesn't expire message.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string|void
|
||||
*/
|
||||
public function renewal_date() {
|
||||
if ( $this->get_data_value( 'is_perpetual' ) ) {
|
||||
return __( 'Does not expire', 'gravityforms' );
|
||||
}
|
||||
|
||||
$date = $this->get_data_value( 'renewal_date' );
|
||||
if ( empty( $date ) ) {
|
||||
$date = $this->get_data_value( 'date_expires' );
|
||||
}
|
||||
|
||||
return gmdate( 'M d, Y', strtotime( $date ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the license has max seats exceeded.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function max_seats_exceeded() {
|
||||
return $this->get_status() === License_Statuses::MAX_SITES_EXCEEDED || $this->get_data_value( 'remaining_seats' ) < 0;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
//---------- Serialization ---------------
|
||||
//----------------------------------------
|
||||
|
||||
/**
|
||||
* Prepares the object for serializing.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __serialize() {
|
||||
return array(
|
||||
'data' => $this->data,
|
||||
'errors' => $this->errors,
|
||||
'status' => $this->status,
|
||||
'meta' => $this->meta,
|
||||
'strat' => $this->transient_strategy,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates the object when unserializing.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param array $data The unserialized data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __unserialize( $data ) {
|
||||
$this->data = $data['data'];
|
||||
$this->errors = $data['errors'];
|
||||
$this->status = $data['status'];
|
||||
$this->meta = $data['meta'];
|
||||
$this->transient_strategy = $data['strat'];
|
||||
}
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\License;
|
||||
|
||||
/**
|
||||
* Class License_Statuses
|
||||
*
|
||||
* Helper class to provide license statuse codes and messages.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Tools\Utils
|
||||
*/
|
||||
class License_Statuses {
|
||||
const VALID_KEY = 'valid_key';
|
||||
const SITE_UNREGISTERED = 'site_unregistered';
|
||||
const INVALID_LICENSE_KEY = 'gravityapi_invalid_license';
|
||||
const EXPIRED_LICENSE_KEY = 'gravityapi_expired_license';
|
||||
const SITE_REVOKED = 'gravityapi_site_revoked';
|
||||
const URL_CHANGED = 'gravityapi_site_url_changed';
|
||||
const MAX_SITES_EXCEEDED = 'gravityapi_exceeds_number_of_sites';
|
||||
const MULTISITE_NOT_ALLOWED = 'gravityapi_multisite_not_allowed';
|
||||
const NO_DATA = 'rest_no_route';
|
||||
|
||||
const USABILITY_VALID = 'success';
|
||||
const USABILITY_ALLOWED = 'warning';
|
||||
const USABILITY_NOT_ALLOWED = 'error';
|
||||
|
||||
/**
|
||||
* Get the correct Message for the given code.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $code
|
||||
*
|
||||
* @return mixed|string|void
|
||||
*/
|
||||
public static function get_message_for_code( $code ) {
|
||||
|
||||
$general_invalid_message = sprintf(
|
||||
/* translators: %1s and %2s are link tag markup */
|
||||
__( 'The license key entered is incorrect; please visit the %1$sGravity Forms website%2$s to verify your license.', 'gravityforms' ),
|
||||
'<a href="https://www.gravityforms.com/my-account/licenses/?utm_source=gf-admin&utm_medium=purchase-link&utm_campaign=license-enforcement" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
|
||||
$map = array(
|
||||
self::VALID_KEY => __( 'Your license key has been successfully validated.', 'gravityforms' ),
|
||||
self::SITE_REVOKED => sprintf(
|
||||
/* translators: %1s and %2s are link tag markup */
|
||||
__( 'The license key entered has been revoked; please check its status in your %1$sGravity Forms account.%2$s', 'gravityforms' ),
|
||||
'<a href="https://www.gravityforms.com/my-account/licenses/?utm_source=gf-admin&utm_medium=account-link-revoked&utm_campaign=license-enforcement" target="_blank">',
|
||||
'</a>'
|
||||
),
|
||||
self::MAX_SITES_EXCEEDED => __( 'This license key has already been activated on its maximum number of sites; please upgrade your license.', 'gravityforms' ),
|
||||
self::MULTISITE_NOT_ALLOWED => __( 'This license key does not support multisite installations. Please use a different license.', 'gravityforms' ),
|
||||
self::EXPIRED_LICENSE_KEY => sprintf(
|
||||
/* translators: %1s and %2s are link tag markup */
|
||||
__( 'This license key has expired; please visit your %1$sGravity Forms account%2$s to manage your license.', 'gravityforms' ),
|
||||
'<a href="https://www.gravityforms.com/my-account/licenses/?utm_source=gf-admin&utm_medium=account-link-expired&utm_campaign=license-enforcement" target="_blank">',
|
||||
'</a>'
|
||||
),
|
||||
self::SITE_UNREGISTERED => $general_invalid_message,
|
||||
self::INVALID_LICENSE_KEY => $general_invalid_message,
|
||||
self::URL_CHANGED => $general_invalid_message,
|
||||
);
|
||||
|
||||
return isset( $map[ $code ] ) ? $map[ $code ] : $general_invalid_message;
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Logging;
|
||||
|
||||
class DB_Logging_Provider implements Logging_Provider {
|
||||
|
||||
const DEBUG = 1;
|
||||
const INFO = 2;
|
||||
const WARN = 3;
|
||||
const ERROR = 4;
|
||||
const FATAL = 5;
|
||||
|
||||
private $timestamp_map = array(
|
||||
self::INFO => "- INFO -->",
|
||||
self::WARN => "- WARN -->",
|
||||
self::DEBUG => "- DEBUG -->",
|
||||
self::ERROR => "- ERROR -->",
|
||||
self::FATAL => "- FATAL -->",
|
||||
);
|
||||
|
||||
protected $model;
|
||||
|
||||
public function __construct( $model ) {
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
public function log_info( $line ) {
|
||||
$this->log( $line, self::INFO );
|
||||
}
|
||||
|
||||
public function log_debug( $line ) {
|
||||
$this->log( $line, self::DEBUG );
|
||||
}
|
||||
|
||||
public function log_warning( $line ) {
|
||||
$this->log( $line, self::WARN );
|
||||
}
|
||||
|
||||
public function log_error( $line ) {
|
||||
$this->log( $line, self::ERROR );
|
||||
}
|
||||
|
||||
public function log_fatal( $line ) {
|
||||
$this->log( $line, self::FATAL );
|
||||
}
|
||||
|
||||
public function log( $line, $priority ) {
|
||||
return $this->model->create( $line, $priority );
|
||||
}
|
||||
|
||||
public function write_line_to_log( $line ) {
|
||||
return $this->log_debug( $line );
|
||||
}
|
||||
|
||||
public function get_lines() {
|
||||
return $this->model->all( true );
|
||||
}
|
||||
|
||||
public function delete_log() {
|
||||
return $this->model->clear();
|
||||
}
|
||||
|
||||
}
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Logging;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Logging\Parsers\File_Log_Parser;
|
||||
|
||||
/**
|
||||
* File Logging Provider
|
||||
*
|
||||
* A logging provider which writes directly to a log file.
|
||||
*/
|
||||
class File_Logging_Provider implements Logging_Provider {
|
||||
const DEBUG = 1;
|
||||
const INFO = 2;
|
||||
const WARN = 3;
|
||||
const ERROR = 4;
|
||||
const FATAL = 5;
|
||||
const OFF = 6;
|
||||
|
||||
const LOG_OPEN = 1;
|
||||
const OPEN_FAILED = 2;
|
||||
const LOG_CLOSED = 3;
|
||||
|
||||
public $log_status = self::LOG_CLOSED;
|
||||
public $date_format = "Y-m-d G:i:s";
|
||||
public $message_queue;
|
||||
private $offset;
|
||||
private $log_file;
|
||||
private $priority = self::INFO;
|
||||
|
||||
private $file_handle;
|
||||
|
||||
private $timestamp_map = array(
|
||||
self::INFO => "- INFO -->",
|
||||
self::WARN => "- WARN -->",
|
||||
self::DEBUG => "- DEBUG -->",
|
||||
self::ERROR => "- ERROR -->",
|
||||
self::FATAL => "- FATAL -->",
|
||||
);
|
||||
|
||||
/**
|
||||
* @var File_Log_Parser
|
||||
*/
|
||||
private $line_parser;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $filepath
|
||||
* @param $priority
|
||||
* @param $offset
|
||||
*/
|
||||
public function __construct( $filepath, $priority, $offset = 0, File_Log_Parser $line_parser ) {
|
||||
if ( $priority == self::OFF ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->offset = $offset;
|
||||
$this->log_file = $filepath;
|
||||
$this->message_queue = array();
|
||||
$this->priority = $priority;
|
||||
$this->line_parser = $line_parser;
|
||||
|
||||
if ( file_exists( $this->log_file ) ) {
|
||||
if ( ! is_writable( $this->log_file ) ) {
|
||||
$this->log_status = self::OPEN_FAILED;
|
||||
$this->message_queue[] = __( "The file exists, but could not be opened for writing. Check that appropriate permissions have been set.", 'gravitytools' );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->file_handle = fopen( $this->log_file, "a" ) ) {
|
||||
$this->log_status = self::LOG_OPEN;
|
||||
$this->message_queue[] = __( "The log file was opened successfully.", 'gravitytools' );
|
||||
} else {
|
||||
$this->log_status = self::OPEN_FAILED;
|
||||
$this->message_queue[] = __( "The file could not be opened. Check permissions.", 'gravitytools' );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close file on destruct.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function __destruct() {
|
||||
if ( $this->file_handle ) {
|
||||
fclose( $this->file_handle );
|
||||
}
|
||||
}
|
||||
|
||||
public function get_log_file_path() {
|
||||
return $this->log_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add info line.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $line
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log_info( $line ) {
|
||||
$this->log( $line, self::INFO );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add debug line.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $line
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log_debug( $line ) {
|
||||
$this->log( $line, self::DEBUG );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add warning line.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $line
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log_warning( $line ) {
|
||||
$this->log( $line, self::WARN );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add error line.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $line
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log_error( $line ) {
|
||||
$this->log( $line, self::ERROR );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fatal line.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $line
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log_fatal( $line ) {
|
||||
$this->log( $line, self::FATAL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a log line with a defined priority.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $line
|
||||
* @param $priority
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log( $line, $priority ) {
|
||||
if ( $this->priority <= $priority ) {
|
||||
$status = $this->get_timeline( $priority );
|
||||
$this->write_line_to_log( "$status $line \n" );
|
||||
}
|
||||
}
|
||||
|
||||
public function delete_log() {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a line to the log.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $line
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function write_line_to_log( $line ) {
|
||||
if ( $this->log_status == self::LOG_OPEN && $this->priority != self::OFF ) {
|
||||
if ( fwrite( $this->file_handle, $line ) === false ) {
|
||||
$this->message_queue[] = __( "The file could not be written to. Check that appropriate permissions have been set.", 'gravitytools' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function get_lines() {
|
||||
$contents = file_get_contents( $this->get_log_file_path() );
|
||||
|
||||
return $this->line_parser->parse_log( $contents );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeline tet for a given log type.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $level
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_timeline( $level ) {
|
||||
|
||||
if ( class_exists( 'DateTime' ) ) {
|
||||
$original_time = microtime( true ) + $this->offset;
|
||||
$microtime = sprintf( '%06d', ( $original_time - floor( $original_time ) ) * 1000000 );
|
||||
$date = new \DateTime( date( 'Y-m-d H:i:s.' . $microtime, (int) $original_time ) );
|
||||
$time = $date->format( $this->date_format );
|
||||
|
||||
} else {
|
||||
$time = gmdate( $this->date_format, time() + $this->offset );
|
||||
}
|
||||
|
||||
return $this->get_formatted_timeline_for_type( $level, $time );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted timeline text for a given type.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $type
|
||||
* @param $time
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_formatted_timeline_for_type( $type, $time ) {
|
||||
return sprintf( '[**] %s %s', $time, $this->timestamp_map[ $type ] );
|
||||
}
|
||||
}
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Logging;
|
||||
|
||||
class Log_Line {
|
||||
|
||||
protected $timestamp;
|
||||
|
||||
protected $priority;
|
||||
|
||||
protected $line;
|
||||
|
||||
protected $id;
|
||||
|
||||
public function __construct( $timestamp, $priority, $line, $id ) {
|
||||
$this->timestamp = $timestamp;
|
||||
$this->priority = $priority;
|
||||
$this->line = $line;
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function timestamp() {
|
||||
return $this->timestamp;
|
||||
}
|
||||
|
||||
public function priority() {
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
public function line() {
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
public function id() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+74
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Logging;
|
||||
|
||||
/**
|
||||
* Logger
|
||||
*
|
||||
* Provides an abstract for dealing with logging. Takes a $provider class (to handle actually writing to a log/db/etc),
|
||||
* and must define its own methods for whether to log, and how to delete said log.
|
||||
*/
|
||||
abstract class Logger {
|
||||
|
||||
/**
|
||||
* @var Logging_Provider
|
||||
*/
|
||||
protected $provider;
|
||||
|
||||
abstract protected function should_log();
|
||||
|
||||
abstract protected function delete_log();
|
||||
|
||||
public function __construct( Logging_Provider $provider ) {
|
||||
$this->provider = $provider;
|
||||
}
|
||||
|
||||
public function log( $message, $priority ) {
|
||||
if ( ! $this->should_log( $priority ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->provider->log( $message, $priority );
|
||||
}
|
||||
|
||||
public function log_info( $message ) {
|
||||
if ( ! $this->should_log( 'info' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->provider->log_info( $message );
|
||||
}
|
||||
|
||||
public function log_debug( $message ) {
|
||||
if ( ! $this->should_log( 'debug' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->provider->log_debug( $message );
|
||||
}
|
||||
|
||||
public function log_warning( $message ) {
|
||||
if ( ! $this->should_log( 'warning' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->provider->log_warning( $message );
|
||||
}
|
||||
|
||||
public function log_error( $message ) {
|
||||
if ( ! $this->should_log( 'error' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->provider->log_error( $message );
|
||||
}
|
||||
|
||||
public function log_fatal( $message ) {
|
||||
if ( ! $this->should_log( 'fatal' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->provider->log_fatal( $message );
|
||||
}
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Logging;
|
||||
|
||||
interface Logging_Provider {
|
||||
|
||||
function log_info( $line );
|
||||
|
||||
function log_debug( $line );
|
||||
|
||||
function log_warning( $line );
|
||||
|
||||
function log_error( $line );
|
||||
|
||||
function log_fatal( $line );
|
||||
|
||||
function log( $line, $priority );
|
||||
|
||||
function delete_log();
|
||||
|
||||
function write_line_to_log( $line );
|
||||
|
||||
function get_lines();
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Logging\Parsers;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Logging\Log_Line;
|
||||
|
||||
class File_Log_Parser {
|
||||
|
||||
public function parse_log( $log ) {
|
||||
$lines = array_filter( explode( '[**]', $log ) );
|
||||
return array_map( function( $line ) {
|
||||
return $this->parse_log_line( $line );
|
||||
}, $lines );
|
||||
}
|
||||
|
||||
public function parse_log_line( $log_line ) {
|
||||
$log_line = trim( $log_line );
|
||||
preg_match('/(.*) - (.*) --> (.*)/', trim( $log_line ), $data );
|
||||
|
||||
if ( count( $data ) !== 4 ) {
|
||||
return new Log_Line( null, null, null );
|
||||
}
|
||||
|
||||
return new Log_Line( $data[1], trim( strtolower( $data[2] ) ), $data[3] );
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+284
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Model;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
|
||||
class Form_Model {
|
||||
|
||||
/**
|
||||
* @var Common
|
||||
*/
|
||||
protected $common;
|
||||
|
||||
public function __construct( $common ) {
|
||||
$this->common = $common;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry table name, including the site's database prefix
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @global $wpdb
|
||||
*
|
||||
* @return string The entry table name
|
||||
*/
|
||||
public function get_entry_table_name() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . 'gf_entry';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current database version.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_database_version() {
|
||||
static $db_version = array();
|
||||
$blog_id = get_current_blog_id();
|
||||
if ( empty( $db_version[ $blog_id ] ) ) {
|
||||
$db_version[ $blog_id ] = get_option( 'gf_db_version' );
|
||||
}
|
||||
|
||||
return $db_version[ $blog_id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total, active, inactive, and trashed form counts.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @uses GFFormsModel::get_form_table_name()
|
||||
*
|
||||
* @return array The form counts.
|
||||
*/
|
||||
public function get_form_count() {
|
||||
global $wpdb;
|
||||
$form_table_name = $this->get_form_table_name();
|
||||
|
||||
if ( ! $this->common->table_exists( $form_table_name ) ) {
|
||||
return array(
|
||||
'total' => 0,
|
||||
'active' => 0,
|
||||
'inactive' => 0,
|
||||
'trash' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
$results = $wpdb->get_results(
|
||||
"
|
||||
SELECT
|
||||
(SELECT count(0) FROM $form_table_name WHERE is_trash = 0) as total,
|
||||
(SELECT count(0) FROM $form_table_name WHERE is_active=1 AND is_trash = 0 ) as active,
|
||||
(SELECT count(0) FROM $form_table_name WHERE is_active=0 AND is_trash = 0 ) as inactive,
|
||||
(SELECT count(0) FROM $form_table_name WHERE is_trash=1) as trash
|
||||
"
|
||||
);
|
||||
|
||||
return array(
|
||||
'total' => intval( $results[0]->total ),
|
||||
'active' => intval( $results[0]->active ),
|
||||
'inactive' => intval( $results[0]->inactive ),
|
||||
'trash' => intval( $results[0]->trash ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form table name, including the site's database prefix.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string The form table name.
|
||||
*/
|
||||
public function get_form_table_name() {
|
||||
global $wpdb;
|
||||
|
||||
if ( version_compare( $this->get_database_version(), '2.3-dev-1', '<' ) ) {
|
||||
return $wpdb->prefix . 'rg_form';
|
||||
}
|
||||
|
||||
return $wpdb->prefix . 'gf_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry count for all forms.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $status
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_entry_count_all_forms( $status = 'active' ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( version_compare( $this->get_database_version(), '2.3-dev-1', '<' ) ) {
|
||||
return $this->get_lead_count_all_forms( $status );
|
||||
}
|
||||
|
||||
$entry_table_name = $this->get_entry_table_name();
|
||||
|
||||
if ( ! $this->common->table_exists( $entry_table_name ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$sql = $wpdb->prepare( "SELECT count(id)
|
||||
FROM $entry_table_name
|
||||
WHERE status=%s", $status );
|
||||
|
||||
return $wpdb->get_var( $sql );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entry meta counts.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_entry_meta_counts() {
|
||||
global $wpdb;
|
||||
|
||||
$detail_table_name = $this->get_lead_details_table_name();
|
||||
$meta_table_name = $this->get_lead_meta_table_name();
|
||||
$notes_table_name = $this->get_lead_notes_table_name();
|
||||
|
||||
$results = $wpdb->get_results(
|
||||
"
|
||||
SELECT
|
||||
(SELECT count(0) FROM $detail_table_name) as details,
|
||||
(SELECT count(0) FROM $meta_table_name) as meta,
|
||||
(SELECT count(0) FROM $notes_table_name) as notes
|
||||
"
|
||||
);
|
||||
|
||||
return array(
|
||||
'details' => intval( $results[0]->details ),
|
||||
'meta' => intval( $results[0]->meta ),
|
||||
'notes' => intval( $results[0]->notes ),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lead counts for all forms.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $status
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_lead_count_all_forms( $status = 'active' ) {
|
||||
global $wpdb;
|
||||
|
||||
$lead_table_name = $this->get_lead_table_name();
|
||||
|
||||
$result = $wpdb->get_var( "SHOW COLUMNS FROM $lead_table_name LIKE 'status'" );
|
||||
|
||||
if ( $result ) {
|
||||
$sql = $wpdb->prepare( "SELECT count(id)
|
||||
FROM $lead_table_name
|
||||
WHERE status=%s", $status );
|
||||
} else {
|
||||
$sql = "SELECT count(id) FROM $lead_table_name";
|
||||
}
|
||||
|
||||
return $wpdb->get_var( $sql );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lead (entries) table name, including the site's database prefix.
|
||||
*
|
||||
* @since 1.0
|
||||
|
||||
* @global $wpdb
|
||||
*
|
||||
* @return string The lead (entry) table name.
|
||||
*/
|
||||
public function get_lead_table_name() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . 'rg_lead';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lead (entry) meta table name, including the site's database prefix.
|
||||
*
|
||||
* @since 1.0
|
||||
|
||||
* @global $wpdb
|
||||
*
|
||||
* @return string The lead (entry) meta table name.
|
||||
*/
|
||||
public function get_lead_meta_table_name() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . 'rg_lead_meta';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lead (entry) notes table name, including the site's database prefix.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @global $wpdb
|
||||
*
|
||||
* @return string The lead (entry) notes table name.
|
||||
*/
|
||||
public function get_lead_notes_table_name() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . 'rg_lead_notes';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lead (entry) details table name, including the site's database prefix.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @global $wpdb
|
||||
*
|
||||
* @return string The lead (entry) details table name.
|
||||
*/
|
||||
public function get_lead_details_table_name() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . 'rg_lead_detail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lead (entry) details long table name, including the site's database prefix.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @global $wpdb
|
||||
*
|
||||
* @return string The lead (entry) details long table name.
|
||||
*/
|
||||
public function get_lead_details_long_table_name() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . 'rg_lead_detail_long';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lead (entry) view table name, including the site's database prefix.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @global $wpdb
|
||||
*
|
||||
* @return string The lead (entry) view table name.
|
||||
*/
|
||||
public function get_lead_view_name() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . 'rg_lead_view';
|
||||
}
|
||||
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Providers;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Service_Container;
|
||||
use Gravity_Forms\Gravity_Tools\Service_Provider;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Config_Collection;
|
||||
use Gravity_Forms\Gravity_Tools\Config_Data_Parser;
|
||||
|
||||
/**
|
||||
* Class Config_Collection_Service_Provider
|
||||
*
|
||||
* Service provider for the Config Collection Service.
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Tools\Providers
|
||||
*/
|
||||
class Config_Collection_Service_Provider extends Service_Provider {
|
||||
|
||||
// Organizational services
|
||||
const CONFIG_COLLECTION = 'config_collection';
|
||||
const DATA_PARSER = 'data_parser';
|
||||
|
||||
protected $rest_namespace;
|
||||
|
||||
/**
|
||||
* The $rest_namespace will be used in order to define the API endpoint for
|
||||
* retrieving mock/config data.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $rest_namespace
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $rest_namespace = 'gravityforms/v2' ) {
|
||||
$this->rest_namespace = $rest_namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register services to the container.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param Service_Container $container
|
||||
*/
|
||||
public function register( Service_Container $container ) {
|
||||
|
||||
// Add to container
|
||||
$container->add( self::CONFIG_COLLECTION, function () {
|
||||
return new Config_Collection();
|
||||
} );
|
||||
|
||||
$container->add( self::DATA_PARSER, function () {
|
||||
return new Config_Data_Parser();
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiailize any actions or hooks.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param Service_Container $container
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init( Service_Container $container ) {
|
||||
|
||||
// Need to pass $this to callbacks; save as variable.
|
||||
$self = $this;
|
||||
|
||||
add_action( 'wp_enqueue_scripts', function () use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle();
|
||||
}, 9999 );
|
||||
|
||||
add_action( 'admin_enqueue_scripts', function () use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle();
|
||||
}, 9999 );
|
||||
|
||||
add_action( 'gform_preview_init', function () use ( $container ) {
|
||||
$container->get( self::CONFIG_COLLECTION )->handle();
|
||||
}, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the Config Mocks REST endpoint.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function config_mocks_endpoint() {
|
||||
define( 'GFORMS_DOING_MOCK', true );
|
||||
$data = $this->container->get( self::CONFIG_COLLECTION )->handle( false );
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Providers;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Service_Container;
|
||||
use Gravity_Forms\Gravity_Tools\Service_Provider;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Config_Collection;
|
||||
use Gravity_Forms\Gravity_Tools\Config_Data_Parser;
|
||||
|
||||
/**
|
||||
* Class Config_Service_Provider
|
||||
*
|
||||
* Service provider for the Config Collection Service.
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Tools\Providers
|
||||
*/
|
||||
abstract class Config_Service_Provider extends Service_Provider {
|
||||
|
||||
/**
|
||||
* Array mapping config class names to their container ID.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $configs = array();
|
||||
|
||||
/**
|
||||
* Register services to the container.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param Service_Container $container
|
||||
*/
|
||||
public function register( Service_Container $container ) {
|
||||
// Add configs to container.
|
||||
$this->register_config_items( $container );
|
||||
$this->register_configs_to_collection( $container );
|
||||
}
|
||||
|
||||
/**
|
||||
* For each config defined in $configs, instantiate and add to container.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param Service_Container $container
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function register_config_items( Service_Container $container ) {
|
||||
$parser = $container->get( Config_Collection_Service_Provider::DATA_PARSER );
|
||||
|
||||
foreach ( $this->configs as $name => $class ) {
|
||||
$container->add( $name, function () use ( $class, $parser ) {
|
||||
return new $class( $parser );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register each config defined in $configs to the GF_Config_Collection.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param Service_Container $container
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_configs_to_collection( Service_Container $container ) {
|
||||
$collection = $container->get( Config_Collection_Service_Provider::CONFIG_COLLECTION );
|
||||
|
||||
foreach ( $this->configs as $name => $config ) {
|
||||
$config_class = $container->get( $name );
|
||||
$collection->add_config( $config_class );
|
||||
}
|
||||
}
|
||||
}
|
||||
+485
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\System_Report\System_Report_Group;
|
||||
use Gravity_Forms\Gravity_Tools\System_Report\System_Report_Item;
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
|
||||
class Environment_Details_Report_Details {
|
||||
|
||||
protected $groups = array();
|
||||
|
||||
private function add( $name, $group ) {
|
||||
$this->groups[ $name ] = $group;
|
||||
}
|
||||
|
||||
public function get_environment_details() {
|
||||
if ( ! function_exists( 'get_locale' ) ) {
|
||||
return $this->groups;
|
||||
}
|
||||
|
||||
$wordpress_environment_data = $this->get_wordpress_environment_data();
|
||||
$active_theme_data = $this->get_active_theme_data();
|
||||
$active_plugins_data = $this->get_active_plugins_data();
|
||||
$web_server_data = $this->get_web_server_data();
|
||||
$php_data = $this->get_php_data();
|
||||
$database_server_data = $this->get_database_server_data();
|
||||
$date_and_time_data = $this->get_date_and_time_data();
|
||||
$translations = $this->get_translations_data();
|
||||
|
||||
$this->add( __( 'WordPress Environment', 'gravity' ), $wordpress_environment_data );
|
||||
$this->add( __( 'Active Theme', 'gravity' ), $active_theme_data );
|
||||
$this->add( __( 'Active Plugins', 'gravity' ), $active_plugins_data );
|
||||
$this->add( __( 'Web Server', 'gravity' ), $web_server_data );
|
||||
$this->add( __( 'PHP', 'gravity' ), $php_data );
|
||||
$this->add( __( 'Database Server', 'gravity' ), $database_server_data );
|
||||
$this->add( __( 'Date and Time', 'gravity' ), $date_and_time_data );
|
||||
$this->add( __( 'Translations', 'gravity' ), $translations );
|
||||
|
||||
return $this->groups;
|
||||
}
|
||||
|
||||
protected function get_translations_data() {
|
||||
$group = new System_Report_Group();
|
||||
|
||||
$group->add( 'site_locale', new System_Report_Item( __( 'Site Locale', 'gravity' ), get_locale() ) );
|
||||
$group->add( 'user_locale', new System_Report_Item( sprintf( esc_html__( 'User (ID: %d) Locale', 'gravity' ), get_current_user_id() ), get_user_locale() ) );
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function get_wordpress_environment_data() {
|
||||
$wp_cron_disabled = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON;
|
||||
$alternate_wp_cron = defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON;
|
||||
|
||||
$args = array(
|
||||
'timeout' => 2,
|
||||
'body' => 'test',
|
||||
'cookies' => $_COOKIE,
|
||||
'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
|
||||
);
|
||||
|
||||
$filters_to_check = array(
|
||||
'pre_wp_mail' => has_filter( 'pre_wp_mail' ),
|
||||
);
|
||||
|
||||
$registered_filters = array_keys( array_filter( $filters_to_check ) );
|
||||
|
||||
$items = array(
|
||||
array(
|
||||
'label' => esc_html__( 'Home URL', 'gravity' ),
|
||||
'value' => get_home_url(),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Site URL', 'gravity' ),
|
||||
'value' => get_site_url(),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'REST API Base URL', 'gravity' ),
|
||||
'value' => rest_url(),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress Version', 'gravity' ),
|
||||
'value' => get_bloginfo( 'version' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress Multisite', 'gravity' ),
|
||||
'value' => is_multisite() ? esc_html__( 'Yes', 'gravity' ) : esc_html__( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress Memory Limit', 'gravity' ),
|
||||
'value' => WP_MEMORY_LIMIT,
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress Debug Mode', 'gravity' ),
|
||||
'value' => WP_DEBUG ? esc_html__( 'Yes', 'gravity' ) : esc_html__( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress Debug Log', 'gravity' ),
|
||||
'value' => WP_DEBUG_LOG ? esc_html__( 'Yes', 'gravity' ) : esc_html__( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress Script Debug Mode', 'gravity' ),
|
||||
'value' => SCRIPT_DEBUG ? __( 'Yes', 'gravity' ) : __( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress Cron', 'gravity' ),
|
||||
'value' => ! $wp_cron_disabled ? __( 'Yes', 'gravity' ) : __( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress Alternate Cron', 'gravity' ),
|
||||
'value' => $alternate_wp_cron ? __( 'Yes', 'gravity' ) : __( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Registered Filters', 'gravity' ),
|
||||
'value' => empty( $registered_filters ) ? esc_html__( 'N/A', 'gravity' ) : join( ', ', $registered_filters ),
|
||||
),
|
||||
);
|
||||
|
||||
$group = new System_Report_Group();
|
||||
|
||||
foreach ( $items as $item ) {
|
||||
$group->add( $item['label'], new System_Report_Item( $item['label'], $item['value'] ) );
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function get_active_theme_data() {
|
||||
$themes = array();
|
||||
$active_theme = wp_get_theme();
|
||||
$parent_theme = $active_theme->parent();
|
||||
|
||||
// Add active theme data
|
||||
$label = ! empty( $active_theme->get( 'ThemeURI' ) )
|
||||
? '<a class="gform-link" href="' . esc_url( $active_theme->get( 'ThemeURI' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $active_theme->get( 'Name' ) ) . '</a>'
|
||||
: esc_html( $active_theme->get( 'Name' ) );
|
||||
|
||||
if ( ! empty( $active_theme->get( 'AuthorURI' ) ) ) {
|
||||
$author = '<a class="gform-link" href="' . esc_url( $active_theme->get( 'AuthorURI' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $active_theme->get( 'Author' ) ) . '</a>';
|
||||
} else {
|
||||
$author = preg_replace_callback( '/(<a[^>]*>)/', function ( $matches ) {
|
||||
preg_match( '/class="[^"]*"/', $matches[1], $class_matches );
|
||||
|
||||
if ( empty( $class_matches ) ) {
|
||||
return str_replace( '<a', '<a class="gform-link"', $matches[1] );
|
||||
}
|
||||
|
||||
return preg_replace( '/class="([^"]*)"/', 'class="$1 gform-link"', $matches[1] );
|
||||
}, $active_theme->get( 'Author' ) );
|
||||
}
|
||||
|
||||
$value = wp_kses_post(
|
||||
sprintf(
|
||||
/* translators: 1: Theme author and URL. 2: Theme version. */
|
||||
__( 'by %1$s - %2$s', 'gravity' ),
|
||||
$author,
|
||||
$active_theme->get( 'Version' )
|
||||
)
|
||||
);
|
||||
|
||||
$themes[] = array(
|
||||
'label' => $label,
|
||||
'value' => $value,
|
||||
);
|
||||
|
||||
// Add parent theme data if it exists
|
||||
if ( $parent_theme instanceof \WP_Theme ) {
|
||||
$parent_label = ! empty( $parent_theme->get( 'ThemeURI' ) )
|
||||
? '<a class="gform-link" href="' . esc_url( $parent_theme->get( 'ThemeURI' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $parent_theme->get( 'Name' ) ) . ' (Parent)</a>'
|
||||
: esc_html( $parent_theme->get( 'Name' ) . ' (Parent)' );
|
||||
|
||||
$parent_author_uri = $parent_theme->get( 'AuthorURI' );
|
||||
|
||||
if ( ! empty( $parent_theme->get( 'AuthorURI' ) ) ) {
|
||||
$parent_author = '<a class="gform-link" href="' . esc_url( $parent_theme->get( 'AuthorURI' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $parent_theme->get( 'Author' ) ) . '</a>';
|
||||
} else {
|
||||
$parent_author = preg_replace_callback( '/(<a[^>]*>)/', function ( $matches ) {
|
||||
preg_match( '/class="[^"]*"/', $matches[1], $class_matches );
|
||||
|
||||
if ( empty( $class_matches ) ) {
|
||||
return str_replace( '<a', '<a class="gform-link"', $matches[1] );
|
||||
}
|
||||
|
||||
return preg_replace( '/class="([^"]*)"/', 'class="$1 gform-link"', $matches[1] );
|
||||
}, $parent_theme->get( 'Author' ) );
|
||||
}
|
||||
|
||||
$parent_value = wp_kses_post(
|
||||
sprintf(
|
||||
/* translators: 1: Theme author and URL. 2: Theme version. */
|
||||
__( 'by %1$s - %2$s', 'gravity' ),
|
||||
$parent_author,
|
||||
$parent_theme->get( 'Version' )
|
||||
)
|
||||
);
|
||||
|
||||
$themes[] = array(
|
||||
'label' => $parent_label,
|
||||
'value' => $parent_value,
|
||||
);
|
||||
}
|
||||
|
||||
$group = new System_Report_Group();
|
||||
|
||||
foreach ( $themes as $theme ) {
|
||||
$group->add( $theme['label'], new System_Report_Item( $theme['label'], $theme['value'] ) );
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function get_active_plugins_data() {
|
||||
$plugins = array();
|
||||
|
||||
foreach ( get_plugins() as $plugin_path => $plugin ) {
|
||||
// If plugin is not active, skip it.
|
||||
if ( ! is_plugin_active( $plugin_path ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$label = isset( $plugin['PluginURI'] ) && ! empty( $plugin['PluginURI'] )
|
||||
? '<a class="gform-link" href="' . esc_url( $plugin['PluginURI'] ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $plugin['Name'] ) . '</a>'
|
||||
: esc_html( $plugin['Name'] );
|
||||
|
||||
$author = $plugin['Author'];
|
||||
|
||||
if ( isset( $plugin['AuthorURI'] ) && ! empty( $plugin['AuthorURI'] ) ) {
|
||||
$author = '<a class="gform-link" href="' . esc_url( $plugin['AuthorURI'] ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $plugin['Author'] ) . '</a>';
|
||||
} else {
|
||||
$author = preg_replace_callback( '/(<a[^>]*>)/', function ( $matches ) {
|
||||
preg_match( '/class="[^"]*"/', $matches[1], $class_matches );
|
||||
|
||||
if ( empty( $class_matches ) ) {
|
||||
return str_replace( '<a', '<a class="gform-link"', $matches[1] );
|
||||
}
|
||||
|
||||
return preg_replace( '/class="([^"]*)"/', 'class="$1 gform-link"', $matches[1] );
|
||||
}, $plugin['Author'] );
|
||||
}
|
||||
|
||||
$value = wp_kses_post(
|
||||
sprintf(
|
||||
/* translators: 1: Plugin author and URL. 2: Plugin version. */
|
||||
__( 'by %1$s - %2$s', 'gravity' ),
|
||||
$author,
|
||||
$plugin['Version']
|
||||
)
|
||||
);
|
||||
|
||||
$plugins[] = array(
|
||||
'label' => $label,
|
||||
'value' => $value,
|
||||
);
|
||||
}
|
||||
|
||||
$group = new System_Report_Group();
|
||||
|
||||
foreach ( $plugins as $plugin ) {
|
||||
$group->add( $plugin['label'], new System_Report_Item( $plugin['label'], $plugin['value'] ) );
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function get_web_server_data() {
|
||||
$items = array(
|
||||
array(
|
||||
'label' => esc_html__( 'Software', 'gravity' ),
|
||||
'value' => esc_html( $_SERVER['SERVER_SOFTWARE'] ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Port', 'gravity' ),
|
||||
'value' => esc_html( $_SERVER['SERVER_PORT'] ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Document Root', 'gravity' ),
|
||||
'value' => esc_html( $_SERVER['DOCUMENT_ROOT'] ),
|
||||
),
|
||||
);
|
||||
|
||||
$group = new System_Report_Group();
|
||||
|
||||
foreach ( $items as $item ) {
|
||||
$group->add( $item['label'], new System_Report_Item( $item['label'], $item['value'] ) );
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function get_php_data() {
|
||||
$curl_version = null;
|
||||
|
||||
if ( function_exists( 'curl_version' ) ) {
|
||||
$curl_version_info = curl_version();
|
||||
|
||||
if ( is_array( $curl_version_info ) && isset( $curl_version_info['version'] ) ) {
|
||||
$curl_version = $curl_version_info['version'];
|
||||
}
|
||||
}
|
||||
|
||||
$items = array(
|
||||
array(
|
||||
'label' => esc_html__( 'Version', 'gravity' ),
|
||||
'value' => esc_html( phpversion() ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Memory Limit', 'gravity' ) . ' (memory_limit)',
|
||||
'value' => esc_html( ini_get( 'memory_limit' ) ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Maximum Execution Time', 'gravity' ) . ' (max_execution_time)',
|
||||
'value' => esc_html( ini_get( 'max_execution_time' ) ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Maximum File Upload Size', 'gravity' ) . ' (upload_max_filesize)',
|
||||
'value' => esc_html( ini_get( 'upload_max_filesize' ) ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Maximum File Uploads', 'gravity' ) . ' (max_file_uploads)',
|
||||
'value' => esc_html( ini_get( 'max_file_uploads' ) ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Maximum Post Size', 'gravity' ) . ' (post_max_size)',
|
||||
'value' => esc_html( ini_get( 'post_max_size' ) ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Maximum Input Variables', 'gravity' ) . ' (max_input_vars)',
|
||||
'value' => esc_html( ini_get( 'max_input_vars' ) ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'cURL Enabled', 'gravity' ),
|
||||
'value' => function_exists( 'curl_init' )
|
||||
? esc_html(
|
||||
sprintf(
|
||||
/* translators: %s: cURL version. */
|
||||
__( 'Yes (version %s)', 'gravity' ),
|
||||
$curl_version
|
||||
)
|
||||
)
|
||||
: esc_html__( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'OpenSSL', 'gravity' ),
|
||||
'value' => defined( 'OPENSSL_VERSION_TEXT' ) ? OPENSSL_VERSION_TEXT . ' (' . OPENSSL_VERSION_NUMBER . ')' : __( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Mcrypt Enabled', 'gravity' ),
|
||||
'value' => function_exists( 'mcrypt_encrypt' ) ? esc_html__( 'Yes', 'gravity' ) : esc_html__( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Mbstring Enabled', 'gravity' ),
|
||||
'value' => function_exists( 'mb_strlen' ) ? esc_html__( 'Yes', 'gravity' ) : esc_html__( 'No', 'gravity' ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Loaded Extensions', 'gravity' ),
|
||||
'value' => join( ', ', get_loaded_extensions() ),
|
||||
),
|
||||
);
|
||||
|
||||
$group = new System_Report_Group();
|
||||
|
||||
foreach( $items as $item ) {
|
||||
$group->add( $item['label'], new System_Report_Item( $item['label'], $item['value'] ) );
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function get_database_server_data() {
|
||||
global $wpdb;
|
||||
|
||||
$db_version = Common::get_db_version();
|
||||
$db_type = Common::get_dbms_type();
|
||||
|
||||
$items = array(
|
||||
array(
|
||||
'label' => esc_html__( 'Database Management System', 'gravity' ),
|
||||
'value' => esc_html( $db_type ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Version', 'gravity' ),
|
||||
'value' => esc_html( $db_version ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Database Character Set', 'gravity' ),
|
||||
'value' => esc_html( ( Common::get_dbms_type() === 'SQLite' ) ? $wpdb->charset : $wpdb->get_var( 'SELECT @@character_set_database' ) ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'Database Collation', 'gravity' ),
|
||||
'value' => esc_html( ( Common::get_dbms_type() === 'SQLite' ) ? ( empty( $wpdb->collate ) ? 'N/A' : $wpdb->collate ) : $wpdb->get_var( 'SELECT @@collation_database' ) ),
|
||||
),
|
||||
);
|
||||
|
||||
$group = new System_Report_Group();
|
||||
|
||||
foreach( $items as $item ) {
|
||||
$group->add( $item['label'], new System_Report_Item( $item['label'], $item['value'] ) );
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function get_date_and_time_data() {
|
||||
global $wpdb;
|
||||
|
||||
$db_date = $wpdb->get_var( 'SELECT utc_timestamp()' );
|
||||
$php_date = date( 'Y-m-d H:i:s' );
|
||||
|
||||
$date_option = trim( get_option( 'date_format' ) );
|
||||
$time_option = trim( get_option( 'time_format' ) );
|
||||
$date_format = $date_option ? $date_option : 'Y-m-d';
|
||||
$time_format = $time_option ? $time_option : 'H:i';
|
||||
|
||||
$gmt_db_date = mysql2date( 'G', $db_date );
|
||||
$local_db_date = strtotime( get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $gmt_db_date ) ) );
|
||||
$formatted_local_db_date = sprintf(
|
||||
/* translators: 1: date, 2: time */
|
||||
__( '%1$s at %2$s', 'gravity' ),
|
||||
date_i18n( $date_format, $local_db_date, true ),
|
||||
date_i18n( $time_format, $local_db_date, true )
|
||||
);
|
||||
|
||||
$gmt_php_date = mysql2date( 'G', $php_date );
|
||||
$local_php_date = strtotime( get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $gmt_php_date ) ) );
|
||||
$formatted_local_php_date = sprintf(
|
||||
/* translators: 1: date, 2: time */
|
||||
__( '%1$s at %2$s', 'gravity' ),
|
||||
date_i18n( $date_format, $local_php_date, true ),
|
||||
date_i18n( $time_format, $local_php_date, true )
|
||||
);
|
||||
|
||||
$items = array(
|
||||
array(
|
||||
'label' => esc_html__( 'WordPress (Local) Timezone', 'gravity' ),
|
||||
'value' => $this->get_timezone(),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'MySQL - Universal time (UTC)', 'gravity' ),
|
||||
'value' => esc_html( $db_date ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'MySQL - Local time', 'gravity' ),
|
||||
'value' => esc_html( $formatted_local_db_date ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'PHP - Universal time (UTC)', 'gravity' ),
|
||||
'value' => esc_html( $php_date ),
|
||||
),
|
||||
array(
|
||||
'label' => esc_html__( 'PHP - Local time', 'gravity' ),
|
||||
'value' => esc_html( $formatted_local_php_date ),
|
||||
),
|
||||
);
|
||||
|
||||
$group = new System_Report_Group();
|
||||
|
||||
foreach( $items as $item ) {
|
||||
$group->add( $item['label'], new System_Report_Item( $item['label'], $item['value'] ) );
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
protected function get_timezone() {
|
||||
$tzstring = get_option( 'timezone_string' );
|
||||
|
||||
// Remove old Etc mappings. Fallback to gmt_offset.
|
||||
if ( false !== strpos( $tzstring, 'Etc/GMT' ) ) {
|
||||
$tzstring = '';
|
||||
}
|
||||
|
||||
if ( empty( $tzstring ) ) { // Create a UTC+- zone if no timezone string exists
|
||||
$current_offset = get_option( 'gmt_offset' );
|
||||
|
||||
if ( 0 == $current_offset ) {
|
||||
$tzstring = 'UTC+0';
|
||||
} elseif ( $current_offset < 0 ) {
|
||||
$tzstring = 'UTC' . $current_offset;
|
||||
} else {
|
||||
$tzstring = 'UTC+' . $current_offset;
|
||||
}
|
||||
}
|
||||
|
||||
return $tzstring;
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\System_Report;
|
||||
|
||||
class System_Report_Group {
|
||||
|
||||
/**
|
||||
* @var System_Report_Item[]
|
||||
*/
|
||||
protected $items = array();
|
||||
|
||||
public function all() {
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function add( $name, System_Report_Item $item ) {
|
||||
$this->items[ $name ] = $item;
|
||||
}
|
||||
|
||||
public function delete( $name ) {
|
||||
unset( $this->items[ $name ] );
|
||||
}
|
||||
|
||||
public function get( $name ) {
|
||||
if ( ! isset( $this->items[ $name ] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->items[ $name ];
|
||||
}
|
||||
|
||||
public function has( $name ) {
|
||||
if ( ! isset( $this->items[ $name ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function as_array() {
|
||||
return array_map( function( $item ) {
|
||||
return $item->as_array();
|
||||
}, $this->items );
|
||||
}
|
||||
|
||||
public function as_string() {
|
||||
$response = '';
|
||||
|
||||
foreach( $this->items as $item ) {
|
||||
$response .= $item->as_string();
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\System_Report;
|
||||
|
||||
class System_Report_Item {
|
||||
|
||||
protected $key;
|
||||
|
||||
protected $value;
|
||||
|
||||
protected $is_sensitive;
|
||||
|
||||
protected $obfuscated_value = '**********';
|
||||
|
||||
public function __construct( $key, $value, $is_sensitive = false ) {
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
$this->is_sensitive = $is_sensitive;
|
||||
}
|
||||
|
||||
public function key() {
|
||||
return $this->escape( $this->key );
|
||||
}
|
||||
|
||||
public function value() {
|
||||
if ( $this->is_sensitive ) {
|
||||
return $this->obfuscated_value;
|
||||
}
|
||||
|
||||
return $this->escape( $this->value );
|
||||
}
|
||||
|
||||
public function is_sensitive() {
|
||||
return $this->is_sensitive;
|
||||
}
|
||||
|
||||
public function as_array() {
|
||||
return array(
|
||||
'key' => $this->key(),
|
||||
'value' => $this->value(),
|
||||
);
|
||||
}
|
||||
|
||||
public function as_string() {
|
||||
return sprintf( "%s: %s\n", $this->key(), $this->value() );
|
||||
}
|
||||
|
||||
private function escape( $string ) {
|
||||
return strip_tags( $string, array( 'a' ) );
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\System_Report;
|
||||
|
||||
use Environment_Details_Report_Details;
|
||||
|
||||
class System_Report_Repository {
|
||||
|
||||
/**
|
||||
* @var System_Report_Group[]
|
||||
*/
|
||||
protected $groups = array();
|
||||
|
||||
private static $instance;
|
||||
|
||||
public function __construct( $init_empty = false ) {
|
||||
if ( $init_empty ) {
|
||||
return;
|
||||
}
|
||||
$this->setup_environment_details();
|
||||
}
|
||||
|
||||
private function setup_environment_details() {
|
||||
$environment_details = new Environment_Details_Report_Details();
|
||||
$groups = $environment_details->get_environment_details();
|
||||
|
||||
foreach( $groups as $key => $group ) {
|
||||
$this->add( $key, $group );
|
||||
}
|
||||
}
|
||||
|
||||
public static function instance( $init_empty = false ) {
|
||||
if ( ! is_null( self::$instance ) ) {
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
return new self( $init_empty );
|
||||
}
|
||||
|
||||
public function all() {
|
||||
return $this->groups;
|
||||
}
|
||||
|
||||
public function get( $name ) {
|
||||
if ( ! isset( $this->groups[ $name ] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->groups[ $name ];
|
||||
}
|
||||
|
||||
public function delete( $name ) {
|
||||
unset( $this->groups[ $name ] );
|
||||
}
|
||||
|
||||
public function has( $name ) {
|
||||
if ( ! isset( $this->groups[ $name ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function add( $name, System_Report_Group $group ) {
|
||||
$this->groups[ $name ] = $group;
|
||||
}
|
||||
|
||||
public function as_array() {
|
||||
$response = array();
|
||||
|
||||
foreach( $this->groups as $name => $group ) {
|
||||
$response[ $name ] = $group->as_array();
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function as_string() {
|
||||
$response = '';
|
||||
|
||||
foreach( $this->groups as $name => $group ) {
|
||||
$response .= sprintf( "%s\n", $name );
|
||||
$response .= $group->as_string();
|
||||
$response .= "\n";
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Telemetry;
|
||||
|
||||
/**
|
||||
* Class Telemetry_Data
|
||||
*
|
||||
* Base class for telemetry data.
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Forms\Telemetry
|
||||
*/
|
||||
abstract class Telemetry_Data {
|
||||
|
||||
/**
|
||||
* @var array $data Data to be sent.
|
||||
*/
|
||||
public $data = array();
|
||||
|
||||
/**
|
||||
* @var string $key Unique identifier for this data object.
|
||||
*/
|
||||
public $key = '';
|
||||
|
||||
protected $enabled_setting_name = '';
|
||||
|
||||
protected $data_setting_name = '';
|
||||
|
||||
abstract public function after_send( $response );
|
||||
|
||||
abstract public function record_data();
|
||||
|
||||
/**
|
||||
* Determine if the user has allowed data collection.
|
||||
*
|
||||
* @since 1.0.3
|
||||
*
|
||||
* @return false|mixed|null
|
||||
*/
|
||||
public function is_data_collection_allowed() {
|
||||
static $is_allowed;
|
||||
|
||||
if ( ! is_null( $is_allowed ) ) {
|
||||
return $is_allowed;
|
||||
}
|
||||
|
||||
$is_allowed = get_option( $this->enabled_setting_name, false );
|
||||
|
||||
return $is_allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current telemetry data.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_existing_data() {
|
||||
return get_option( $this->data_setting_name, [] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save telemetry data.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param Telemetry_Data $data The data to save.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save_data( $data ) {
|
||||
$existing_data = $this->get_existing_data();
|
||||
|
||||
if ( ! $existing_data ) {
|
||||
$existing_data = array();
|
||||
}
|
||||
|
||||
$existing_data[ $this->key ] = $data;
|
||||
|
||||
update_option( $this->data_setting_name, $existing_data, false );
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Telemetry;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Background_Processing\Background_Process;
|
||||
|
||||
/**
|
||||
* Telemetry_Processor Class.
|
||||
*/
|
||||
abstract class Telemetry_Processor extends Background_Process {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const TELEMETRY_ENDPOINT = 'https://in.gravity.io/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $action = 'telemetry_processor';
|
||||
|
||||
/**
|
||||
* Send data to the telemetry endpoint.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param array $entries The data to send.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
abstract public function send_data( $entries );
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* Process a single batch of telemetry data.
|
||||
*
|
||||
* @param mixed $batch
|
||||
* @return mixed
|
||||
*/
|
||||
protected function task( $batch ) {
|
||||
|
||||
if ( ! is_array( $batch ) ) {
|
||||
$batch = array( $batch );
|
||||
}
|
||||
|
||||
$raw_response = null;
|
||||
$this->logger->log_debug( __METHOD__ . sprintf( '(): Processing a batch of %d telemetry data.', count( $batch ) ) );
|
||||
$raw_response = $this->send_data( $batch );
|
||||
|
||||
if ( is_wp_error( $raw_response ) ) {
|
||||
$this->logger->log_debug( __METHOD__ . sprintf( '(): Failed sending telemetry data. Code: %s; Message: %s.', $raw_response->get_error_code(), $raw_response->get_error_message() ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $batch as $item ) {
|
||||
/**
|
||||
* @var Telemetry_Data $item
|
||||
*/
|
||||
if ( ! is_object( $item ) ) {
|
||||
$this->logger->log_debug( __METHOD__ . sprintf( '(): Telemetry data is missing. Aborting running data_sent method on this entry.' ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
$item->after_send( $raw_response );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Vendored
+421
@@ -0,0 +1,421 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Updates;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\License\License_API_Connector;
|
||||
use Gravity_Forms\Gravity_Tools\Utils\Common;
|
||||
|
||||
if ( ! defined( 'RG_CURRENT_PAGE' ) ) {
|
||||
define( 'RG_CURRENT_PAGE', '' );
|
||||
}
|
||||
|
||||
class Auto_Updater {
|
||||
|
||||
protected $_version;
|
||||
protected $_slug;
|
||||
protected $_title;
|
||||
protected $_update_icon;
|
||||
protected $_full_path;
|
||||
protected $_path;
|
||||
protected $_url;
|
||||
protected $_is_forms;
|
||||
|
||||
/**
|
||||
* @var Common
|
||||
*/
|
||||
protected $common;
|
||||
|
||||
/**
|
||||
* @var License_API_Connector
|
||||
*/
|
||||
protected $license_connector;
|
||||
|
||||
|
||||
public function __construct( $slug, $version, $title, $full_path, $path, $url, $update_icon, $common, $license_connector, $is_forms = true ) {
|
||||
$this->_slug = $slug;
|
||||
$this->_version = $version;
|
||||
$this->_title = $title;
|
||||
$this->_full_path = $full_path;
|
||||
$this->_path = $path;
|
||||
$this->_url = $url;
|
||||
$this->_update_icon = $update_icon;
|
||||
$this->common = $common;
|
||||
$this->license_connector = $license_connector;
|
||||
$this->_is_forms = $is_forms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize various hooks and filters.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init() {
|
||||
if ( is_admin() ) {
|
||||
add_action( 'install_plugins_pre_plugin-information', array( $this, 'display_changelog' ), 9 );
|
||||
add_action( 'gform_after_check_update', array( $this, 'flush_version_info' ) );
|
||||
add_action( 'gform_updates', array( $this, 'display_updates' ) );
|
||||
if ( $this->_is_forms ) {
|
||||
add_filter( 'gform_updates_list', array( $this, 'get_update_info' ) );
|
||||
}
|
||||
|
||||
if ( in_array( RG_CURRENT_PAGE, array( 'admin-ajax.php' ) ) ) {
|
||||
add_action( 'wp_ajax_gf_get_changelog', array( $this, 'ajax_display_changelog' ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Check for updates. The check might not run the admin context. E.g. from WP-CLI.
|
||||
add_filter( 'transient_update_plugins', array( $this, 'check_update' ) );
|
||||
add_filter( 'site_transient_update_plugins', array( $this, 'check_update' ) );
|
||||
|
||||
// ManageWP premium update filters
|
||||
add_filter( 'mwp_premium_update_notification', array( $this, 'premium_update_push' ) );
|
||||
add_filter( 'mwp_premium_perform_update', array( $this, 'premium_update' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Premium update push for ManageWP.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @filter mwp_premium_update_notification 10 1
|
||||
*
|
||||
* @param $premium_update
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function premium_update_push( $premium_update ) {
|
||||
|
||||
if ( ! function_exists( 'get_plugin_data' ) ) {
|
||||
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
||||
}
|
||||
|
||||
$update = $this->get_version_info( $this->_slug );
|
||||
if ( $this->common->rgar( $update, 'is_valid_key' ) == true && version_compare( $this->_version, $update['version'], '<' ) ) {
|
||||
$plugin_data = get_plugin_data( $this->_full_path );
|
||||
$plugin_data['type'] = 'plugin';
|
||||
$plugin_data['slug'] = $this->_path;
|
||||
$plugin_data['new_version'] = isset( $update['version'] ) ? $update['version'] : false;
|
||||
$premium_update[] = $plugin_data;
|
||||
}
|
||||
|
||||
return $premium_update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrate with ManageWP
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @filter mwp_premium_perform_update 10 1
|
||||
*
|
||||
* @param $premium_update
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function premium_update( $premium_update ) {
|
||||
|
||||
if ( ! function_exists( 'get_plugin_data' ) ) {
|
||||
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
||||
}
|
||||
|
||||
$update = $this->get_version_info( $this->_slug );
|
||||
if ( $this->common->rgar( $update, 'is_valid_key' ) == true && version_compare( $this->_version, $update['version'], '<' ) ) {
|
||||
$plugin_data = get_plugin_data( $this->_full_path );
|
||||
$plugin_data['slug'] = $this->_path;
|
||||
$plugin_data['type'] = 'plugin';
|
||||
$plugin_data['url'] = isset( $update['url'] ) ? $update['url'] : false; // OR provide your own callback function for managing the update
|
||||
|
||||
array_push( $premium_update, $plugin_data );
|
||||
}
|
||||
|
||||
return $premium_update;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flush the currently-stored version info.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function flush_version_info() {
|
||||
$this->set_version_info( $this->_slug, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set version info in a transient.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $plugin_slug
|
||||
* @param $version_info
|
||||
*
|
||||
* @return void]
|
||||
*/
|
||||
private function set_version_info( $plugin_slug, $version_info ) {
|
||||
if ( function_exists( 'set_site_transient' ) ) {
|
||||
set_site_transient( $plugin_slug . '_version', $version_info, 60 * 60 * 12 );
|
||||
} else {
|
||||
set_transient( $plugin_slug . '_version', $version_info, 60 * 60 * 12 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for updates.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @filter transient_update_plugins 10 1
|
||||
* @filter site_transient_update_plugins 10 1
|
||||
*
|
||||
* @param $option
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function check_update( $option ) {
|
||||
|
||||
if ( empty( $option ) ) {
|
||||
return $option;
|
||||
}
|
||||
|
||||
$key = $this->get_key();
|
||||
|
||||
$version_info = $this->get_version_info( $this->_slug );
|
||||
|
||||
if ( $this->common->rgar( $version_info, 'is_error' ) == '1' ) {
|
||||
return $option;
|
||||
}
|
||||
|
||||
if ( empty( $option->response[ $this->_path ] ) ) {
|
||||
$option->response[ $this->_path ] = new \stdClass();
|
||||
}
|
||||
|
||||
$plugin = array(
|
||||
'plugin' => $this->_path,
|
||||
'url' => $this->_url,
|
||||
'slug' => $this->_slug,
|
||||
'icons' => array(
|
||||
'2x' => $this->_update_icon,
|
||||
),
|
||||
'package' => is_string( $version_info['url'] ) ? str_replace( '{KEY}', $key, $version_info['url'] ) : '',
|
||||
'new_version' => $version_info['version'],
|
||||
'id' => '0',
|
||||
);
|
||||
|
||||
//Empty response means that the key is invalid. Do not queue for upgrade
|
||||
if ( ! $this->common->rgar( $version_info, 'is_valid_key' ) || version_compare( $this->_version, $version_info['version'], '>=' ) ) {
|
||||
unset( $option->response[ $this->_path ] );
|
||||
$option->no_update[ $this->_path ] = (object) $plugin;
|
||||
} else {
|
||||
$option->response[ $this->_path ] = (object) $plugin;
|
||||
}
|
||||
|
||||
return $option;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the changelog.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_changelog() {
|
||||
if ( $_REQUEST['plugin'] != $this->_slug ) {
|
||||
return;
|
||||
}
|
||||
$change_log = $this->get_changelog();
|
||||
echo $change_log;
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get changelog with admin-ajax.php in GFForms::maybe_display_update_notification().
|
||||
*
|
||||
* @since 2.4.15
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_display_changelog() {
|
||||
check_admin_referer();
|
||||
|
||||
$this->display_changelog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the changelog content.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_changelog() {
|
||||
$key = $this->get_key();
|
||||
$body = "key={$key}";
|
||||
$options = array( 'method' => 'POST', 'timeout' => 3, 'body' => $body );
|
||||
$options['headers'] = array(
|
||||
'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ),
|
||||
'Content-Length' => strlen( $body ),
|
||||
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
|
||||
);
|
||||
|
||||
$raw_response = $this->common->post_to_manager( 'changelog.php', $this->get_remote_request_params( $this->_slug, $key, $this->_version ), $options );
|
||||
|
||||
if ( is_wp_error( $raw_response ) || 200 != $raw_response['response']['code'] ) {
|
||||
$text = sprintf( esc_html__( 'Oops!! Something went wrong.%sPlease try again or %scontact us%s.', 'gravityforms' ), '<br/>', "<a href='" . esc_attr( $this->common->get_support_url() ) . "'>", '</a>' );
|
||||
} else {
|
||||
$text = $raw_response['body'];
|
||||
if ( substr( $text, 0, 10 ) != '<!--GFM-->' ) {
|
||||
$text = '';
|
||||
}
|
||||
}
|
||||
|
||||
return stripslashes( $text );
|
||||
}
|
||||
|
||||
private function get_version_info( $offering, $use_cache = true ) {
|
||||
$version_info = $this->license_connector->get_version_info( $use_cache );
|
||||
$is_valid_key = $this->common->rgar( $version_info, 'is_valid_key' ) && $this->common->rgars( $version_info, "offerings/{$offering}/is_available" );
|
||||
|
||||
$info = array(
|
||||
'is_valid_key' => $is_valid_key,
|
||||
'version' => $this->common->rgars( $version_info, "offerings/{$offering}/version" ),
|
||||
'url' => $this->common->rgars( $version_info, "offerings/{$offering}/url" )
|
||||
);
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
private function get_remote_request_params( $offering, $key, $version ) {
|
||||
global $wpdb;
|
||||
|
||||
return sprintf( 'of=%s&key=%s&v=%s&wp=%s&php=%s&mysql=%s', urlencode( $offering ), urlencode( $key ), urlencode( $version ), urlencode( get_bloginfo( 'version' ) ), urlencode( phpversion() ), urlencode( $this->common->get_db_version() ) );
|
||||
}
|
||||
|
||||
private function get_key() {
|
||||
return $this->common->get_key();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the update info.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $updates
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_update_info( $updates ) {
|
||||
|
||||
$force_check = rgget( 'force-check' ) == 1;
|
||||
$version_info = $this->get_version_info( $this->_slug, ! $force_check );
|
||||
|
||||
$plugin_file = $this->_path;
|
||||
$upgrade_url = wp_nonce_url( 'update.php?action=upgrade-plugin&plugin=' . urlencode( $plugin_file ), 'upgrade-plugin_' . $plugin_file );
|
||||
|
||||
if ( ! $this->common->rgar( $version_info, 'is_valid_key' ) ) {
|
||||
|
||||
$version_icon = 'dashicons-no';
|
||||
$version_message = sprintf(
|
||||
'<p>%s</p>',
|
||||
sprintf(
|
||||
esc_html( '%sRegister%s your copy of Gravity Forms to receive access to automatic updates and support. Need a license key? %sPurchase one now%s.', 'gravityforms' ),
|
||||
'<a href="admin.php?page=gf_settings">',
|
||||
'</a>',
|
||||
'<a href="https://www.gravityforms.com">',
|
||||
'</a>'
|
||||
)
|
||||
);
|
||||
|
||||
} elseif ( version_compare( $this->_version, $version_info['version'], '<' ) ) {
|
||||
|
||||
$details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . urlencode( $this->_slug ) . '§ion=changelog&TB_iframe=true&width=600&height=800' );
|
||||
$message_link_text = sprintf( esc_html__( 'View version %s details', 'gravityforms' ), $version_info['version'] );
|
||||
$message_link = sprintf( '<a href="%s" class="thickbox" title="%s">%s</a>', esc_url( $details_url ), esc_attr( $this->_title ), $message_link_text );
|
||||
$message = sprintf( esc_html__( 'There is a new version of %1$s available. %s.', 'gravityforms' ), $this->_title, $message_link );
|
||||
|
||||
$version_icon = 'dashicons-no';
|
||||
$version_message = $message;
|
||||
|
||||
} else {
|
||||
|
||||
$version_icon = 'dashicons-yes';
|
||||
$version_message = sprintf( esc_html__( 'Your version of %s is up to date.', 'gravityforms' ), $this->_title );
|
||||
}
|
||||
|
||||
$updates[] = array(
|
||||
'name' => esc_html( $this->_title ),
|
||||
'is_valid_key' => $this->common->rgar( $version_info, 'is_valid_key' ),
|
||||
'path' => $this->_path,
|
||||
'slug' => $this->_slug,
|
||||
'latest_version' => $version_info['version'],
|
||||
'installed_version' => $this->_version,
|
||||
'upgrade_url' => $upgrade_url,
|
||||
'download_url' => $version_info['url'],
|
||||
'version_icon' => $version_icon,
|
||||
'version_message' => $version_message,
|
||||
);
|
||||
|
||||
return $updates;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display updates if necessary.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_updates() {
|
||||
|
||||
?>
|
||||
<div class="wrap <?php echo $this->common->get_browser_class() ?>">
|
||||
<h2><?php esc_html_e( $this->_title ); ?></h2>
|
||||
<?php
|
||||
$force_check = rgget( 'force-check' ) == 1;
|
||||
$version_info = $this->get_version_info( $this->_slug, ! $force_check );
|
||||
|
||||
if ( ! $this->common->rgar( $version_info, 'is_valid_key' ) ) {
|
||||
?>
|
||||
<div class="gf_update_expired alert_red">
|
||||
<?php printf( esc_html__( '%sRegister%s your copy of %s to receive access to automatic updates and support. Need a license key? %sPurchase one now%s.', 'gravityforms' ), '<a href="admin.php?page=gf_settings">', '</a>', $this->_title, '<a href="https://www.gravityforms.com">', '</a>' ); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
} elseif ( version_compare( $this->_version, $version_info['version'], '<' ) ) {
|
||||
|
||||
if ( $this->common->rgar( $version_info, 'is_valid_key' ) ) {
|
||||
$plugin_file = $this->_path;
|
||||
$upgrade_url = wp_nonce_url( 'update.php?action=upgrade-plugin&plugin=' . urlencode( $plugin_file ), 'upgrade-plugin_' . $plugin_file );
|
||||
$details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . urlencode( $this->_slug ) . '§ion=changelog&TB_iframe=true&width=600&height=800' );
|
||||
$message_link_text = sprintf( esc_html__( 'View version %s details', 'gravityforms' ), $version_info['version'] );
|
||||
$message_link = sprintf( '<a href="%s" class="thickbox" title="%s">%s</a>', esc_url( $details_url ), esc_attr( $this->_title ), $message_link_text );
|
||||
$message = sprintf( esc_html__( 'There is a new version of %1$s available. %s.', 'gravityforms' ), $this->_title, $message_link );
|
||||
|
||||
?>
|
||||
<div class="gf_update_outdated alert_yellow">
|
||||
<?php echo $message . ' <p>' . sprintf( esc_html__( 'You can update to the latest version automatically or download the update and install it manually. %sUpdate Automatically%s %sDownload Update%s', 'gravityforms' ), "</p><a class='button-primary' href='{$upgrade_url}'>", '</a>', " <a class='button' href='{$version_info['url']}'>", '</a>' ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
|
||||
?>
|
||||
<div class="gf_update_current alert_green">
|
||||
<?php printf( esc_html__( 'Your version of %s is up to date.', 'gravityforms' ), $this->_title ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Upgrades;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Logging\Logger;
|
||||
|
||||
class Upgrade_Routines {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace;
|
||||
|
||||
protected $routines = array();
|
||||
|
||||
public function __construct( $namespace ) {
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
public function add( $key, $callback ) {
|
||||
$this->routines[ $key ] = $callback;
|
||||
}
|
||||
|
||||
public function remove( $key ) {
|
||||
unset( $this->routines[ $key ] );
|
||||
}
|
||||
|
||||
public function get( $key ) {
|
||||
return isset( $this->routines[ $key ] ) ? $this->routines[ $key ] : null;
|
||||
}
|
||||
|
||||
public function handle() {
|
||||
foreach( $this->routines as $key => $callback ) {
|
||||
$option_key = sprintf( '%s_upgrade_routine_%s', $this->namespace, $key );
|
||||
$handled = get_option( $option_key, false );
|
||||
|
||||
if ( $handled ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
call_user_func( $callback );
|
||||
|
||||
update_option( $option_key, true );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Vendored
+96
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Utils;
|
||||
|
||||
class Beltloop {
|
||||
|
||||
public static function sort( $data, $id_key = 'id', $sort_key = 'prevId' ) {
|
||||
$indexed = array();
|
||||
|
||||
foreach ( $data as $datum ) {
|
||||
$indexed[] = array(
|
||||
'sort_val' => $datum[ $sort_key ],
|
||||
'data' => $datum,
|
||||
);
|
||||
}
|
||||
|
||||
$sorted = array();
|
||||
|
||||
$current_index = 0;
|
||||
|
||||
while ( count( $indexed ) ) {
|
||||
$item_by_idx = self::get_matching_item_by_sort_key( $current_index, $indexed, $id_key );
|
||||
$current = $item_by_idx['data'];
|
||||
$sorted[] = $current;
|
||||
|
||||
unset( $indexed[ $item_by_idx['idx'] ] );
|
||||
$current_index = $current[ $id_key ];
|
||||
}
|
||||
|
||||
return $sorted;
|
||||
}
|
||||
|
||||
private static function get_matching_item_by_sort_key( $index, $items, $id_key = 'id' ) {
|
||||
$checked = array_filter( $items, function( $item ) use ( $index ) {
|
||||
return (int) $item['sort_val'] === (int) $index;
|
||||
} );
|
||||
|
||||
if ( ! empty( $checked ) ) {
|
||||
return array(
|
||||
'data' => $checked[ array_key_first( $checked ) ]['data'],
|
||||
'idx' => array_key_first( $checked ),
|
||||
);
|
||||
}
|
||||
|
||||
if ( (int) $index !== 0 ) {
|
||||
$heads = array_filter( $items, function( $item ) {
|
||||
$v = $item['sort_val'];
|
||||
return $v === null || $v === '' || (int) $v === 0;
|
||||
} );
|
||||
if ( ! empty( $heads ) ) {
|
||||
$first = $heads[ array_key_first( $heads ) ];
|
||||
return array(
|
||||
'data' => $first['data'],
|
||||
'idx' => array_key_first( $heads ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$min_id = null;
|
||||
$min_idx = null;
|
||||
$min_data = null;
|
||||
foreach ( $items as $idx => $item ) {
|
||||
$id = isset( $item['data'][ $id_key ] ) ? (int) $item['data'][ $id_key ] : 0;
|
||||
if ( $min_id === null || $id < $min_id ) {
|
||||
$min_id = $id;
|
||||
$min_idx = $idx;
|
||||
$min_data = $item['data'];
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'data' => $min_data,
|
||||
'idx' => $min_idx,
|
||||
);
|
||||
}
|
||||
|
||||
public static function partial_sort( $full_list, $partial_list, $id_key = 'id' ) {
|
||||
$indexed = array();
|
||||
|
||||
foreach ( $full_list as $item ) {
|
||||
$indexed[ $item[ $id_key ] ] = $item;
|
||||
}
|
||||
|
||||
$sorted = array();
|
||||
|
||||
foreach ( $partial_list as $part_item ) {
|
||||
$search = $part_item[ $id_key ];
|
||||
$pos = (int) array_search( $search, array_keys( $indexed ) );
|
||||
$sorted[ $pos ] = $part_item;
|
||||
}
|
||||
|
||||
ksort( $sorted );
|
||||
|
||||
return array_values( $sorted );
|
||||
}
|
||||
}
|
||||
Vendored
+185
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Utils;
|
||||
|
||||
use ArrayAccess;
|
||||
|
||||
class Bettarray implements ArrayAccess {
|
||||
|
||||
protected $array;
|
||||
|
||||
public function __construct( array $array ) {
|
||||
$this->array = $array;
|
||||
}
|
||||
|
||||
public function all() {
|
||||
return $this->array;
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetExists( $offset ) {
|
||||
return isset( $this->array[ $offset ] );
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet( $offset ) {
|
||||
return $this->get_nested_value( $offset );
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet( $offset, $value ) {
|
||||
if ( is_null( $offset ) ) {
|
||||
$this->array[] = $value;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->update_nested_value( $offset, $value );
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset( $offset ) {
|
||||
$this->delete_nested_value( $offset );
|
||||
}
|
||||
|
||||
public function get( $key ) {
|
||||
return $this->get_nested_value( $key );
|
||||
}
|
||||
|
||||
public function get_raw( $key ) {
|
||||
return $this->get_nested_value( $key, false );
|
||||
}
|
||||
|
||||
public function set( $key, $value ) {
|
||||
return $this->update_nested_value( $key, $value );
|
||||
}
|
||||
|
||||
public function delete( $key ) {
|
||||
return $this->delete_nested_value( $key );
|
||||
}
|
||||
|
||||
public function slice( $offset, $count ) {
|
||||
$data = $this->array;
|
||||
|
||||
$sliced = array_slice( $data, $offset, $count );
|
||||
|
||||
return new self( $sliced );
|
||||
}
|
||||
|
||||
public function pluck( $search_key, $raw = false ) {
|
||||
$results = array();
|
||||
|
||||
foreach( $this->array as $row ) {
|
||||
if ( isset( $row[ $search_key ]) ) {
|
||||
$results[] = $row[ $search_key ];
|
||||
}
|
||||
}
|
||||
|
||||
if ( $raw ) {
|
||||
return $results;
|
||||
}
|
||||
|
||||
return new self( $results );
|
||||
}
|
||||
|
||||
public function filter( callable $callback ) {
|
||||
$results = array();
|
||||
|
||||
foreach( $this->array as $row ) {
|
||||
$matched = call_user_func( $callback, $row );
|
||||
if ( $matched ) {
|
||||
$results[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return new self( $results );
|
||||
}
|
||||
|
||||
public function count() {
|
||||
return count( $this->array );
|
||||
}
|
||||
|
||||
public function dd() {
|
||||
var_dump( $this->array );
|
||||
die();
|
||||
}
|
||||
|
||||
public function dump() {
|
||||
var_dump( $this->array );
|
||||
}
|
||||
|
||||
public function append( $key, $value ) {
|
||||
$existing = $this->get_nested_value( $key, false );
|
||||
|
||||
if ( ! is_array( $existing ) ) {
|
||||
$existing = array();
|
||||
}
|
||||
|
||||
$existing[] = $value;
|
||||
|
||||
$this->update_nested_value( $key, $existing );
|
||||
}
|
||||
|
||||
public function amend( $key, $value ) {
|
||||
$existing = $this->get_nested_value( $key, false );
|
||||
|
||||
if ( ! is_array( $existing ) ) {
|
||||
$existing = array();
|
||||
}
|
||||
|
||||
$existing = array_merge( $existing, $value );
|
||||
|
||||
$this->update_nested_value( $key, $existing );
|
||||
}
|
||||
|
||||
private function get_nested_value( $key, $as_bettarray = true ) {
|
||||
$current = $this->array;
|
||||
$key_arr = explode( '.', $key );
|
||||
|
||||
while ( count( $key_arr ) ) {
|
||||
$new_key = array_shift( $key_arr );
|
||||
$current = isset( $current[ $new_key ] ) ? $current[ $new_key ] : array();
|
||||
}
|
||||
|
||||
if ( is_array( $current ) && $as_bettarray ) {
|
||||
return new self( $current );
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
private function update_nested_value( $key, $value ) {
|
||||
$current = &$this->array;
|
||||
$key_arr = explode( '.', $key );
|
||||
|
||||
while ( count( $key_arr ) ) {
|
||||
$new_key = array_shift( $key_arr );
|
||||
|
||||
if ( ! isset( $current[ $new_key ] ) ) {
|
||||
$current[ $new_key ] = array();
|
||||
}
|
||||
|
||||
$current = &$current[ $new_key ];
|
||||
}
|
||||
|
||||
$current = $value;
|
||||
}
|
||||
|
||||
private function delete_nested_value( $key ) {
|
||||
$current = &$this->array;
|
||||
$key_arr = explode( '.', $key );
|
||||
|
||||
while ( count( $key_arr ) > 1 ) {
|
||||
$new_key = array_shift( $key_arr );
|
||||
|
||||
if ( ! isset( $current[ $new_key ] ) ) {
|
||||
$current[ $new_key ] = array();
|
||||
}
|
||||
|
||||
$current = &$current[ $new_key ];
|
||||
}
|
||||
|
||||
$new_key = array_shift( $key_arr );
|
||||
|
||||
unset( $current[ $new_key ] );
|
||||
}
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace Gravity_Forms\Gravity_Tools\Utils;
|
||||
|
||||
class Booliesh {
|
||||
|
||||
public static function get( $value, $default = false ) {
|
||||
if ( is_string( $value ) ) {
|
||||
$value = strtolower( $value );
|
||||
}
|
||||
|
||||
if ( is_object( $value ) || is_array( $value ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ( $value === false || $value === 0 || $value === '0' || $value === 'no' || $value === 'off' || $value === 'false' || empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $value === true || $value === 1 || $value === '1' || $value === 'yes' || $value === 'on' || $value === 'true' || ! empty( $value ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+399
@@ -0,0 +1,399 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Utils;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\License\License_API_Connector;
|
||||
use Gravity_Forms\Gravity_Tools\License\License_Statuses;
|
||||
|
||||
class Common {
|
||||
|
||||
private static $plugins;
|
||||
|
||||
protected $gravity_manager_url;
|
||||
protected $support_url;
|
||||
protected $key;
|
||||
|
||||
public function __construct( $gravity_manager_url, $support_url, $key ) {
|
||||
$this->gravity_manager_url = $gravity_manager_url;
|
||||
$this->support_url = $support_url;
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the support URL
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_support_url() {
|
||||
return $this->support_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post request to Gravity Manager.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $file The file.
|
||||
* @param string $query The query string.
|
||||
* @param array $options The options.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function post_to_manager( $file, $query, $options ) {
|
||||
|
||||
if ( ! isset( $options['headers'] ) ) {
|
||||
$options['headers'] = array();
|
||||
}
|
||||
// Forcing Referer to the unfiltered home url when sending requests to gravity manager.
|
||||
$options['headers']['Referer'] = get_option( 'home' );
|
||||
|
||||
// Sending filtered version of URL so that gravity manager can remove duplicate URLs when filtered and unfiltered URLs are different.
|
||||
$options['headers']['Filtered-Site-URL'] = get_bloginfo( 'url' );
|
||||
|
||||
$request_url = $this->gravity_manager_url . '/' . $file . '?' . $query;
|
||||
$raw_response = wp_remote_post( $request_url, $options );
|
||||
|
||||
return $raw_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored license key.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_key() {
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw value from a SELECT version() db query.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string Returns the raw value from a SELECT version() or SELECT sqlite_version() db query.
|
||||
*/
|
||||
public static function get_dbms_version() {
|
||||
static $value;
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
global $wpdb;
|
||||
$value = $wpdb->get_var( 'SELECT version();' );
|
||||
|
||||
if ( ( get_class( $wpdb ) === 'WP_SQLite_DB' ) || $wpdb->last_error ) {
|
||||
$value = $wpdb->get_var( 'SELECT sqlite_version();' );
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current database management system.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string either MySQL, MariaDB, or SQLite.
|
||||
*/
|
||||
public static function get_dbms_type() {
|
||||
static $type;
|
||||
global $wpdb;
|
||||
|
||||
if ( empty( $type ) ) {
|
||||
$type = strpos( strtolower( self::get_dbms_version() ), 'mariadb' ) ? 'MariaDB' : 'MySQL';
|
||||
|
||||
if ( get_class( $wpdb ) === 'WP_SQLite_DB' ) {
|
||||
$type = 'SQLite';
|
||||
}
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total emails sent.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_emails_sent() {
|
||||
$count = get_option( 'gform_email_count' );
|
||||
|
||||
if ( ! $count ) {
|
||||
$count = 0;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of API calls.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_api_calls() {
|
||||
$count = get_option( 'gform_api_count' );
|
||||
|
||||
if ( ! $count ) {
|
||||
$count = 0;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the version of MySQL or MariaDB currently in use.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_db_version() {
|
||||
static $version;
|
||||
|
||||
if ( empty( $version ) ) {
|
||||
$version = preg_replace( '/[^0-9.].*/', '', self::get_dbms_version() );
|
||||
}
|
||||
|
||||
return $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserializes a string while suppressing errors, checks if the result is of the expected type.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $string The string to be unserialized.
|
||||
* @param string $expected The expected type after unserialization.
|
||||
* @param bool $default The default value to return if unserialization failed.
|
||||
*
|
||||
* @return false|mixed
|
||||
*/
|
||||
public static function safe_unserialize( $string, $expected, $default = false ) {
|
||||
|
||||
$data = is_string( $string ) ? @unserialize( $string ) : $string;
|
||||
|
||||
if ( is_a( $data, $expected ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the existence of a MySQL table.
|
||||
*
|
||||
* @since 1.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $table_name Table to check for.
|
||||
*
|
||||
* @uses wpdb::get_var()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function table_exists( $table_name ) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$count = $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
|
||||
return ! empty( $count );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for getting values from query strings or arrays
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $name The key
|
||||
* @param array $array The array to search through. If null, checks query strings. Defaults to null.
|
||||
*
|
||||
* @return string The value. If none found, empty string.
|
||||
*/
|
||||
public function rgget( $name, $array = null ) {
|
||||
if ( ! isset( $array ) ) {
|
||||
$array = $_GET;
|
||||
}
|
||||
|
||||
if ( ! is_array( $array ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( isset( $array[ $name ] ) ) {
|
||||
return $array[ $name ];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to obtain POST values.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $name The key
|
||||
* @param bool $do_stripslashes Optional. Performs stripslashes_deep. Defaults to true.
|
||||
*
|
||||
* @return string The value. If none found, empty string.
|
||||
*/
|
||||
public function rgpost( $name, $do_stripslashes = true ) {
|
||||
if ( isset( $_POST[ $name ] ) ) {
|
||||
return $do_stripslashes ? stripslashes_deep( $_POST[ $name ] ) : $_POST[ $name ];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific property of an array without needing to check if that property exists.
|
||||
*
|
||||
* Provide a default value if you want to return a specific value if the property is not set.
|
||||
*
|
||||
* @since 1.0
|
||||
* @access public
|
||||
*
|
||||
* @param array $array Array from which the property's value should be retrieved.
|
||||
* @param string $prop Name of the property to be retrieved.
|
||||
* @param string $default Optional. Value that should be returned if the property is not set or empty. Defaults to null.
|
||||
*
|
||||
* @return null|string|mixed The value
|
||||
*/
|
||||
public function rgar( $array, $prop, $default = null ) {
|
||||
|
||||
if ( ! is_array( $array ) && ! ( is_object( $array ) && $array instanceof ArrayAccess ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ( isset( $array[ $prop ] ) ) {
|
||||
$value = $array[ $prop ];
|
||||
} else {
|
||||
$value = '';
|
||||
}
|
||||
|
||||
return empty( $value ) && $default !== null ? $default : $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a specific property within a multidimensional array.
|
||||
*
|
||||
* @since 1.0
|
||||
* @access public
|
||||
*
|
||||
* @param array $array The array to search in.
|
||||
* @param string $name The name of the property to find.
|
||||
* @param string $default Optional. Value that should be returned if the property is not set or empty. Defaults to null.
|
||||
*
|
||||
* @return null|string|mixed The value
|
||||
*/
|
||||
public function rgars( $array, $name, $default = null ) {
|
||||
|
||||
if ( ! is_array( $array ) && ! ( is_object( $array ) && $array instanceof ArrayAccess ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$names = explode( '/', $name );
|
||||
$val = $array;
|
||||
foreach ( $names as $current_name ) {
|
||||
$val = $this->rgar( $val, $current_name, $default );
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if a value is empty.
|
||||
*
|
||||
* @since 1.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $name The property name to check.
|
||||
* @param array $array Optional. An array to check through. Otherwise, checks for POST variables.
|
||||
*
|
||||
* @return bool True if empty. False otherwise.
|
||||
*/
|
||||
public function rgempty( $name, $array = null ) {
|
||||
|
||||
if ( is_array( $name ) ) {
|
||||
return empty( $name );
|
||||
}
|
||||
|
||||
if ( ! $array ) {
|
||||
$array = $_POST;
|
||||
}
|
||||
|
||||
$val = $this->rgar( $array, $name );
|
||||
|
||||
return empty( $val );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the string is empty
|
||||
*
|
||||
* @since 1.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $text The string to check.
|
||||
*
|
||||
* @return bool True if empty. False otherwise.
|
||||
*/
|
||||
public function rgblank( $text ) {
|
||||
return empty( $text ) && ! is_array( $text ) && strval( $text ) != '0';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a property value from an object
|
||||
*
|
||||
* @since 1.0
|
||||
* @access public
|
||||
*
|
||||
* @param object $obj The object to check
|
||||
* @param string $name The property name to check for
|
||||
*
|
||||
* @return string The property value
|
||||
*/
|
||||
public function rgobj( $obj, $name ) {
|
||||
if ( isset( $obj->$name ) ) {
|
||||
return $obj->$name;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a delimiter separated string to an array.
|
||||
*
|
||||
* @since 1.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $sep The delimiter between values
|
||||
* @param string $string The string to convert
|
||||
* @param int $count The expected number of items in the resulting array
|
||||
*
|
||||
* @return array $ary The exploded array
|
||||
*/
|
||||
public function rgexplode( $sep, $string, $count ) {
|
||||
$ary = explode( $sep, $string );
|
||||
while ( count( $ary ) < $count ) {
|
||||
$ary[] = '';
|
||||
}
|
||||
|
||||
return $ary;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+708
@@ -0,0 +1,708 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Utils;
|
||||
|
||||
/**
|
||||
* Provides methods for retrieving lists of geological data.
|
||||
*
|
||||
* Each of the public methods allows two arguments:
|
||||
*
|
||||
* @param $as_json - bool - Whether the data should be returned as JSON instead of an array.
|
||||
* @param $process_callback - callable - An optional callback that takes the data as a parameter and returns a modified version.
|
||||
*/
|
||||
class GeoData {
|
||||
|
||||
/**
|
||||
* Provides a list of Countries organized by their 2-character country codes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function countries_list() {
|
||||
return array(
|
||||
'AF' => __( 'Afghanistan', 'gravitytools' ),
|
||||
'AX' => __( 'Åland Islands', 'gravitytools' ),
|
||||
'AL' => __( 'Albania', 'gravitytools' ),
|
||||
'DZ' => __( 'Algeria', 'gravitytools' ),
|
||||
'AS' => __( 'American Samoa', 'gravitytools' ),
|
||||
'AD' => __( 'Andorra', 'gravitytools' ),
|
||||
'AO' => __( 'Angola', 'gravitytools' ),
|
||||
'AI' => __( 'Anguilla', 'gravitytools' ),
|
||||
'AQ' => __( 'Antarctica', 'gravitytools' ),
|
||||
'AG' => __( 'Antigua and Barbuda', 'gravitytools' ),
|
||||
'AR' => __( 'Argentina', 'gravitytools' ),
|
||||
'AM' => __( 'Armenia', 'gravitytools' ),
|
||||
'AW' => __( 'Aruba', 'gravitytools' ),
|
||||
'AC' => __( 'Ascension Island', 'gravitytools' ),
|
||||
'AU' => __( 'Australia', 'gravitytools' ),
|
||||
'AT' => __( 'Austria', 'gravitytools' ),
|
||||
'AZ' => __( 'Azerbaijan', 'gravitytools' ),
|
||||
'BS' => __( 'Bahamas', 'gravitytools' ),
|
||||
'BH' => __( 'Bahrain', 'gravitytools' ),
|
||||
'BD' => __( 'Bangladesh', 'gravitytools' ),
|
||||
'BB' => __( 'Barbados', 'gravitytools' ),
|
||||
'BY' => __( 'Belarus', 'gravitytools' ),
|
||||
'BE' => __( 'Belgium', 'gravitytools' ),
|
||||
'PW' => __( 'Belau', 'gravitytools' ),
|
||||
'BZ' => __( 'Belize', 'gravitytools' ),
|
||||
'BJ' => __( 'Benin', 'gravitytools' ),
|
||||
'BM' => __( 'Bermuda', 'gravitytools' ),
|
||||
'BT' => __( 'Bhutan', 'gravitytools' ),
|
||||
'BO' => __( 'Bolivia', 'gravitytools' ),
|
||||
'BQ' => __( 'Bonaire, Saint Eustatius and Saba', 'gravitytools' ),
|
||||
'BA' => __( 'Bosnia and Herzegovina', 'gravitytools' ),
|
||||
'BW' => __( 'Botswana', 'gravitytools' ),
|
||||
'BV' => __( 'Bouvet Island', 'gravitytools' ),
|
||||
'BR' => __( 'Brazil', 'gravitytools' ),
|
||||
'IO' => __( 'British Indian Ocean Territory', 'gravitytools' ),
|
||||
'BN' => __( 'Brunei', 'gravitytools' ),
|
||||
'BG' => __( 'Bulgaria', 'gravitytools' ),
|
||||
'BF' => __( 'Burkina Faso', 'gravitytools' ),
|
||||
'BI' => __( 'Burundi', 'gravitytools' ),
|
||||
'KH' => __( 'Cambodia', 'gravitytools' ),
|
||||
'CM' => __( 'Cameroon', 'gravitytools' ),
|
||||
'CA' => __( 'Canada', 'gravitytools' ),
|
||||
'CV' => __( 'Cape Verde', 'gravitytools' ),
|
||||
'KY' => __( 'Cayman Islands', 'gravitytools' ),
|
||||
'CF' => __( 'Central African Republic', 'gravitytools' ),
|
||||
'TD' => __( 'Chad', 'gravitytools' ),
|
||||
'CL' => __( 'Chile', 'gravitytools' ),
|
||||
'CN' => __( 'China', 'gravitytools' ),
|
||||
'CX' => __( 'Christmas Island', 'gravitytools' ),
|
||||
'CC' => __( 'Cocos (Keeling) Islands', 'gravitytools' ),
|
||||
'CO' => __( 'Colombia', 'gravitytools' ),
|
||||
'KM' => __( 'Comoros', 'gravitytools' ),
|
||||
'CG' => __( 'Congo (Brazzaville)', 'gravitytools' ),
|
||||
'CD' => __( 'Congo (Kinshasa)', 'gravitytools' ),
|
||||
'CK' => __( 'Cook Islands', 'gravitytools' ),
|
||||
'CR' => __( 'Costa Rica', 'gravitytools' ),
|
||||
'HR' => __( 'Croatia', 'gravitytools' ),
|
||||
'CU' => __( 'Cuba', 'gravitytools' ),
|
||||
'CW' => __( 'Curaçao', 'gravitytools' ),
|
||||
'CY' => __( 'Cyprus', 'gravitytools' ),
|
||||
'CZ' => __( 'Czech Republic', 'gravitytools' ),
|
||||
'DK' => __( 'Denmark', 'gravitytools' ),
|
||||
'DJ' => __( 'Djibouti', 'gravitytools' ),
|
||||
'DM' => __( 'Dominica', 'gravitytools' ),
|
||||
'DO' => __( 'Dominican Republic', 'gravitytools' ),
|
||||
'EC' => __( 'Ecuador', 'gravitytools' ),
|
||||
'EG' => __( 'Egypt', 'gravitytools' ),
|
||||
'SV' => __( 'El Salvador', 'gravitytools' ),
|
||||
'GQ' => __( 'Equatorial Guinea', 'gravitytools' ),
|
||||
'ER' => __( 'Eritrea', 'gravitytools' ),
|
||||
'EE' => __( 'Estonia', 'gravitytools' ),
|
||||
'ET' => __( 'Ethiopia', 'gravitytools' ),
|
||||
'FK' => __( 'Falkland Islands', 'gravitytools' ),
|
||||
'FO' => __( 'Faroe Islands', 'gravitytools' ),
|
||||
'FJ' => __( 'Fiji', 'gravitytools' ),
|
||||
'FI' => __( 'Finland', 'gravitytools' ),
|
||||
'FR' => __( 'France', 'gravitytools' ),
|
||||
'GF' => __( 'French Guiana', 'gravitytools' ),
|
||||
'PF' => __( 'French Polynesia', 'gravitytools' ),
|
||||
'TF' => __( 'French Southern Territories', 'gravitytools' ),
|
||||
'GA' => __( 'Gabon', 'gravitytools' ),
|
||||
'GM' => __( 'Gambia', 'gravitytools' ),
|
||||
'GE' => __( 'Georgia', 'gravitytools' ),
|
||||
'DE' => __( 'Germany', 'gravitytools' ),
|
||||
'GH' => __( 'Ghana', 'gravitytools' ),
|
||||
'GI' => __( 'Gibraltar', 'gravitytools' ),
|
||||
'GR' => __( 'Greece', 'gravitytools' ),
|
||||
'GL' => __( 'Greenland', 'gravitytools' ),
|
||||
'GD' => __( 'Grenada', 'gravitytools' ),
|
||||
'GP' => __( 'Guadeloupe', 'gravitytools' ),
|
||||
'GU' => __( 'Guam', 'gravitytools' ),
|
||||
'GT' => __( 'Guatemala', 'gravitytools' ),
|
||||
'GG' => __( 'Guernsey', 'gravitytools' ),
|
||||
'GN' => __( 'Guinea', 'gravitytools' ),
|
||||
'GW' => __( 'Guinea-Bissau', 'gravitytools' ),
|
||||
'GY' => __( 'Guyana', 'gravitytools' ),
|
||||
'HT' => __( 'Haiti', 'gravitytools' ),
|
||||
'HM' => __( 'Heard Island and McDonald Islands', 'gravitytools' ),
|
||||
'HN' => __( 'Honduras', 'gravitytools' ),
|
||||
'HK' => __( 'Hong Kong', 'gravitytools' ),
|
||||
'HU' => __( 'Hungary', 'gravitytools' ),
|
||||
'IS' => __( 'Iceland', 'gravitytools' ),
|
||||
'IN' => __( 'India', 'gravitytools' ),
|
||||
'ID' => __( 'Indonesia', 'gravitytools' ),
|
||||
'IR' => __( 'Iran', 'gravitytools' ),
|
||||
'IQ' => __( 'Iraq', 'gravitytools' ),
|
||||
'IE' => __( 'Ireland', 'gravitytools' ),
|
||||
'IM' => __( 'Isle of Man', 'gravitytools' ),
|
||||
'IL' => __( 'Israel', 'gravitytools' ),
|
||||
'IT' => __( 'Italy', 'gravitytools' ),
|
||||
'CI' => __( 'Ivory Coast', 'gravitytools' ),
|
||||
'JM' => __( 'Jamaica', 'gravitytools' ),
|
||||
'JP' => __( 'Japan', 'gravitytools' ),
|
||||
'JE' => __( 'Jersey', 'gravitytools' ),
|
||||
'JO' => __( 'Jordan', 'gravitytools' ),
|
||||
'KZ' => __( 'Kazakhstan', 'gravitytools' ),
|
||||
'KE' => __( 'Kenya', 'gravitytools' ),
|
||||
'KI' => __( 'Kiribati', 'gravitytools' ),
|
||||
'XK' => __( 'Kosovo', 'gravitytools' ),
|
||||
'KW' => __( 'Kuwait', 'gravitytools' ),
|
||||
'KG' => __( 'Kyrgyzstan', 'gravitytools' ),
|
||||
'LA' => __( 'Laos', 'gravitytools' ),
|
||||
'LV' => __( 'Latvia', 'gravitytools' ),
|
||||
'LB' => __( 'Lebanon', 'gravitytools' ),
|
||||
'LS' => __( 'Lesotho', 'gravitytools' ),
|
||||
'LR' => __( 'Liberia', 'gravitytools' ),
|
||||
'LY' => __( 'Libya', 'gravitytools' ),
|
||||
'LI' => __( 'Liechtenstein', 'gravitytools' ),
|
||||
'LT' => __( 'Lithuania', 'gravitytools' ),
|
||||
'LU' => __( 'Luxembourg', 'gravitytools' ),
|
||||
'MO' => __( 'Macao', 'gravitytools' ),
|
||||
'MK' => __( 'North Macedonia', 'gravitytools' ),
|
||||
'MG' => __( 'Madagascar', 'gravitytools' ),
|
||||
'MW' => __( 'Malawi', 'gravitytools' ),
|
||||
'MY' => __( 'Malaysia', 'gravitytools' ),
|
||||
'MV' => __( 'Maldives', 'gravitytools' ),
|
||||
'ML' => __( 'Mali', 'gravitytools' ),
|
||||
'MT' => __( 'Malta', 'gravitytools' ),
|
||||
'MH' => __( 'Marshall Islands', 'gravitytools' ),
|
||||
'MQ' => __( 'Martinique', 'gravitytools' ),
|
||||
'MR' => __( 'Mauritania', 'gravitytools' ),
|
||||
'MU' => __( 'Mauritius', 'gravitytools' ),
|
||||
'YT' => __( 'Mayotte', 'gravitytools' ),
|
||||
'MX' => __( 'Mexico', 'gravitytools' ),
|
||||
'FM' => __( 'Micronesia', 'gravitytools' ),
|
||||
'MD' => __( 'Moldova', 'gravitytools' ),
|
||||
'MC' => __( 'Monaco', 'gravitytools' ),
|
||||
'MN' => __( 'Mongolia', 'gravitytools' ),
|
||||
'ME' => __( 'Montenegro', 'gravitytools' ),
|
||||
'MS' => __( 'Montserrat', 'gravitytools' ),
|
||||
'MA' => __( 'Morocco', 'gravitytools' ),
|
||||
'MZ' => __( 'Mozambique', 'gravitytools' ),
|
||||
'MM' => __( 'Myanmar', 'gravitytools' ),
|
||||
'NA' => __( 'Namibia', 'gravitytools' ),
|
||||
'NR' => __( 'Nauru', 'gravitytools' ),
|
||||
'NP' => __( 'Nepal', 'gravitytools' ),
|
||||
'NL' => __( 'Netherlands', 'gravitytools' ),
|
||||
'NC' => __( 'New Caledonia', 'gravitytools' ),
|
||||
'NZ' => __( 'New Zealand', 'gravitytools' ),
|
||||
'NI' => __( 'Nicaragua', 'gravitytools' ),
|
||||
'NE' => __( 'Niger', 'gravitytools' ),
|
||||
'NG' => __( 'Nigeria', 'gravitytools' ),
|
||||
'NU' => __( 'Niue', 'gravitytools' ),
|
||||
'NF' => __( 'Norfolk Island', 'gravitytools' ),
|
||||
'MP' => __( 'Northern Mariana Islands', 'gravitytools' ),
|
||||
'KP' => __( 'North Korea', 'gravitytools' ),
|
||||
'NO' => __( 'Norway', 'gravitytools' ),
|
||||
'OM' => __( 'Oman', 'gravitytools' ),
|
||||
'PK' => __( 'Pakistan', 'gravitytools' ),
|
||||
'PS' => __( 'Palestinian Territory', 'gravitytools' ),
|
||||
'PA' => __( 'Panama', 'gravitytools' ),
|
||||
'PG' => __( 'Papua New Guinea', 'gravitytools' ),
|
||||
'PY' => __( 'Paraguay', 'gravitytools' ),
|
||||
'PE' => __( 'Peru', 'gravitytools' ),
|
||||
'PH' => __( 'Philippines', 'gravitytools' ),
|
||||
'PN' => __( 'Pitcairn', 'gravitytools' ),
|
||||
'PL' => __( 'Poland', 'gravitytools' ),
|
||||
'PT' => __( 'Portugal', 'gravitytools' ),
|
||||
'PR' => __( 'Puerto Rico', 'gravitytools' ),
|
||||
'QA' => __( 'Qatar', 'gravitytools' ),
|
||||
'RE' => __( 'Reunion', 'gravitytools' ),
|
||||
'RO' => __( 'Romania', 'gravitytools' ),
|
||||
'RU' => __( 'Russia', 'gravitytools' ),
|
||||
'RW' => __( 'Rwanda', 'gravitytools' ),
|
||||
'BL' => __( 'Saint Barthélemy', 'gravitytools' ),
|
||||
'SH' => __( 'Saint Helena', 'gravitytools' ),
|
||||
'KN' => __( 'Saint Kitts and Nevis', 'gravitytools' ),
|
||||
'LC' => __( 'Saint Lucia', 'gravitytools' ),
|
||||
'MF' => __( 'Saint Martin (French part)', 'gravitytools' ),
|
||||
'SX' => __( 'Saint Martin (Dutch part)', 'gravitytools' ),
|
||||
'PM' => __( 'Saint Pierre and Miquelon', 'gravitytools' ),
|
||||
'VC' => __( 'Saint Vincent and the Grenadines', 'gravitytools' ),
|
||||
'SM' => __( 'San Marino', 'gravitytools' ),
|
||||
'ST' => __( 'São Tomé and Príncipe', 'gravitytools' ),
|
||||
'SA' => __( 'Saudi Arabia', 'gravitytools' ),
|
||||
'SN' => __( 'Senegal', 'gravitytools' ),
|
||||
'RS' => __( 'Serbia', 'gravitytools' ),
|
||||
'SC' => __( 'Seychelles', 'gravitytools' ),
|
||||
'SL' => __( 'Sierra Leone', 'gravitytools' ),
|
||||
'SG' => __( 'Singapore', 'gravitytools' ),
|
||||
'SK' => __( 'Slovakia', 'gravitytools' ),
|
||||
'SI' => __( 'Slovenia', 'gravitytools' ),
|
||||
'SB' => __( 'Solomon Islands', 'gravitytools' ),
|
||||
'SO' => __( 'Somalia', 'gravitytools' ),
|
||||
'ZA' => __( 'South Africa', 'gravitytools' ),
|
||||
'GS' => __( 'South Georgia/Sandwich Islands', 'gravitytools' ),
|
||||
'KR' => __( 'South Korea', 'gravitytools' ),
|
||||
'SS' => __( 'South Sudan', 'gravitytools' ),
|
||||
'ES' => __( 'Spain', 'gravitytools' ),
|
||||
'LK' => __( 'Sri Lanka', 'gravitytools' ),
|
||||
'SD' => __( 'Sudan', 'gravitytools' ),
|
||||
'SR' => __( 'Suriname', 'gravitytools' ),
|
||||
'SJ' => __( 'Svalbard and Jan Mayen', 'gravitytools' ),
|
||||
'SZ' => __( 'Eswatini', 'gravitytools' ),
|
||||
'SE' => __( 'Sweden', 'gravitytools' ),
|
||||
'CH' => __( 'Switzerland', 'gravitytools' ),
|
||||
'SY' => __( 'Syria', 'gravitytools' ),
|
||||
'TW' => __( 'Taiwan', 'gravitytools' ),
|
||||
'TJ' => __( 'Tajikistan', 'gravitytools' ),
|
||||
'TZ' => __( 'Tanzania', 'gravitytools' ),
|
||||
'TH' => __( 'Thailand', 'gravitytools' ),
|
||||
'TL' => __( 'Timor-Leste', 'gravitytools' ),
|
||||
'TG' => __( 'Togo', 'gravitytools' ),
|
||||
'TK' => __( 'Tokelau', 'gravitytools' ),
|
||||
'TO' => __( 'Tonga', 'gravitytools' ),
|
||||
'TT' => __( 'Trinidad and Tobago', 'gravitytools' ),
|
||||
'TN' => __( 'Tunisia', 'gravitytools' ),
|
||||
'TR' => __( 'Turkey', 'gravitytools' ),
|
||||
'TM' => __( 'Turkmenistan', 'gravitytools' ),
|
||||
'TC' => __( 'Turks and Caicos Islands', 'gravitytools' ),
|
||||
'TV' => __( 'Tuvalu', 'gravitytools' ),
|
||||
'UG' => __( 'Uganda', 'gravitytools' ),
|
||||
'UA' => __( 'Ukraine', 'gravitytools' ),
|
||||
'AE' => __( 'United Arab Emirates', 'gravitytools' ),
|
||||
'GB' => __( 'United Kingdom (UK)', 'gravitytools' ),
|
||||
'US' => __( 'United States (US)', 'gravitytools' ),
|
||||
'UM' => __( 'United States (US) Minor Outlying Islands', 'gravitytools' ),
|
||||
'UY' => __( 'Uruguay', 'gravitytools' ),
|
||||
'UZ' => __( 'Uzbekistan', 'gravitytools' ),
|
||||
'VU' => __( 'Vanuatu', 'gravitytools' ),
|
||||
'VA' => __( 'Vatican', 'gravitytools' ),
|
||||
'VE' => __( 'Venezuela', 'gravitytools' ),
|
||||
'VN' => __( 'Vietnam', 'gravitytools' ),
|
||||
'VG' => __( 'Virgin Islands (British)', 'gravitytools' ),
|
||||
'VI' => __( 'Virgin Islands (US)', 'gravitytools' ),
|
||||
'WF' => __( 'Wallis and Futuna', 'gravitytools' ),
|
||||
'EH' => __( 'Western Sahara', 'gravitytools' ),
|
||||
'WS' => __( 'Samoa', 'gravitytools' ),
|
||||
'YE' => __( 'Yemen', 'gravitytools' ),
|
||||
'ZM' => __( 'Zambia', 'gravitytools' ),
|
||||
'ZW' => __( 'Zimbabwe', 'gravitytools' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of US states organized by their two-character state code.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function states_list() {
|
||||
return array(
|
||||
'AL' => __( 'Alabama', 'gravitytools' ),
|
||||
'AK' => __( 'Alaska', 'gravitytools' ),
|
||||
'AZ' => __( 'Arizona', 'gravitytools' ),
|
||||
'AR' => __( 'Arkansas', 'gravitytools' ),
|
||||
'CA' => __( 'California', 'gravitytools' ),
|
||||
'CO' => __( 'Colorado', 'gravitytools' ),
|
||||
'CT' => __( 'Connecticut', 'gravitytools' ),
|
||||
'DE' => __( 'Delaware', 'gravitytools' ),
|
||||
'DC' => __( 'District of Columbia', 'gravitytools' ),
|
||||
'FL' => __( 'Florida', 'gravitytools' ),
|
||||
'GA' => __( 'Georgia', 'gravitytools' ),
|
||||
'HI' => __( 'Hawaii', 'gravitytools' ),
|
||||
'ID' => __( 'Idaho', 'gravitytools' ),
|
||||
'IL' => __( 'Illinois', 'gravitytools' ),
|
||||
'IN' => __( 'Indiana', 'gravitytools' ),
|
||||
'IA' => __( 'Iowa', 'gravitytools' ),
|
||||
'KS' => __( 'Kansas', 'gravitytools' ),
|
||||
'KY' => __( 'Kentucky', 'gravitytools' ),
|
||||
'LA' => __( 'Louisiana', 'gravitytools' ),
|
||||
'ME' => __( 'Maine', 'gravitytools' ),
|
||||
'MD' => __( 'Maryland', 'gravitytools' ),
|
||||
'MA' => __( 'Massachusetts', 'gravitytools' ),
|
||||
'MI' => __( 'Michigan', 'gravitytools' ),
|
||||
'MN' => __( 'Minnesota', 'gravitytools' ),
|
||||
'MS' => __( 'Mississippi', 'gravitytools' ),
|
||||
'MO' => __( 'Missouri', 'gravitytools' ),
|
||||
'MT' => __( 'Montana', 'gravitytools' ),
|
||||
'NE' => __( 'Nebraska', 'gravitytools' ),
|
||||
'NV' => __( 'Nevada', 'gravitytools' ),
|
||||
'NH' => __( 'New Hampshire', 'gravitytools' ),
|
||||
'NJ' => __( 'New Jersey', 'gravitytools' ),
|
||||
'NM' => __( 'New Mexico', 'gravitytools' ),
|
||||
'NY' => __( 'New York', 'gravitytools' ),
|
||||
'NC' => __( 'North Carolina', 'gravitytools' ),
|
||||
'ND' => __( 'North Dakota', 'gravitytools' ),
|
||||
'OH' => __( 'Ohio', 'gravitytools' ),
|
||||
'OK' => __( 'Oklahoma', 'gravitytools' ),
|
||||
'OR' => __( 'Oregon', 'gravitytools' ),
|
||||
'PA' => __( 'Pennsylvania', 'gravitytools' ),
|
||||
'RI' => __( 'Rhode Island', 'gravitytools' ),
|
||||
'SC' => __( 'South Carolina', 'gravitytools' ),
|
||||
'SD' => __( 'South Dakota', 'gravitytools' ),
|
||||
'TN' => __( 'Tennessee', 'gravitytools' ),
|
||||
'TX' => __( 'Texas', 'gravitytools' ),
|
||||
'UT' => __( 'Utah', 'gravitytools' ),
|
||||
'VT' => __( 'Vermont', 'gravitytools' ),
|
||||
'VA' => __( 'Virginia', 'gravitytools' ),
|
||||
'WA' => __( 'Washington', 'gravitytools' ),
|
||||
'WV' => __( 'West Virginia', 'gravitytools' ),
|
||||
'WI' => __( 'Wisconsin', 'gravitytools' ),
|
||||
'WY' => __( 'Wyoming', 'gravitytools' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of Canadian provinces, organized by their two-character province code.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function provinces_list() {
|
||||
return array(
|
||||
'AB' => __( 'Alberta', 'gravitytools' ),
|
||||
'BC' => __( 'British Columbia', 'gravitytools' ),
|
||||
'MB' => __( 'Manitoba', 'gravitytools' ),
|
||||
'NB' => __( 'New Brunswick', 'gravitytools' ),
|
||||
'NL' => __( 'Newfoundland and Labrador', 'gravitytools' ),
|
||||
'NS' => __( 'Nova Scotia', 'gravitytools' ),
|
||||
'NT' => __( 'Northwest Territories', 'gravitytools' ),
|
||||
'NU' => __( 'Nunavut', 'gravitytools' ),
|
||||
'ON' => __( 'Ontario', 'gravitytools' ),
|
||||
'PE' => __( 'Prince Edward Island', 'gravitytools' ),
|
||||
'QC' => __( 'Quebec', 'gravitytools' ),
|
||||
'SK' => __( 'Saskatchewan', 'gravitytools' ),
|
||||
'YT' => __( 'Yukon', 'gravitytools' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of phone number formatting info.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function phone_list() {
|
||||
$countries = self::countries_list();
|
||||
|
||||
$data = array(
|
||||
array( 'AF', '93', '🇦🇫' ),
|
||||
array( 'AX', '358', '🇦🇽' ),
|
||||
array( 'AL', '355', '🇦🇱' ),
|
||||
array( 'DZ', '213', '🇩🇿' ),
|
||||
array( 'AS', '1', '🇦🇸' ),
|
||||
array( 'AD', '376', '🇦🇩' ),
|
||||
array( 'AO', '244', '🇦🇴' ),
|
||||
array( 'AI', '1', '🇦🇮' ),
|
||||
array( 'AG', '1', '🇦🇬' ),
|
||||
array( 'AR', '54', '🇦🇷' ),
|
||||
array( 'AM', '374', '🇦🇲' ),
|
||||
array( 'AW', '297', '🇦🇼' ),
|
||||
array( 'AC', '247', '🇦🇨' ),
|
||||
array( 'AU', '61', '🇦🇺' ),
|
||||
array( 'AT', '43', '🇦🇹' ),
|
||||
array( 'AZ', '994', '🇦🇿' ),
|
||||
array( 'BS', '1', '🇧🇸' ),
|
||||
array( 'BH', '973', '🇧🇭' ),
|
||||
array( 'BD', '880', '🇧🇩' ),
|
||||
array( 'BB', '1', '🇧🇧' ),
|
||||
array( 'BY', '375', '🇧🇾' ),
|
||||
array( 'BE', '32', '🇧🇪' ),
|
||||
array( 'BZ', '501', '🇧🇿' ),
|
||||
array( 'BJ', '229', '🇧🇯' ),
|
||||
array( 'BM', '1', '🇧🇲' ),
|
||||
array( 'BT', '975', '🇧🇹' ),
|
||||
array( 'BO', '591', '🇧🇴' ),
|
||||
array( 'BA', '387', '🇧🇦' ),
|
||||
array( 'BW', '267', '🇧🇼' ),
|
||||
array( 'BR', '55', '🇧🇷' ),
|
||||
array( 'IO', '246', '🇮🇴' ),
|
||||
array( 'VG', '1', '🇻🇬' ),
|
||||
array( 'BN', '673', '🇧🇳' ),
|
||||
array( 'BG', '359', '🇧🇬' ),
|
||||
array( 'BF', '226', '🇧🇫' ),
|
||||
array( 'BI', '257', '🇧🇮' ),
|
||||
array( 'KH', '855', '🇰🇭' ),
|
||||
array( 'CM', '237', '🇨🇲' ),
|
||||
array( 'CA', '1', '🇨🇦' ),
|
||||
array( 'CV', '238', '🇨🇻' ),
|
||||
array( 'BQ', '599', '🇧🇶' ),
|
||||
array( 'KY', '1', '🇰🇾' ),
|
||||
array( 'CF', '236', '🇨🇫' ),
|
||||
array( 'TD', '235', '🇹🇩' ),
|
||||
array( 'CL', '56', '🇨🇱' ),
|
||||
array( 'CN', '86', '🇨🇳' ),
|
||||
array( 'CX', '61', '🇨🇽' ),
|
||||
array( 'CC', '61', '🇨🇨' ),
|
||||
array( 'CO', '57', '🇨🇴' ),
|
||||
array( 'KM', '269', '🇰🇲' ),
|
||||
array( 'CG', '242', '🇨🇬' ),
|
||||
array( 'CD', '243', '🇨🇩' ),
|
||||
array( 'CK', '682', '🇨🇰' ),
|
||||
array( 'CR', '506', '🇨🇷' ),
|
||||
array( 'CI', '225', '🇨🇮' ),
|
||||
array( 'HR', '385', '🇭🇷' ),
|
||||
array( 'CU', '53', '🇨🇺' ),
|
||||
array( 'CW', '599', '🇨🇼' ),
|
||||
array( 'CY', '357', '🇨🇾' ),
|
||||
array( 'CZ', '420', '🇨🇿' ),
|
||||
array( 'DK', '45', '🇩🇰' ),
|
||||
array( 'DJ', '253', '🇩🇯' ),
|
||||
array( 'DM', '1', '🇩🇲' ),
|
||||
array( 'DO', '1', '🇩🇴' ),
|
||||
array( 'EC', '593', '🇪🇨' ),
|
||||
array( 'EG', '20', '🇪🇬' ),
|
||||
array( 'SV', '503', '🇸🇻' ),
|
||||
array( 'GQ', '240', '🇬🇶' ),
|
||||
array( 'ER', '291', '🇪🇷' ),
|
||||
array( 'EE', '372', '🇪🇪' ),
|
||||
array( 'SZ', '268', '🇸🇿' ),
|
||||
array( 'ET', '251', '🇪🇹' ),
|
||||
array( 'FK', '500', '🇫🇰' ),
|
||||
array( 'FO', '298', '🇫🇴' ),
|
||||
array( 'FJ', '679', '🇫🇯' ),
|
||||
array( 'FI', '358', '🇫🇮' ),
|
||||
array( 'FR', '33', '🇫🇷' ),
|
||||
array( 'GF', '594', '🇬🇫' ),
|
||||
array( 'PF', '689', '🇵🇫' ),
|
||||
array( 'GA', '241', '🇬🇦' ),
|
||||
array( 'GM', '220', '🇬🇲' ),
|
||||
array( 'GE', '995', '🇬🇪' ),
|
||||
array( 'DE', '49', '🇩🇪' ),
|
||||
array( 'GH', '233', '🇬🇭' ),
|
||||
array( 'GI', '350', '🇬🇮' ),
|
||||
array( 'GR', '30', '🇬🇷' ),
|
||||
array( 'GL', '299', '🇬🇱' ),
|
||||
array( 'GD', '1', '🇬🇩' ),
|
||||
array( 'GP', '590', '🇬🇵' ),
|
||||
array( 'GU', '1', '🇬🇺' ),
|
||||
array( 'GT', '502', '🇬🇹' ),
|
||||
array( 'GG', '44', '🇬🇬' ),
|
||||
array( 'GN', '224', '🇬🇳' ),
|
||||
array( 'GW', '245', '🇬🇼' ),
|
||||
array( 'GY', '592', '🇬🇾' ),
|
||||
array( 'HT', '509', '🇭🇹' ),
|
||||
array( 'HN', '504', '🇭🇳' ),
|
||||
array( 'HK', '852', '🇭🇰' ),
|
||||
array( 'HU', '36', '🇭🇺' ),
|
||||
array( 'IS', '354', '🇮🇸' ),
|
||||
array( 'IN', '91', '🇮🇳' ),
|
||||
array( 'ID', '62', '🇮🇩' ),
|
||||
array( 'IR', '98', '🇮🇷' ),
|
||||
array( 'IQ', '964', '🇮🇶' ),
|
||||
array( 'IE', '353', '🇮🇪' ),
|
||||
array( 'IM', '44', '🇮🇲' ),
|
||||
array( 'IL', '972', '🇮🇱' ),
|
||||
array( 'IT', '39', '🇮🇹' ),
|
||||
array( 'JM', '1', '🇯🇲' ),
|
||||
array( 'JP', '81', '🇯🇵' ),
|
||||
array( 'JE', '44', '🇯🇪' ),
|
||||
array( 'JO', '962', '🇯🇴' ),
|
||||
array( 'KZ', '7', '🇰🇿' ),
|
||||
array( 'KE', '254', '🇰🇪' ),
|
||||
array( 'KI', '686', '🇰🇮' ),
|
||||
array( 'XK', '383', '🇽🇰' ),
|
||||
array( 'KW', '965', '🇰🇼' ),
|
||||
array( 'KG', '996', '🇰🇬' ),
|
||||
array( 'LA', '856', '🇱🇦' ),
|
||||
array( 'LV', '371', '🇱🇻' ),
|
||||
array( 'LB', '961', '🇱🇧' ),
|
||||
array( 'LS', '266', '🇱🇸' ),
|
||||
array( 'LR', '231', '🇱🇷' ),
|
||||
array( 'LY', '218', '🇱🇾' ),
|
||||
array( 'LI', '423', '🇱🇮' ),
|
||||
array( 'LT', '370', '🇱🇹' ),
|
||||
array( 'LU', '352', '🇱🇺' ),
|
||||
array( 'MO', '853', '🇲🇴' ),
|
||||
array( 'MG', '261', '🇲🇬' ),
|
||||
array( 'MW', '265', '🇲🇼' ),
|
||||
array( 'MY', '60', '🇲🇾' ),
|
||||
array( 'MV', '960', '🇲🇻' ),
|
||||
array( 'ML', '223', '🇲🇱' ),
|
||||
array( 'MT', '356', '🇲🇹' ),
|
||||
array( 'MH', '692', '🇲🇭' ),
|
||||
array( 'MQ', '596', '🇲🇶' ),
|
||||
array( 'MR', '222', '🇲🇷' ),
|
||||
array( 'MU', '230', '🇲🇺' ),
|
||||
array( 'YT', '262', '🇾🇹' ),
|
||||
array( 'MX', '52', '🇲🇽' ),
|
||||
array( 'FM', '691', '🇫🇲' ),
|
||||
array( 'MD', '373', '🇲🇩' ),
|
||||
array( 'MC', '377', '🇲🇨' ),
|
||||
array( 'MN', '976', '🇲🇳' ),
|
||||
array( 'ME', '382', '🇲🇪' ),
|
||||
array( 'MS', '1', '🇲🇸' ),
|
||||
array( 'MA', '212', '🇲🇦' ),
|
||||
array( 'MZ', '258', '🇲🇿' ),
|
||||
array( 'MM', '95', '🇲🇲' ),
|
||||
array( 'NA', '264', '🇳🇦' ),
|
||||
array( 'NR', '674', '🇳🇷' ),
|
||||
array( 'NP', '977', '🇳🇵' ),
|
||||
array( 'NL', '31', '🇳🇱' ),
|
||||
array( 'NC', '687', '🇳🇨' ),
|
||||
array( 'NZ', '64', '🇳🇿' ),
|
||||
array( 'NI', '505', '🇳🇮' ),
|
||||
array( 'NE', '227', '🇳🇪' ),
|
||||
array( 'NG', '234', '🇳🇬' ),
|
||||
array( 'NU', '683', '🇳🇺' ),
|
||||
array( 'NF', '672', '🇳🇫' ),
|
||||
array( 'KP', '850', '🇰🇵' ),
|
||||
array( 'MK', '389', '🇲🇰' ),
|
||||
array( 'MP', '1', '🇲🇵' ),
|
||||
array( 'NO', '47', '🇳🇴' ),
|
||||
array( 'OM', '968', '🇴🇲' ),
|
||||
array( 'PK', '92', '🇵🇰' ),
|
||||
array( 'PW', '680', '🇵🇼' ),
|
||||
array( 'PS', '970', '🇵🇸' ),
|
||||
array( 'PA', '507', '🇵🇦' ),
|
||||
array( 'PG', '675', '🇵🇬' ),
|
||||
array( 'PY', '595', '🇵🇾' ),
|
||||
array( 'PE', '51', '🇵🇪' ),
|
||||
array( 'PH', '63', '🇵🇭' ),
|
||||
array( 'PL', '48', '🇵🇱' ),
|
||||
array( 'PT', '351', '🇵🇹' ),
|
||||
array( 'PR', '1', '🇵🇷' ),
|
||||
array( 'QA', '974', '🇶🇦' ),
|
||||
array( 'RE', '262', '🇷🇪' ),
|
||||
array( 'RO', '40', '🇷🇴' ),
|
||||
array( 'RU', '7', '🇷🇺' ),
|
||||
array( 'RW', '250', '🇷🇼' ),
|
||||
array( 'WS', '685', '🇼🇸' ),
|
||||
array( 'SM', '378', '🇸🇲' ),
|
||||
array( 'ST', '239', '🇸🇹' ),
|
||||
array( 'SA', '966', '🇸🇦' ),
|
||||
array( 'SN', '221', '🇸🇳' ),
|
||||
array( 'RS', '381', '🇷🇸' ),
|
||||
array( 'SC', '248', '🇸🇨' ),
|
||||
array( 'SL', '232', '🇸🇱' ),
|
||||
array( 'SG', '65', '🇸🇬' ),
|
||||
array( 'SX', '1', '🇸🇽' ),
|
||||
array( 'SK', '421', '🇸🇰' ),
|
||||
array( 'SI', '386', '🇸🇮' ),
|
||||
array( 'SB', '677', '🇸🇧' ),
|
||||
array( 'SO', '252', '🇸🇴' ),
|
||||
array( 'ZA', '27', '🇿🇦' ),
|
||||
array( 'KR', '82', '🇰🇷' ),
|
||||
array( 'SS', '211', '🇸🇸' ),
|
||||
array( 'ES', '34', '🇪🇸' ),
|
||||
array( 'LK', '94', '🇱🇰' ),
|
||||
array( 'BL', '590', '🇧🇱' ),
|
||||
array( 'SH', '290', '🇸🇭' ),
|
||||
array( 'KN', '1', '🇰🇳' ),
|
||||
array( 'LC', '1', '🇱🇨' ),
|
||||
array( 'MF', '590', '🇲🇫' ),
|
||||
array( 'PM', '508', '🇵🇲' ),
|
||||
array( 'VC', '1', '🇻🇨' ),
|
||||
array( 'SD', '249', '🇸🇩' ),
|
||||
array( 'SR', '597', '🇸🇷' ),
|
||||
array( 'SJ', '47', '🇸🇯' ),
|
||||
array( 'SE', '46', '🇸🇪' ),
|
||||
array( 'CH', '41', '🇨🇭' ),
|
||||
array( 'SY', '963', '🇸🇾' ),
|
||||
array( 'TW', '886', '🇹🇼' ),
|
||||
array( 'TJ', '992', '🇹🇯' ),
|
||||
array( 'TZ', '255', '🇹🇿' ),
|
||||
array( 'TH', '66', '🇹🇭' ),
|
||||
array( 'TL', '670', '🇹🇱' ),
|
||||
array( 'TG', '228', '🇹🇬' ),
|
||||
array( 'TK', '690', '🇹🇰' ),
|
||||
array( 'TO', '676', '🇹🇴' ),
|
||||
array( 'TT', '1', '🇹🇹' ),
|
||||
array( 'TN', '216', '🇹🇳' ),
|
||||
array( 'TR', '90', '🇹🇷' ),
|
||||
array( 'TM', '993', '🇹🇲' ),
|
||||
array( 'TC', '1', '🇹🇨' ),
|
||||
array( 'TV', '688', '🇹🇻' ),
|
||||
array( 'UG', '256', '🇺🇬' ),
|
||||
array( 'UA', '380', '🇺🇦' ),
|
||||
array( 'AE', '971', '🇦🇪' ),
|
||||
array( 'GB', '44', '🇬🇧' ),
|
||||
array( 'US', '1', '🇺🇸' ),
|
||||
array( 'UY', '598', '🇺🇾' ),
|
||||
array( 'VI', '1', '🇻🇮' ),
|
||||
array( 'UZ', '998', '🇺🇿' ),
|
||||
array( 'VU', '678', '🇻🇺' ),
|
||||
array( 'VA', '39', '🇻🇦' ),
|
||||
array( 'VE', '58', '🇻🇪' ),
|
||||
array( 'VN', '84', '🇻🇳' ),
|
||||
array( 'WF', '681', '🇼🇫' ),
|
||||
array( 'EH', '212', '🇪🇭' ),
|
||||
array( 'YE', '967', '🇾🇪' ),
|
||||
array( 'ZM', '260', '🇿🇲' ),
|
||||
array( 'ZW', '263', '🇿🇼' ),
|
||||
);
|
||||
|
||||
return array_map( function ( $item ) use ( $countries ) {
|
||||
return array(
|
||||
'iso' => $item[0],
|
||||
'name' => $countries[ $item[0] ],
|
||||
'calling_code' => $item[1],
|
||||
'flag' => $item[2],
|
||||
);
|
||||
}, $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given list of data by type. Helper method used to route the individual type requests
|
||||
* through to the appropriate data list method.
|
||||
*
|
||||
* @param $type - string - The type of data to retrieve.
|
||||
* @param $as_json - boolean - Whether to retrieve this data as as JSON string.
|
||||
* @param $process_callback - callable - An optional callback for transforming the data before returning.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
private static function get_data_by_type( $type, $as_json = false, $process_callback = null ) {
|
||||
switch ( $type ) {
|
||||
case 'country':
|
||||
$data = self::countries_list();
|
||||
break;
|
||||
case 'state':
|
||||
$data = self::states_list();
|
||||
break;
|
||||
case 'province':
|
||||
$data = self::provinces_list();
|
||||
break;
|
||||
case 'phone':
|
||||
$data = self::phone_list();
|
||||
break;
|
||||
default:
|
||||
$data = array();
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! is_null( $process_callback ) ) {
|
||||
$data = call_user_func( $process_callback, $data );
|
||||
}
|
||||
|
||||
return $as_json ? json_encode( $data ) : $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an array of US States.
|
||||
*
|
||||
* @param $as_json - boolean - Whether to retrieve this data as a JSON string.
|
||||
* @param $process_callback - callable - An optional callback for transforming the data before returning.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public static function states( $as_json = false, $process_callback = null ) {
|
||||
return self::get_data_by_type( 'state', $as_json, $process_callback );
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an array of Canadian Provinces.
|
||||
*
|
||||
* @param $as_json - boolean - Whether to retrieve this data as a JSON string.
|
||||
* @param $process_callback - callable - An optional callback for transforming the data before returning.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public static function provinces( $as_json = false, $process_callback = null ) {
|
||||
return self::get_data_by_type( 'province', $as_json, $process_callback );
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an array of Countries.
|
||||
*
|
||||
* @param $as_json - boolean - Whether to retrieve this data as a JSON string.
|
||||
* @param $process_callback - callable - An optional callback for transforming the data before returning.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public static function countries( $as_json = false, $process_callback = null ) {
|
||||
return self::get_data_by_type( 'country', $as_json, $process_callback );
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an array of phone format information.
|
||||
*
|
||||
* @param $as_json - boolean - Whether to retrieve this data as a JSON string.
|
||||
* @param $process_callback - callable - An optional callback for transforming the data before returning.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public static function phone_info( $as_json = false, $process_callback = null ) {
|
||||
return self::get_data_by_type( 'phone', $as_json, $process_callback );
|
||||
}
|
||||
}
|
||||
+659
@@ -0,0 +1,659 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools\Utils;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Moola {
|
||||
|
||||
protected $amount;
|
||||
|
||||
protected $currency_code;
|
||||
|
||||
protected $currency_data = array(
|
||||
'ALL' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Albania Lek',
|
||||
'symbol' => 'Lek',
|
||||
),
|
||||
'AFN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Afghanistan Afghani',
|
||||
'symbol' => '؋',
|
||||
),
|
||||
'ARS' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Argentina Peso',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'AWG' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Aruba Guilder',
|
||||
'symbol' => 'ƒ',
|
||||
),
|
||||
'AUD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Australia Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'AZN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Azerbaijan Manat',
|
||||
'symbol' => '₼',
|
||||
),
|
||||
'BSD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Bahamas Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'BBD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Barbados Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'BYN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Belarus Ruble',
|
||||
'symbol' => 'Br',
|
||||
),
|
||||
'BZD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Belize Dollar',
|
||||
'symbol' => 'BZ$',
|
||||
),
|
||||
'BMD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Bermuda Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'BOB' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Bolivia Bolíviano',
|
||||
'symbol' => '$b',
|
||||
),
|
||||
'BAM' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Bosnia and Herzegovina Convertible Mark',
|
||||
'symbol' => 'KM',
|
||||
),
|
||||
'BWP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Botswana Pula',
|
||||
'symbol' => 'P',
|
||||
),
|
||||
'BGN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Bulgaria Lev',
|
||||
'symbol' => 'лв',
|
||||
),
|
||||
'BRL' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Brazil Real',
|
||||
'symbol' => 'R$',
|
||||
),
|
||||
'BND' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Brunei Darussalam Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'KHR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Cambodia Riel',
|
||||
'symbol' => '៛',
|
||||
),
|
||||
'CAD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Canada Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'KYD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Cayman Islands Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'CLP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Chile Peso',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'CNY' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'China Yuan Renminbi',
|
||||
'symbol' => '¥',
|
||||
),
|
||||
'COP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Colombia Peso',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'CRC' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Costa Rica Colon',
|
||||
'symbol' => '₡',
|
||||
),
|
||||
'HRK' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Croatia Kuna',
|
||||
'symbol' => 'kn',
|
||||
),
|
||||
'CUP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Cuba Peso',
|
||||
'symbol' => '₱',
|
||||
),
|
||||
'CZK' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Czech Republic Koruna',
|
||||
'symbol' => 'Kč',
|
||||
),
|
||||
'DKK' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Denmark Krone',
|
||||
'symbol' => 'kr',
|
||||
),
|
||||
'DOP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Dominican Republic Peso',
|
||||
'symbol' => 'RD$',
|
||||
),
|
||||
'XCD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'East Caribbean Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'EGP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Egypt Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'SVC' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'El Salvador Colon',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'EUR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Euro Member Countries',
|
||||
'symbol' => '€',
|
||||
),
|
||||
'FKP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Falkland Islands (Malvinas) Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'FJD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Fiji Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'GHS' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Ghana Cedi',
|
||||
'symbol' => '¢',
|
||||
),
|
||||
'GIP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Gibraltar Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'GTQ' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Guatemala Quetzal',
|
||||
'symbol' => 'Q',
|
||||
),
|
||||
'GGP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Guernsey Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'GYD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Guyana Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'HNL' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Honduras Lempira',
|
||||
'symbol' => 'L',
|
||||
),
|
||||
'HKD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Hong Kong Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'HUF' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Hungary Forint',
|
||||
'symbol' => 'Ft',
|
||||
),
|
||||
'ISK' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Iceland Krona',
|
||||
'symbol' => 'kr',
|
||||
),
|
||||
'INR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'India Rupee',
|
||||
'symbol' => '',
|
||||
),
|
||||
'IDR' => array(
|
||||
'decimals' => 0,
|
||||
'name' => 'Indonesia Rupiah',
|
||||
'symbol' => 'Rp',
|
||||
),
|
||||
'IRR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Iran Rial',
|
||||
'symbol' => '﷼',
|
||||
),
|
||||
'IMP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Isle of Man Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'ILS' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Israel Shekel',
|
||||
'symbol' => '₪',
|
||||
),
|
||||
'JMD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Jamaica Dollar',
|
||||
'symbol' => 'J$',
|
||||
),
|
||||
'JPY' => array(
|
||||
'decimals' => 0,
|
||||
'name' => 'Japan Yen',
|
||||
'symbol' => '¥',
|
||||
),
|
||||
'JEP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Jersey Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'KZT' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Kazakhstan Tenge',
|
||||
'symbol' => 'лв',
|
||||
),
|
||||
'KPW' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Korea (North) Won',
|
||||
'symbol' => '₩',
|
||||
),
|
||||
'KRW' => array(
|
||||
'decimals' => 0,
|
||||
'name' => 'Korea (South) Won',
|
||||
'symbol' => '₩',
|
||||
),
|
||||
'KGS' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Kyrgyzstan Som',
|
||||
'symbol' => 'лв',
|
||||
),
|
||||
'LAK' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Laos Kip',
|
||||
'symbol' => '₭',
|
||||
),
|
||||
'LBP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Lebanon Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'LRD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Liberia Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'MKD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Macedonia Denar',
|
||||
'symbol' => 'ден',
|
||||
),
|
||||
'MYR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Malaysia Ringgit',
|
||||
'symbol' => 'RM',
|
||||
),
|
||||
'MUR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Mauritius Rupee',
|
||||
'symbol' => '₨',
|
||||
),
|
||||
'MXN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Mexico Peso',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'MNT' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Mongolia Tughrik',
|
||||
'symbol' => '₮',
|
||||
),
|
||||
'MZN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Mozambique Metical',
|
||||
'symbol' => 'MT',
|
||||
),
|
||||
'NAD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Namibia Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'NPR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Nepal Rupee',
|
||||
'symbol' => '₨',
|
||||
),
|
||||
'ANG' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Netherlands Antilles Guilder',
|
||||
'symbol' => 'ƒ',
|
||||
),
|
||||
'NZD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'New Zealand Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'NIO' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Nicaragua Cordoba',
|
||||
'symbol' => 'C$',
|
||||
),
|
||||
'NGN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Nigeria Naira',
|
||||
'symbol' => '₦',
|
||||
),
|
||||
'NOK' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Norway Krone',
|
||||
'symbol' => 'kr',
|
||||
),
|
||||
'OMR' => array(
|
||||
'decimals' => 3,
|
||||
'name' => 'Oman Rial',
|
||||
'symbol' => '﷼',
|
||||
),
|
||||
'PKR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Pakistan Rupee',
|
||||
'symbol' => '₨',
|
||||
),
|
||||
'PAB' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Panama Balboa',
|
||||
'symbol' => 'B/.',
|
||||
),
|
||||
'PYG' => array(
|
||||
'decimals' => 0,
|
||||
'name' => 'Paraguay Guarani',
|
||||
'symbol' => 'Gs',
|
||||
),
|
||||
'PEN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Peru Sol',
|
||||
'symbol' => 'S/.',
|
||||
),
|
||||
'PHP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Philippines Peso',
|
||||
'symbol' => '₱',
|
||||
),
|
||||
'PLN' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Poland Zloty',
|
||||
'symbol' => 'zł',
|
||||
),
|
||||
'QAR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Qatar Riyal',
|
||||
'symbol' => '﷼',
|
||||
),
|
||||
'RON' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Romania Leu',
|
||||
'symbol' => 'lei',
|
||||
),
|
||||
'RUB' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Russia Ruble',
|
||||
'symbol' => '₽',
|
||||
),
|
||||
'SHP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Saint Helena Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'SAR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Saudi Arabia Riyal',
|
||||
'symbol' => '﷼',
|
||||
),
|
||||
'RSD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Serbia Dinar',
|
||||
'symbol' => 'Дин.',
|
||||
),
|
||||
'SCR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Seychelles Rupee',
|
||||
'symbol' => '₨',
|
||||
),
|
||||
'SGD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Singapore Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'SBD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Solomon Islands Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'SOS' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Somalia Shilling',
|
||||
'symbol' => 'S',
|
||||
),
|
||||
'ZAR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'South Africa Rand',
|
||||
'symbol' => 'R',
|
||||
),
|
||||
'LKR' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Sri Lanka Rupee',
|
||||
'symbol' => '₨',
|
||||
),
|
||||
'SEK' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Sweden Krona',
|
||||
'symbol' => 'kr',
|
||||
),
|
||||
'CHF' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Switzerland Franc',
|
||||
'symbol' => 'CHF',
|
||||
),
|
||||
'SRD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Suriname Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'SYP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Syria Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'TWD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Taiwan New Dollar',
|
||||
'symbol' => 'NT$',
|
||||
),
|
||||
'THB' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Thailand Baht',
|
||||
'symbol' => '฿',
|
||||
),
|
||||
'TTD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Trinidad and Tobago Dollar',
|
||||
'symbol' => 'TT$',
|
||||
),
|
||||
'TRY' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Turkey Lira',
|
||||
'symbol' => '',
|
||||
),
|
||||
'TVD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Tuvalu Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'UAH' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Ukraine Hryvnia',
|
||||
'symbol' => '₴',
|
||||
),
|
||||
'GBP' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'United Kingdom Pound',
|
||||
'symbol' => '£',
|
||||
),
|
||||
'USD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'United States Dollar',
|
||||
'symbol' => '$',
|
||||
),
|
||||
'UYU' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Uruguay Peso',
|
||||
'symbol' => '$U',
|
||||
),
|
||||
'UZS' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Uzbekistan Som',
|
||||
'symbol' => 'лв',
|
||||
),
|
||||
'VEF' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Venezuela Bolívar',
|
||||
'symbol' => 'Bs',
|
||||
),
|
||||
'VND' => array(
|
||||
'decimals' => 0,
|
||||
'name' => 'Viet Nam Dong',
|
||||
'symbol' => '₫',
|
||||
),
|
||||
'YER' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Yemen Rial',
|
||||
'symbol' => '﷼',
|
||||
),
|
||||
'ZWD' => array(
|
||||
'decimals' => 2,
|
||||
'name' => 'Zimbabwe Dollar',
|
||||
'symbol' => 'Z$',
|
||||
),
|
||||
);
|
||||
|
||||
public function __construct( $amount, $currency_code, $is_raw = true ) {
|
||||
if ( ! $is_raw ) {
|
||||
$amount = $this->convert_display_amount_to_raw( $amount, $currency_code );
|
||||
}
|
||||
$this->amount = $amount;
|
||||
$this->currency_code = $currency_code;
|
||||
|
||||
$this->get_currency_data( $currency_code );
|
||||
}
|
||||
|
||||
public function raw_value() {
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
public function display_value( $precision = 0, $show_currency = false, $commas = false ) {
|
||||
$currency_data = $this->get_currency_data( $this->currency_code );
|
||||
$decimals = (int) $currency_data['decimals'];
|
||||
|
||||
$divider = 1;
|
||||
|
||||
for ( $i = 0; $i < $decimals; $i++ ) {
|
||||
$divider *= 10;
|
||||
}
|
||||
|
||||
$float_val = (float) ( $this->amount / $divider );
|
||||
|
||||
if ( ! $show_currency ) {
|
||||
return round( $float_val, $precision );
|
||||
}
|
||||
|
||||
$rounded = round( $float_val, $precision );
|
||||
$formatted_val = $commas ? number_format( $rounded ) : $rounded;
|
||||
|
||||
return sprintf( '%s%s', $currency_data['symbol'], $formatted_val );
|
||||
}
|
||||
|
||||
public function change_currency( $new_currency_code ) {
|
||||
$new_data = $this->get_currency_data( $new_currency_code );
|
||||
$current_data = $this->get_currency_data( $this->currency_code );
|
||||
|
||||
$this->currency_code = $new_currency_code;
|
||||
|
||||
if ( $new_data['decimals'] === $current_data['decimals'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$modifier = 1;
|
||||
|
||||
$start = min( $new_data['decimals'], $current_data['decimals'] );
|
||||
$end = max( $new_data['decimals'], $current_data['decimals'] );
|
||||
|
||||
for ( $i = $start; $i < $end; $i++ ) {
|
||||
$modifier *= 10;
|
||||
}
|
||||
|
||||
if ( $new_data['decimals'] > $current_data['decimals'] ) {
|
||||
$this->amount = $this->amount * $modifier;
|
||||
}
|
||||
|
||||
if ( $new_data['decimals'] < $current_data['decimals'] ) {
|
||||
$this->amount = $this->amount / $modifier;
|
||||
}
|
||||
}
|
||||
|
||||
public function convert_display_amount_to_raw( $display_value, $currency_code ) {
|
||||
$currency_data = $this->get_currency_data( $currency_code );
|
||||
$sanitized = $this->sanitize_display_value( $display_value );
|
||||
|
||||
$modifier = 1;
|
||||
|
||||
for( $i = 0; $i < $currency_data['decimals']; $i++ ) {
|
||||
$modifier *= 10;
|
||||
}
|
||||
|
||||
return $sanitized * $modifier;
|
||||
}
|
||||
|
||||
private function sanitize_display_value( $display_value ) {
|
||||
$stripped = preg_replace( "/[^0-9.]/", "", $display_value );
|
||||
|
||||
if ( $stripped === '' ) {
|
||||
$stripped = 0;
|
||||
}
|
||||
|
||||
if ( ! is_numeric( $stripped ) ) {
|
||||
throw new InvalidArgumentException( 'Invalid display value provided for sanitization.' );
|
||||
}
|
||||
|
||||
return floatval( $stripped );
|
||||
}
|
||||
|
||||
private function get_currency_data( $currency_code ) {
|
||||
if ( ! array_key_exists( $currency_code, $this->currency_data ) ) {
|
||||
throw new InvalidArgumentException( 'Invalid currency code provided.' );
|
||||
}
|
||||
|
||||
return $this->currency_data[ $currency_code ];
|
||||
}
|
||||
}
|
||||
Vendored
+163
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools;
|
||||
|
||||
use Gravity_Forms\Gravity_Tools\Config;
|
||||
|
||||
/**
|
||||
* Collection to hold Config items and provide their structured data when needed.
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Tools
|
||||
*/
|
||||
class Config_Collection {
|
||||
|
||||
/**
|
||||
* @var Config[] $configs
|
||||
*/
|
||||
private $configs = array();
|
||||
|
||||
/**
|
||||
* Add a config to the collection.
|
||||
*
|
||||
* @param Config $config
|
||||
*/
|
||||
public function add_config( Config $config ) {
|
||||
$this->configs[] = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle outputting the config data.
|
||||
*
|
||||
* If $localize is true, data is actually localized via `wp_localize_script`, otherwise
|
||||
* data is simply returned as an array.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param bool $localize Whether to localize the data, or simply return it.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function handle( $localize = true ) {
|
||||
$scripts = $this->get_configs_by_script();
|
||||
$data_to_localize = array();
|
||||
|
||||
foreach ( $scripts as $script => $items ) {
|
||||
$item_data = $this->localize_data_for_script( $script, $items, $localize );
|
||||
$data_to_localize = array_merge( $data_to_localize, $item_data );
|
||||
}
|
||||
|
||||
return $data_to_localize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize the data for the given script.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $script
|
||||
* @param Config[] $items
|
||||
*/
|
||||
private function localize_data_for_script( $script, $items, $localize = true ) {
|
||||
$data = array();
|
||||
|
||||
foreach ( $items as $name => $configs ) {
|
||||
$localized_data = $this->get_merged_data_for_object( $configs );
|
||||
|
||||
/**
|
||||
* Allows users to filter the data localized for a given script/resource.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param array $localized_data The current localize data
|
||||
* @param string $script The script being localized
|
||||
* @param array $configs An array of $configs being applied to this script
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
$localized_data = apply_filters( 'gform_localized_script_data_' . $name, $localized_data, $script, $configs );
|
||||
|
||||
$data[ $name ] = $localized_data;
|
||||
|
||||
if ( $localize ) {
|
||||
wp_localize_script( $script, $name, $localized_data );
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the merged data object for the applicable configs. Will process each config by its
|
||||
* $priority property, overriding or merging values as needed.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param Config[] $configs
|
||||
*/
|
||||
private function get_merged_data_for_object( $configs ) {
|
||||
// Squash warnings for PHP < 7.0 when running tests.
|
||||
@usort( $configs, array( $this, 'sort_by_priority' ) );
|
||||
|
||||
$data = array();
|
||||
|
||||
foreach ( $configs as $config ) {
|
||||
|
||||
// Config is set to overwrite data - simply return its value without attempting to merge.
|
||||
if ( $config->should_overwrite() ) {
|
||||
$data = $config->get_data();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Config should be merged - loop through each key and attempt to recursively merge the values.
|
||||
foreach ( $config->get_data() as $key => $value ) {
|
||||
$existing = isset( $data[ $key ] ) ? $data[ $key ] : null;
|
||||
|
||||
if ( is_null( $existing ) || ! is_array( $existing ) || ! is_array( $value ) ) {
|
||||
$data[ $key ] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
$data[ $key ] = array_merge_recursive( $existing, $value );
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate configs, organized by the script they belong to.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_configs_by_script() {
|
||||
$data_to_localize = array();
|
||||
|
||||
foreach ( $this->configs as $config ) {
|
||||
if ( ( ! defined( 'GFORMS_DOING_MOCK' ) || ! GFORMS_DOING_MOCK ) && ! $config->should_enqueue() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data_to_localize[ $config->script_to_localize() ][ $config->name() ][] = $config;
|
||||
}
|
||||
|
||||
return $data_to_localize;
|
||||
}
|
||||
|
||||
/**
|
||||
* usort() callback to sort the configs by their $priority.
|
||||
*
|
||||
* @param Config $a
|
||||
* @param Config $b
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function sort_by_priority( Config $a, Config $b ) {
|
||||
if ( $a->priority() === $b->priority() ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $a->priority() < $b->priority() ? - 1 : 1;
|
||||
}
|
||||
}
|
||||
Vendored
+75
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Tools;
|
||||
|
||||
/**
|
||||
* Parses a given data array to return either Live or Mock values, depending on the
|
||||
* environment and context.
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Tools
|
||||
*/
|
||||
class Config_Data_Parser {
|
||||
|
||||
/**
|
||||
* Parse the given $data array and get the correct values for the context.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parse( $data ) {
|
||||
$return = array();
|
||||
|
||||
foreach( $data as $key => $value ) {
|
||||
$return[ $key ] = $this->get_correct_value( $value );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through each array key and get the correct value. Is called recursively for
|
||||
* nested arrays.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
private function get_correct_value( $value ) {
|
||||
|
||||
// Value isn't array - we've reached the final level for this branch.
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Value is an array with our defined value and default keys. Return either live or mock data.
|
||||
if ( array_key_exists( 'default', $value ) && array_key_exists( 'value', $value ) ) {
|
||||
return $this->is_mock() ? $value['default'] : $value['value'];
|
||||
}
|
||||
|
||||
$data = array();
|
||||
|
||||
// Value is an array - recursively call this method to dig into each level and return the correct value.
|
||||
foreach( $value as $key => $value ) {
|
||||
$data[ $key ] = $this->get_correct_value( $value );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the current environmental context is a Mock context.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_mock() {
|
||||
return defined( 'GFORMS_DOING_MOCK' ) && GFORMS_DOING_MOCK;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user