first commit

This commit is contained in:
2024-12-17 13:43:22 +01:00
commit 8e6cd8b410
21292 changed files with 3514826 additions and 0 deletions

10
modules/mailchimppro/vendor/.htaccess vendored Normal file
View File

@@ -0,0 +1,10 @@
# Apache 2.2
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
Require all denied
</IfModule>

View File

@@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit684ce49a5524df0b1b22273574a6940d::getLoader();

View File

@@ -0,0 +1,445 @@
<?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 http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
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 array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $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 array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $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] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $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 array|string $paths The PSR-0 base directories
*/
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 array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
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
*/
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
*/
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
*/
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
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* 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;
}
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;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

View File

@@ -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.

View File

@@ -0,0 +1,9 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

View File

@@ -0,0 +1,11 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'd4b3877d06f9b76941adbfe5d3cb2fbf' => $baseDir . '/src/LinkHelper.php',
'b230e1fbf7ff4907477dbbf4766a9d49' => $baseDir . '/src/MailchimpProConfig.php',
);

View File

@@ -0,0 +1,10 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'JasonGrimes' => array($vendorDir . '/jasongrimes/paginator/src'),
);

View File

@@ -0,0 +1,11 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'DrewM\\MailChimp\\' => array($vendorDir . '/drewm/mailchimp-api/src'),
'' => array($baseDir . '/src'),
);

View File

@@ -0,0 +1,70 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit684ce49a5524df0b1b22273574a6940d
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit684ce49a5524df0b1b22273574a6940d', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit684ce49a5524df0b1b22273574a6940d', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit684ce49a5524df0b1b22273574a6940d::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit684ce49a5524df0b1b22273574a6940d::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire684ce49a5524df0b1b22273574a6940d($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire684ce49a5524df0b1b22273574a6940d($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View File

@@ -0,0 +1,52 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit684ce49a5524df0b1b22273574a6940d
{
public static $files = array (
'd4b3877d06f9b76941adbfe5d3cb2fbf' => __DIR__ . '/../..' . '/src/LinkHelper.php',
'b230e1fbf7ff4907477dbbf4766a9d49' => __DIR__ . '/../..' . '/src/MailchimpProConfig.php',
);
public static $prefixLengthsPsr4 = array (
'D' =>
array (
'DrewM\\MailChimp\\' => 16,
),
);
public static $prefixDirsPsr4 = array (
'DrewM\\MailChimp\\' =>
array (
0 => __DIR__ . '/..' . '/drewm/mailchimp-api/src',
),
);
public static $fallbackDirsPsr4 = array (
0 => __DIR__ . '/../..' . '/src',
);
public static $prefixesPsr0 = array (
'J' =>
array (
'JasonGrimes' =>
array (
0 => __DIR__ . '/..' . '/jasongrimes/paginator/src',
),
),
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit684ce49a5524df0b1b22273574a6940d::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit684ce49a5524df0b1b22273574a6940d::$prefixDirsPsr4;
$loader->fallbackDirsPsr4 = ComposerStaticInit684ce49a5524df0b1b22273574a6940d::$fallbackDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit684ce49a5524df0b1b22273574a6940d::$prefixesPsr0;
}, null, ClassLoader::class);
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,107 @@
[
{
"name": "drewm/mailchimp-api",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/PrestaChamps/mailchimp-api.git",
"reference": "30155166cd1059346c0e3fb94d7e636f88e9d374"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PrestaChamps/mailchimp-api/zipball/30155166cd1059346c0e3fb94d7e636f88e9d374",
"reference": "30155166cd1059346c0e3fb94d7e636f88e9d374",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"php": ">=5.6"
},
"require-dev": {
"phpunit/phpunit": "7.0.*",
"vlucas/phpdotenv": "^2.0"
},
"time": "2019-02-11T15:03:33+00:00",
"type": "library",
"installation-source": "source",
"autoload": {
"psr-4": {
"DrewM\\MailChimp\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"DrewM\\MailChimp\\Tests\\": "tests/"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Drew McLellan",
"email": "drew.mclellan@gmail.com",
"homepage": "http://allinthehead.com/"
},
{
"name": "Zoltan Szanto",
"email": "mrbig00@gmail.com",
"homepage": "http://allinthehead.com/"
}
],
"description": "Super-simple, minimum abstraction MailChimp API v3 wrapper",
"homepage": "https://github.com/drewm/mailchimp-api",
"support": {
"source": "https://github.com/PrestaChamps/mailchimp-api/tree/master"
}
},
{
"name": "jasongrimes/paginator",
"version": "1.0.3",
"version_normalized": "1.0.3.0",
"source": {
"type": "git",
"url": "https://github.com/jasongrimes/php-paginator.git",
"reference": "3411e3cd0c6479a0b514f26e4358f0273552f221"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jasongrimes/php-paginator/zipball/3411e3cd0c6479a0b514f26e4358f0273552f221",
"reference": "3411e3cd0c6479a0b514f26e4358f0273552f221",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"time": "2018-07-11T18:11:49+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"JasonGrimes": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jason Grimes",
"email": "jason@grimesit.com"
}
],
"description": "A lightweight PHP paginator, for generating pagination controls in the style of Stack Overflow and Flickr. The 'first' and 'last' page links are shown inline as page numbers, and excess page numbers are replaced by ellipses.",
"homepage": "http://github.com/jasongrimes/php-paginator",
"keywords": [
"pager",
"pagination",
"paginator"
]
}
]

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,2 @@
MC_API_KEY=""
MC_LIST_ID=""

View File

@@ -0,0 +1,8 @@
/tests export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.scrutinizer.yml export-ignore
/.travis.yml export-ignore
/phpunit.xml export-ignore
/.env export-ignore
/.env.example export-ignore

View File

@@ -0,0 +1,17 @@
## Submitting issues
This is quite a popular project, but it's not my job, so please read the below before posting an issue. Thank you!
- If you have high-level implementation questions about your project ("How do I add this to WordPress", "I've got a form that takes an email address...") you're best to ask somewhere like StackOverflow.
- If you have purchased a commercial product or template that uses this code and now have a problem, *I'm not going to help you with it, sorry.* Talk to the person who took your money. None of it came to me. :smile:
- If your question is about the MailChimp API itself, please check out the [MailChimp Guides](http://developer.mailchimp.com/documentation/mailchimp/guides/). This project doesn't handle any of that logic - we're just helping you form the requests.
If, however, you think you've found a bug, or would like to discuss a change or improvement, feel free to raise an issue and we'll figure it out between us.
## Pull requests
This is a fairly simple wrapper, but it has been made much better by contributions from those using it. If you'd like to suggest an improvement, please raise an issue to discuss it before making your pull request.
Pull requests for bugs are more than welcome - please explain the bug you're trying to fix in the message.
There are a small number of PHPUnit unit tests. To get up and running, copy `.env.example` to `.env` and add your API key details. Unit testing against an API is obviously a bit tricky, but I'd welcome any contributions to this. It would be great to have more test coverage.

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,4 @@
.env
/vendor
composer.lock
.idea

View File

@@ -0,0 +1,10 @@
# .scrutinizer.yml
checks:
php: true
filter:
excluded_paths:
- tests/*
- vendor/*
paths:
- src/*

View File

@@ -0,0 +1,14 @@
language: php
sudo: true
php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
before_script:
- composer self-update
- composer install --prefer-source --no-interaction --dev --ignore-platform-reqs
script:
- ./scripts/travis.sh

View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Drew McLellan
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.

View File

@@ -0,0 +1,225 @@
MailChimp API
=============
Super-simple, minimum abstraction MailChimp API v3 wrapper, in PHP.
I hate complex wrappers. This lets you get from the MailChimp API docs to the code as directly as possible.
Requires PHP 5.3 and a pulse. Abstraction is for chimps.
[![Build Status](https://travis-ci.org/drewm/mailchimp-api.svg?branch=master)](https://travis-ci.org/drewm/mailchimp-api)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/drewm/mailchimp-api/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/drewm/mailchimp-api/?branch=master)
[![Packagist](https://img.shields.io/packagist/dt/drewm/mailchimp-api.svg?maxAge=2592000)](https://packagist.org/packages/drewm/mailchimp-api)
Installation
------------
You can install mailchimp-api using Composer:
```
composer require drewm/mailchimp-api
```
You will then need to:
* run ``composer install`` to get these dependencies added to your vendor directory
* add the autoloader to your application with this line: ``require("vendor/autoload.php")``
Alternatively you can just download the `MailChimp.php` file and include it manually:
```php
include('./MailChimp.php');
```
If you wish to use the batch request or webhook interfaces, you'll also need to download and include the `Batch.php` or `Webhook.php` files:
```php
include('./Batch.php');
include('./Webhook.php');
```
These are optional. If you're not using batches or webhooks you can just skip them. You can always come back and add them later.
Examples
--------
Start by `use`-ing the class and creating an instance with your API key
```php
use \DrewM\MailChimp\MailChimp;
$MailChimp = new MailChimp('abc123abc123abc123abc123abc123-us1');
```
Then, list all the mailing lists (with a `get` on the `lists` method)
```php
$result = $MailChimp->get('lists');
print_r($result);
```
Subscribe someone to a list (with a `post` to the `lists/{listID}/members` method):
```php
$list_id = 'b1234346';
$result = $MailChimp->post("lists/$list_id/members", [
'email_address' => 'davy@example.com',
'status' => 'subscribed',
]);
print_r($result);
```
Update a list member with more information (using `patch` to update):
```php
$list_id = 'b1234346';
$subscriber_hash = $MailChimp->subscriberHash('davy@example.com');
$result = $MailChimp->patch("lists/$list_id/members/$subscriber_hash", [
'merge_fields' => ['FNAME'=>'Davy', 'LNAME'=>'Jones'],
'interests' => ['2s3a384h' => true],
]);
print_r($result);
```
Remove a list member using the `delete` method:
```php
$list_id = 'b1234346';
$subscriber_hash = $MailChimp->subscriberHash('davy@example.com');
$MailChimp->delete("lists/$list_id/members/$subscriber_hash");
```
Quickly test for a successful action with the `success()` method:
```php
$list_id = 'b1234346';
$result = $MailChimp->post("lists/$list_id/members", [
'email_address' => 'davy@example.com',
'status' => 'subscribed',
]);
if ($MailChimp->success()) {
print_r($result);
} else {
echo $MailChimp->getLastError();
}
```
Batch Operations
----------------
The MailChimp [Batch Operations](http://developer.mailchimp.com/documentation/mailchimp/guides/how-to-use-batch-operations/) functionality enables you to complete multiple operations with a single call. A good example is adding thousands of members to a list - you can perform this in one request rather than thousands.
```php
use \DrewM\MailChimp\MailChimp;
use \DrewM\MailChimp\Batch;
$MailChimp = new MailChimp('abc123abc123abc123abc123abc123-us1');
$Batch = $MailChimp->new_batch();
```
You can then make requests on the `Batch` object just as you would normally with the `MailChimp` object. The difference is that you need to set an ID for the operation as the first argument, and also that you won't get a response. The ID is used for finding the result of this request in the combined response from the batch operation.
```php
$Batch->post("op1", "lists/$list_id/members", [
'email_address' => 'micky@example.com',
'status' => 'subscribed',
]);
$Batch->post("op2", "lists/$list_id/members", [
'email_address' => 'michael@example.com',
'status' => 'subscribed',
]);
$Batch->post("op3", "lists/$list_id/members", [
'email_address' => 'peter@example.com',
'status' => 'subscribed',
]);
```
Once you've finished all the requests that should be in the batch, you need to execute it.
```php
$result = $Batch->execute();
```
The result includes a batch ID. At a later point, you can check the status of your batch:
```php
$MailChimp->new_batch($batch_id);
$result = $Batch->check_status();
```
When your batch is finished, you can download the results from the URL given in the response. In the JSON, the result of each operation will be keyed by the ID you used as the first argument for the request.
Webhooks
--------
**Note:** Use of the Webhooks functionality requires at least PHP 5.4.
MailChimp [webhooks](http://kb.mailchimp.com/integrations/other-integrations/how-to-set-up-webhooks) enable your code to be notified of changes to lists and campaigns.
When you set up a webhook you specify a URL on your server for the data to be sent to. This wrapper's Webhook class helps you catch that incoming webhook in a tidy way. It uses a subscription model, with your code subscribing to whichever webhook events it wants to listen for. You provide a callback function that the webhook data is passed to.
To listen for the `unsubscribe` webhook:
```php
use \DrewM\MailChimp\Webhook;
Webhook::subscribe('unsubscribe', function($data){
print_r($data);
});
```
At first glance the _subscribe/unsubscribe_ looks confusing - your code is subscribing to the MailChimp `unsubscribe` webhook event. The callback function is passed as single argument - an associative array containing the webhook data.
If you'd rather just catch all webhooks and deal with them yourself, you can use:
```php
use \DrewM\MailChimp\Webhook;
$result = Webhook::receive();
print_r($result);
```
There doesn't appear to be any documentation for the content of the webhook data. It's helpful to use something like [ngrok](https://ngrok.com) for tunneling the webhooks to your development machine - you can then use its web interface to inspect what's been sent and to replay incoming webhooks while you debug your code.
Troubleshooting
---------------
To get the last error returned by either the HTTP client or by the API, use `getLastError()`:
```php
echo $MailChimp->getLastError();
```
For further debugging, you can inspect the headers and body of the response:
```php
print_r($MailChimp->getLastResponse());
```
If you suspect you're sending data in the wrong format, you can look at what was sent to MailChimp by the wrapper:
```php
print_r($MailChimp->getLastRequest());
```
If your server's CA root certificates are not up to date you may find that SSL verification fails and you don't get a response. The correction solution for this [is not to disable SSL verification](http://snippets.webaware.com.au/howto/stop-turning-off-curlopt_ssl_verifypeer-and-fix-your-php-config/). The solution is to update your certificates. If you can't do that, there's an option at the top of the class file. Please don't just switch it off without at least attempting to update your certs -- that's lazy and dangerous. You're not a lazy, dangerous developer are you?
If you have **high-level implementation questions about your project** ("How do I add this to WordPress", "I've got a form that takes an email address...") please **take them to somewhere like StackOverflow**. If you think you've found a bug, or would like to discuss a change or improvement, feel free to raise an issue and we'll figure it out between us.
Contributing
------------
This is a fairly simple wrapper, but it has been made much better by contributions from those using it. If you'd like to suggest an improvement, please raise an issue to discuss it before making your pull request.
Pull requests for bugs are more than welcome - please explain the bug you're trying to fix in the message.
There are a small number of PHPUnit unit tests. To get up and running, copy `.env.example` to `.env` and add your API key details. Unit testing against an API is obviously a bit tricky, but I'd welcome any contributions to this. It would be great to have more test coverage.

View File

@@ -0,0 +1,40 @@
{
"name": "drewm/mailchimp-api",
"description": "Super-simple, minimum abstraction MailChimp API v3 wrapper",
"license": "MIT",
"require": {
"php": ">=5.6",
"ext-curl": "*",
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit": "7.0.*",
"vlucas/phpdotenv": "^2.0"
},
"autoload": {
"psr-4": {
"DrewM\\MailChimp\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"DrewM\\MailChimp\\Tests\\": "tests/"
}
},
"homepage": "https://github.com/drewm/mailchimp-api",
"authors": [
{
"name": "Drew McLellan",
"email": "drew.mclellan@gmail.com",
"homepage": "http://allinthehead.com/"
},
{
"name": "Zoltan Szanto",
"email": "mrbig00@gmail.com",
"homepage": "http://allinthehead.com/"
}
]
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="./tests/bootstrap.php"
colors="true"
failOnRisky="true"
failOnWarning="true"
stopOnFailure="false">
<testsuites>
<testsuite name="MailChimp Test Suite">
<directory suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
#!/bin/bash
cd ${TRAVIS_BUILD_DIR}
if [[ $TRAVIS_PHP_VERSION = '7.1' ]]; then
phpunit
fi
if [[ $TRAVIS_PHP_VERSION = '7.2' ]]; then
phpunit
fi

View File

@@ -0,0 +1,170 @@
<?php
namespace DrewM\MailChimp;
/**
* A MailChimp Batch operation.
* http://developer.mailchimp.com/documentation/mailchimp/reference/batches/
*
* @author Drew McLellan <drew.mclellan@gmail.com>
*/
class Batch
{
private $MailChimp;
private $operations = array();
private $batch_id;
public function __construct(MailChimp $MailChimp, $batch_id = null)
{
$this->MailChimp = $MailChimp;
$this->batch_id = $batch_id;
}
/**
* Add an HTTP DELETE request operation to the batch - for deleting data
*
* @param string $id ID for the operation within the batch
* @param string $method URL of the API request method
*
* @return void
*/
public function delete($id, $method)
{
$this->queueOperation('DELETE', $id, $method);
}
/**
* Add an HTTP GET request operation to the batch - for retrieving data
*
* @param string $id ID for the operation within the batch
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
*
* @return void
*/
public function get($id, $method, $args = array())
{
$this->queueOperation('GET', $id, $method, $args);
}
/**
* Add an HTTP PATCH request operation to the batch - for performing partial updates
*
* @param string $id ID for the operation within the batch
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
*
* @return void
*/
public function patch($id, $method, $args = array())
{
$this->queueOperation('PATCH', $id, $method, $args);
}
/**
* Add an HTTP POST request operation to the batch - for creating and updating items
*
* @param string $id ID for the operation within the batch
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
*
* @return void
*/
public function post($id, $method, $args = array())
{
$this->queueOperation('POST', $id, $method, $args);
}
/**
* Add an HTTP PUT request operation to the batch - for creating new items
*
* @param string $id ID for the operation within the batch
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
*
* @return void
*/
public function put($id, $method, $args = array())
{
$this->queueOperation('PUT', $id, $method, $args);
}
/**
* Execute the batch request
*
* @param int $timeout Request timeout in seconds (optional)
*
* @return array|false Assoc array of API response, decoded from JSON
*/
public function execute($timeout = 10)
{
$req = array('operations' => $this->operations);
$result = $this->MailChimp->post('batches', $req, $timeout);
if ($result && isset($result['id'])) {
$this->batch_id = $result['id'];
}
return $result;
}
/**
* Check the status of a batch request. If the current instance of the Batch object
* was used to make the request, the batch_id is already known and is therefore optional.
*
* @param string $batch_id ID of the batch about which to enquire
*
* @return array|false Assoc array of API response, decoded from JSON
*/
public function check_status($batch_id = null)
{
if ($batch_id === null && $this->batch_id) {
$batch_id = $this->batch_id;
}
return $this->MailChimp->get('batches/' . $batch_id);
}
/**
* Get operations
*
* @return array
*/
public function get_operations()
{
return $this->operations;
}
/**
* Add an operation to the internal queue.
*
* @param string $http_verb GET, POST, PUT, PATCH or DELETE
* @param string $id ID for the operation within the batch
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
*
* @return void
*/
private function queueOperation($http_verb, $id, $method, $args = null)
{
$operation = array(
'operation_id' => $id,
'method' => $http_verb,
'path' => $method,
);
if ($args) {
if ($http_verb == 'GET') {
$key = 'params';
$operation[$key] = $args;
} else {
$key = 'body';
$operation[$key] = json_encode($args);
}
}
$this->operations[] = $operation;
}
}

View File

@@ -0,0 +1,506 @@
<?php
namespace DrewM\MailChimp;
/**
* Super-simple, minimum abstraction MailChimp API v3 wrapper
* MailChimp API v3: http://developer.mailchimp.com
* This wrapper: https://github.com/drewm/mailchimp-api
*
* @author Drew McLellan <drew.mclellan@gmail.com>
* @author Zoltan Szanto <mrbig00@gmail.com>
* @version 2.5
*/
class MailChimp
{
const TIMEOUT = 10;
static $USER_AGENT = 'DrewM/MailChimp-API/3.0 (github.com/drewm/mailchimp-api)';
/**
* Enable SSL Verification
* @see http://snippets.webaware.com.au/howto/stop-turning-off-curlopt_ssl_verifypeer-and-fix-your-php-config/
* @var bool
*/
public $verify_ssl = true;
protected $request_successful = false;
protected $last_error = '';
protected $last_response = array();
protected $last_request = array();
protected $api_key;
protected $api_endpoint = 'https://<dc>.api.mailchimp.com/3.0';
/**
* Create a new instance
*
* @param string $api_key Your MailChimp API key
* @param string $api_endpoint Optional custom API endpoint
*
* @throws \Exception
*/
public function __construct($api_key, $api_endpoint = null)
{
if (!function_exists('curl_init') || !function_exists('curl_setopt')) {
throw new \Exception("cURL support is required, but can't be found.");
}
$this->api_key = $api_key;
if ($api_endpoint === null) {
if (strpos($this->api_key, '-') === false) {
throw new \Exception("Invalid MailChimp API key supplied.");
}
list(, $data_center) = explode('-', $this->api_key);
$this->api_endpoint = str_replace('<dc>', $data_center, $this->api_endpoint);
} else {
$this->api_endpoint = $api_endpoint;
}
$this->last_response = array('headers' => null, 'body' => null);
}
/**
* Create a new instance of a Batch request. Optionally with the ID of an existing batch.
*
* @param string $batch_id Optional ID of an existing batch, if you need to check its status for example.
*
* @return Batch New Batch object.
*/
public function new_batch($batch_id = null)
{
return new Batch($this, $batch_id);
}
/**
* @return string The url to the API endpoint
*/
public function getApiEndpoint()
{
return $this->api_endpoint;
}
/**
* Convert an email address into a 'subscriber hash' for identifying the subscriber in a method URL
*
* @param string $email The subscriber's email address
*
* @return string Hashed version of the input
*/
public function subscriberHash($email)
{
return md5(strtolower($email));
}
/**
* Was the last request successful?
*
* @return bool True for success, false for failure
*/
public function success()
{
return $this->request_successful;
}
/**
* Get the last error returned by either the network transport, or by the API.
* If something didn't work, this should contain the string describing the problem.
*
* @return string|false describing the error
*/
public function getLastError()
{
return $this->last_error ?: false;
}
/**
* Get an array containing the HTTP headers and the body of the API response.
*
* @return array Assoc array with keys 'headers' and 'body'
*/
public function getLastResponse()
{
return $this->last_response;
}
/**
* Get an array containing the HTTP headers and the body of the API request.
*
* @return array Assoc array
*/
public function getLastRequest()
{
return $this->last_request;
}
/**
* Make an HTTP DELETE request - for deleting data
*
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (if any)
* @param int $timeout Timeout limit for request in seconds
*
* @return array|false Assoc array of API response, decoded from JSON
*/
public function delete($method, $args = array(), $timeout = self::TIMEOUT)
{
return $this->makeRequest('delete', $method, $args, $timeout);
}
/**
* Make an HTTP GET request - for retrieving data
*
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
* @param int $timeout Timeout limit for request in seconds
*
* @return array|false Assoc array of API response, decoded from JSON
*/
public function get($method, $args = array(), $timeout = self::TIMEOUT)
{
return $this->makeRequest('get', $method, $args, $timeout);
}
/**
* Make an HTTP PATCH request - for performing partial updates
*
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
* @param int $timeout Timeout limit for request in seconds
*
* @return array|false Assoc array of API response, decoded from JSON
*/
public function patch($method, $args = array(), $timeout = self::TIMEOUT)
{
return $this->makeRequest('patch', $method, $args, $timeout);
}
/**
* Make an HTTP POST request - for creating and updating items
*
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
* @param int $timeout Timeout limit for request in seconds
*
* @return array|false Assoc array of API response, decoded from JSON
*/
public function post($method, $args = array(), $timeout = self::TIMEOUT)
{
return $this->makeRequest('post', $method, $args, $timeout);
}
/**
* Make an HTTP PUT request - for creating new items
*
* @param string $method URL of the API request method
* @param array $args Assoc array of arguments (usually your data)
* @param int $timeout Timeout limit for request in seconds
*
* @return array|false Assoc array of API response, decoded from JSON
*/
public function put($method, $args = array(), $timeout = self::TIMEOUT)
{
return $this->makeRequest('put', $method, $args, $timeout);
}
/**
* Performs the underlying HTTP request. Not very exciting.
*
* @param string $http_verb The HTTP verb to use: get, post, put, patch, delete
* @param string $method The API method to be called
* @param array $args Assoc array of parameters to be passed
* @param int $timeout
*
* @return array|false Assoc array of decoded result
*/
protected function makeRequest($http_verb, $method, $args = array(), $timeout = self::TIMEOUT)
{
$url = $this->api_endpoint . '/' . $method;
$response = $this->prepareStateForRequest($http_verb, $method, $url, $timeout);
$httpHeader = array(
'Accept: application/vnd.api+json',
'Content-Type: application/vnd.api+json',
'Authorization: OAuth ' . $this->api_key
);
if (isset($args["language"])) {
$httpHeader[] = "Accept-Language: " . $args["language"];
}
$ch = $this->prepareResource($url, $timeout, $httpHeader);
switch ($http_verb) {
case 'post':
curl_setopt($ch, CURLOPT_POST, true);
$this->attachRequestPayload($ch, $args);
break;
case 'get':
$query = http_build_query($args, '', '&');
curl_setopt($ch, CURLOPT_URL, $url . '?' . $query);
break;
case 'delete':
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
break;
case 'patch':
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
$this->attachRequestPayload($ch, $args);
break;
case 'put':
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
$this->attachRequestPayload($ch, $args);
break;
}
$responseContent = curl_exec($ch);
$response['headers'] = curl_getinfo($ch);
$response = $this->setResponseState($response, $responseContent, $ch);
$formattedResponse = $this->formatResponse($response);
curl_close($ch);
$isSuccess = $this->determineSuccess($response, $formattedResponse, $timeout);
return is_array($formattedResponse) ? $formattedResponse : $isSuccess;
}
/**
* Prepare cURL resource before request
*
* @param $url
* @param $timeout
* @param array $headers
*
* @return resource
*/
protected function prepareResource($url, $timeout, $headers = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_USERAGENT, static::$USER_AGENT);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->verify_ssl);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
return $ch;
}
/**
* @param string $http_verb
* @param string $method
* @param string $url
* @param integer $timeout
*
* @return array
*/
protected function prepareStateForRequest($http_verb, $method, $url, $timeout)
{
$this->last_error = '';
$this->request_successful = false;
$this->last_response = array(
'headers' => null, // array of details from curl_getinfo()
'httpHeaders' => null, // array of HTTP headers
'body' => null // content of the response
);
$this->last_request = array(
'method' => $http_verb,
'path' => $method,
'url' => $url,
'body' => '',
'timeout' => $timeout,
);
return $this->last_response;
}
/**
* Get the HTTP headers as an array of header-name => header-value pairs.
*
* The "Link" header is parsed into an associative array based on the
* rel names it contains. The original value is available under
* the "_raw" key.
*
* @param string $headersAsString
*
* @return array
*/
protected function getHeadersAsArray($headersAsString)
{
$headers = array();
foreach (explode("\r\n", $headersAsString) as $i => $line) {
if ($i === 0) { // HTTP code
continue;
}
$line = trim($line);
if (empty($line)) {
continue;
}
list($key, $value) = explode(': ', $line);
if ($key == 'Link') {
$value = array_merge(
array('_raw' => $value),
$this->getLinkHeaderAsArray($value)
);
}
$headers[$key] = $value;
}
return $headers;
}
/**
* Extract all rel => URL pairs from the provided Link header value
*
* Mailchimp only implements the URI reference and relation type from
* RFC 5988, so the value of the header is something like this:
*
* 'https://us13.api.mailchimp.com/schema/3.0/Lists/Instance.json; rel="describedBy",
* <https://us13.admin.mailchimp.com/lists/members/?id=XXXX>; rel="dashboard"'
*
* @param string $linkHeaderAsString
*
* @return array
*/
protected function getLinkHeaderAsArray($linkHeaderAsString)
{
$urls = array();
if (preg_match_all('/<(.*?)>\s*;\s*rel="(.*?)"\s*/', $linkHeaderAsString, $matches)) {
foreach ($matches[2] as $i => $relName) {
$urls[$relName] = $matches[1][$i];
}
}
return $urls;
}
/**
* Encode the data and attach it to the request
*
* @param resource $ch cURL session handle, used by reference
* @param array $data Assoc array of data to attach
*/
protected function attachRequestPayload(&$ch, $data)
{
$encoded = json_encode($data);
$this->last_request['body'] = $encoded;
curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded);
}
/**
* Decode the response and format any error messages for debugging
*
* @param array $response The response from the curl request
*
* @return array|false The JSON decoded into an array
*/
protected function formatResponse($response)
{
$this->last_response = $response;
if (!empty($response['body'])) {
return json_decode($response['body'], true);
}
return false;
}
/**
* Do post-request formatting and setting state from the response
*
* @param array $response The response from the curl request
* @param string $responseContent The body of the response from the curl request
* @param resource $ch The curl resource
*
* @return array The modified response
*/
protected function setResponseState($response, $responseContent, $ch)
{
if ($responseContent === false) {
$this->last_error = curl_error($ch);
} else {
$headerSize = $response['headers']['header_size'];
$response['httpHeaders'] = $this->getHeadersAsArray(substr($responseContent, 0, $headerSize));
$response['body'] = substr($responseContent, $headerSize);
if (isset($response['headers']['request_header'])) {
$this->last_request['headers'] = $response['headers']['request_header'];
}
}
return $response;
}
/**
* Check if the response was successful or a failure. If it failed, store the error.
*
* @param array $response The response from the curl request
* @param array|false $formattedResponse The response body payload from the curl request
* @param int $timeout The timeout supplied to the curl request.
*
* @return bool If the request was successful
*/
protected function determineSuccess($response, $formattedResponse, $timeout)
{
$status = $this->findHTTPStatus($response, $formattedResponse);
if ($status >= 200 && $status <= 299) {
$this->request_successful = true;
return true;
}
if (isset($formattedResponse['detail'])) {
$this->last_error = sprintf('%d: %s', $formattedResponse['status'], $formattedResponse['detail']);
return false;
}
if ($timeout > 0 && $response['headers'] && $response['headers']['total_time'] >= $timeout) {
$this->last_error = sprintf('Request timed out after %f seconds.', $response['headers']['total_time']);
return false;
}
$this->last_error = 'Unknown error, call getLastResponse() to find out what happened.';
return false;
}
/**
* Find the HTTP status code from the headers or API response body
*
* @param array $response The response from the curl request
* @param array|false $formattedResponse The response body payload from the curl request
*
* @return int HTTP status code
*/
protected function findHTTPStatus($response, $formattedResponse)
{
if (!empty($response['headers']) && isset($response['headers']['http_code'])) {
return (int)$response['headers']['http_code'];
}
if (!empty($response['body']) && isset($formattedResponse['status'])) {
return (int)$formattedResponse['status'];
}
return 418;
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace DrewM\MailChimp;
/**
* A MailChimp Webhook request.
* How to Set Up Webhooks: http://eepurl.com/bs-j_T
*
* @author Drew McLellan <drew.mclellan@gmail.com>
*/
class Webhook
{
private static $eventSubscriptions = array();
private static $receivedWebhook = null;
/**
* Subscribe to an incoming webhook request. The callback will be invoked when a matching webhook is received.
*
* @param string $event Name of the webhook event, e.g. subscribe, unsubscribe, campaign
* @param callable $callback A callable function to invoke with the data from the received webhook
*
* @return void
*/
public static function subscribe($event, callable $callback)
{
if (!isset(self::$eventSubscriptions[$event])) self::$eventSubscriptions[$event] = array();
self::$eventSubscriptions[$event][] = $callback;
self::receive();
}
/**
* Retrieve the incoming webhook request as sent.
*
* @param string $input An optional raw POST body to use instead of php://input - mainly for unit testing.
*
* @return array|false An associative array containing the details of the received webhook
*/
public static function receive($input = null)
{
if (is_null($input)) {
if (self::$receivedWebhook !== null) {
$input = self::$receivedWebhook;
} else {
$input = file_get_contents("php://input");
}
}
if (!is_null($input) && $input != '') {
return self::processWebhook($input);
}
return false;
}
/**
* Process the raw request into a PHP array and dispatch any matching subscription callbacks
*
* @param string $input The raw HTTP POST request
*
* @return array|false An associative array containing the details of the received webhook
*/
private static function processWebhook($input)
{
self::$receivedWebhook = $input;
parse_str($input, $result);
if ($result && isset($result['type'])) {
self::dispatchWebhookEvent($result['type'], $result['data']);
return $result;
}
return false;
}
/**
* Call any subscribed callbacks for this event
*
* @param string $event The name of the callback event
* @param array $data An associative array of the webhook data
*
* @return void
*/
private static function dispatchWebhookEvent($event, $data)
{
if (isset(self::$eventSubscriptions[$event])) {
foreach (self::$eventSubscriptions[$event] as $callback) {
$callback($data);
}
// reset subscriptions
self::$eventSubscriptions[$event] = array();
}
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,29 @@
<?php
namespace DrewM\MailChimp\Tests;
use DrewM\MailChimp\MailChimp;
use PHPUnit\Framework\TestCase;
class BatchTest extends TestCase
{
/**
* @throws \Exception
*/
public function testNewBatch()
{
$MC_API_KEY = getenv('MC_API_KEY');
if (!$MC_API_KEY) {
$this->markTestSkipped('No API key in ENV');
}
$MailChimp = new MailChimp($MC_API_KEY);
$Batch = $MailChimp->new_batch('1');
$this->assertInstanceOf('\DrewM\MailChimp\Batch', $Batch);
$this->assertSame(array(), $Batch->get_operations());
}
}

View File

@@ -0,0 +1,21 @@
<?php
use DrewM\MailChimp\MailChimp;
use PHPUnit\Framework\TestCase;
class ListsTest extends TestCase
{
public function testGetLists()
{
$MC_API_KEY = getenv('MC_API_KEY');
if (!$MC_API_KEY) {
$this->markTestSkipped('No API key in ENV');
}
$MailChimp = new MailChimp($MC_API_KEY);
$lists = $MailChimp->get('lists');
$this->assertArrayHasKey('lists', $lists);
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace DrewM\MailChimp\Tests;
use DrewM\MailChimp\MailChimp;
use PHPUnit\Framework\TestCase;
class MailChimpTest extends TestCase
{
/**
* @throws \Exception
*/
public function testInvalidAPIKey()
{
$this->expectException('\Exception');
new MailChimp('abc');
}
public function testTestEnvironment()
{
$MC_API_KEY = getenv('MC_API_KEY');
$this->assertNotEmpty($MC_API_KEY, 'No environment variables! Copy .env.example -> .env and fill out your MailChimp account details.');
}
/**
* @throws \Exception
*/
public function testInstantiation()
{
$MC_API_KEY = getenv('MC_API_KEY');
if (!$MC_API_KEY) {
$this->markTestSkipped('No API key in ENV');
}
$MailChimp = new MailChimp($MC_API_KEY, 'https://api.mailchimp.com/3.0');
$this->assertInstanceOf('\DrewM\MailChimp\MailChimp', $MailChimp);
$this->assertSame('https://api.mailchimp.com/3.0', $MailChimp->getApiEndpoint());
$this->assertFalse($MailChimp->success());
$this->assertFalse($MailChimp->getLastError());
$this->assertSame(array('headers' => null, 'body' => null), $MailChimp->getLastResponse());
$this->assertSame(array(), $MailChimp->getLastRequest());
}
/**
* @throws \Exception
*/
public function testSubscriberHash()
{
$MC_API_KEY = getenv('MC_API_KEY');
if (!$MC_API_KEY) {
$this->markTestSkipped('No API key in ENV');
}
$MailChimp = new MailChimp($MC_API_KEY);
$email = 'Foo@Example.Com';
$expected = md5(strtolower($email));
$result = $MailChimp->subscriberHash($email);
$this->assertEquals($expected, $result);
}
public function testResponseState()
{
$MC_API_KEY = getenv('MC_API_KEY');
if (!$MC_API_KEY) {
$this->markTestSkipped('No API key in ENV');
}
$MailChimp = new MailChimp($MC_API_KEY);
$MailChimp->get('lists');
$this->assertTrue($MailChimp->success());
}
/* This test requires that your test list have:
* a) a list
* b) enough entries that the curl request will timeout after 1 second.
* How many this is may depend on your network connection to the Mailchimp servers.
*/
/*
public function testRequestTimeout()
{
$this->markTestSkipped('CI server too fast to realistically test.');
$MC_API_KEY = getenv('MC_API_KEY');
if (!$MC_API_KEY) {
$this->markTestSkipped('No API key in ENV');
}
$MailChimp = new MailChimp($MC_API_KEY);
$result = $MailChimp->get('lists');
$list_id = $result['lists'][0]['id'];
$args = array( 'count' => 1000 );
$timeout = 1;
$result = $MailChimp->get("lists/$list_id/members", $args, $timeout );
$this->assertFalse( $result );
$error = $MailChimp->getLastError();
$this->assertRegExp( '/Request timed out after 1.\d+ seconds/', $error );
}
*/
}

View File

@@ -0,0 +1,16 @@
<?php
\error_reporting(E_ALL);
include_once \dirname(__DIR__) . '/vendor/autoload.php';
if (!\class_exists('Dotenv\Dotenv')) {
throw new \RuntimeException('You need to define environment variables for configuration or add "symfony/dotenv" as a Composer dependency to load variables from a .env file.');
}
$env_file_path = __DIR__ . '/../';
if (file_exists($env_file_path . '.env')) {
$dotenv = new Dotenv\Dotenv($env_file_path);
$dotenv->load();
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

34
modules/mailchimppro/vendor/index.php vendored Normal file
View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,5 @@
/vendor/
composer.lock
*.swp
*.swo
*~

View File

@@ -0,0 +1,14 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
before_script: composer install --dev --prefer-source
notifications:
email: jason@grimesit.com

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 Jason Grimes
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.

View File

@@ -0,0 +1,170 @@
PHP Paginator
=============
[![Build Status](https://travis-ci.org/jasongrimes/php-paginator.svg?branch=master)](https://travis-ci.org/jasongrimes/php-paginator)
[![Total Downloads](https://poser.pugx.org/jasongrimes/paginator/downloads.svg)](https://packagist.org/packages/jasongrimes/paginator)
[![Latest Stable Version](https://poser.pugx.org/jasongrimes/paginator/v/stable.svg)](https://packagist.org/packages/jasongrimes/paginator) [![Latest Unstable Version](https://poser.pugx.org/jasongrimes/paginator/v/unstable.svg)](https://packagist.org/packages/jasongrimes/paginator) [![License](https://poser.pugx.org/jasongrimes/paginator/license.svg)](https://packagist.org/packages/jasongrimes/paginator)
A lightweight PHP paginator, for generating pagination controls in the style of Stack Overflow and Flickr. The "first" and "last" page links are shown inline as page numbers, and excess page numbers are replaced by ellipses.
## Screenshots
These examples show how the paginator handles overflow when there are a lot of pages.
They're rendered using the sample templates provided in the [examples](examples/) directory,
which depend on Twitter Bootstrap.
You can easily use your own custom HTML to render the pagination control instead.
Default template:
<img src="examples/screenshot-default-first.png" width="447"><br/>
<img src="examples/screenshot-default-mid.png" width="597"><br/>
<img src="examples/screenshot-default-last.png" width="534"><br/>
Small template (useful for mobile interfaces):
<img src="examples/screenshot-small-first.png" width="157"><br/>
<img src="examples/screenshot-small-mid.png" width="220"><br/>
<img src="examples/screenshot-small-last.png" width="157"><br/>
The small template renders the page number as a select list to save space:
<img src="examples/screenshot-small-mid-open.png" width="218">
## Installation
Install with composer:
composer require "jasongrimes/paginator:~1.0"
## Basic usage
Here's a quick example using the defaults:
<?php
require '../vendor/autoload.php';
use JasonGrimes\Paginator;
$totalItems = 1000;
$itemsPerPage = 50;
$currentPage = 8;
$urlPattern = '/foo/page/(:num)';
$paginator = new Paginator($totalItems, $itemsPerPage, $currentPage, $urlPattern);
?>
<html>
<head>
<!-- The default, built-in template supports the Twitter Bootstrap pagination styles. -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
</head>
<body>
<?php
// Example of rendering the pagination control with the built-in template.
// See below for information about using other templates or custom rendering.
echo $paginator;
?>
</body>
</html>
This will output the following:
<img src="examples/screenshot-default-mid.png" width="597">
<ul class="pagination">
<li><a href="/foo/page/7">&laquo; Previous</a></li>
<li><a href="/foo/page/1">1</a></li>
<li class="disabled"><span>...</span></li>
<li><a href="/foo/page/5">5</a></li>
<li><a href="/foo/page/6">6</a></li>
<li><a href="/foo/page/7">7</a></li>
<li class="active"><a href="/foo/page/8">8</a></li>
<li><a href="/foo/page/9">9</a></li>
<li><a href="/foo/page/10">10</a></li>
<li><a href="/foo/page/11">11</a></li>
<li><a href="/foo/page/12">12</a></li>
<li class="disabled"><span>...</span></li>
<li><a href="/foo/page/20">20</a></li>
<li><a href="/foo/page/9">Next &raquo;</a></li>
</ul>
To render it with one of the other example templates, just make sure the variable is named `$paginator` and then include the template file:
$paginator = new Paginator($totalItems, $itemsPerPage, $currentPage, $urlPattern);
include '../vendor/jasongrimes/paginator/examples/pagerSmall.phtml';
<img src="examples/screenshot-small-mid.png" width="220"><br/>
If the example templates don't suit you, you can iterate over the paginated data to render your own pagination control.
## Rendering a custom pagination control
Use `$paginator->getPages()`, `$paginator->getNextUrl()`, and `$paginator->getPrevUrl()` to render a pagination control with your own HTML.
For example:
<ul class="pagination">
<?php if ($paginator->getPrevUrl()): ?>
<li><a href="<?php echo $paginator->getPrevUrl(); ?>">&laquo; Previous</a></li>
<?php endif; ?>
<?php foreach ($paginator->getPages() as $page): ?>
<?php if ($page['url']): ?>
<li <?php echo $page['isCurrent'] ? 'class="active"' : ''; ?>>
<a href="<?php echo $page['url']; ?>"><?php echo $page['num']; ?></a>
</li>
<?php else: ?>
<li class="disabled"><span><?php echo $page['num']; ?></span></li>
<?php endif; ?>
<?php endforeach; ?>
<?php if ($paginator->getNextUrl()): ?>
<li><a href="<?php echo $paginator->getNextUrl(); ?>">Next &raquo;</a></li>
<?php endif; ?>
</ul>
<p>
<?php echo $paginator->getTotalItems(); ?> found.
Showing
<?php echo $paginator->getCurrentPageFirstItem(); ?>
-
<?php echo $paginator->getCurrentPageLastItem(); ?>.
</p>
See the [examples](examples) directory for more sample templates.
## Pages data structure
$paginator->getPages();
`getPages()` returns a data structure like the following:
array (
array ('num' => 1, 'url' => '/foo/page/1', 'isCurrent' => false),
array ('num' => '...', 'url' => NULL, 'isCurrent' => false),
array ('num' => 5, 'url' => '/foo/page/5', 'isCurrent' => false),
array ('num' => 6, 'url' => '/foo/page/6', 'isCurrent' => false),
array ('num' => 7, 'url' => '/foo/page/7', 'isCurrent' => false),
array ('num' => 8, 'url' => '/foo/page/8', 'isCurrent' => true),
array ('num' => 9, 'url' => '/foo/page/9', 'isCurrent' => false),
array ('num' => 10, 'url' => '/foo/page/10', 'isCurrent' => false),
array ('num' => 11, 'url' => '/foo/page/11', 'isCurrent' => false),
array ('num' => 12, 'url' => '/foo/page/12', 'isCurrent' => false),
array ('num' => '...', 'url' => NULL, 'isCurrent' => false),
array ('num' => 20, 'url' => '/foo/page/20', 'isCurrent' => false),
)
## Customizing the number of pages shown
By default, no more than 10 pages are shown, including the first and last page, with the overflow replaced by ellipses.
To change the default number of pages:
$paginator->setMaxPagesToShow(5);

View File

@@ -0,0 +1,29 @@
{
"name": "jasongrimes/paginator",
"type": "library",
"description": "A lightweight PHP paginator, for generating pagination controls in the style of Stack Overflow and Flickr. The 'first' and 'last' page links are shown inline as page numbers, and excess page numbers are replaced by ellipses.",
"keywords": ["paginator", "pagination", "pager"],
"homepage": "http://github.com/jasongrimes/php-paginator",
"license": "MIT",
"authors": [
{
"name": "Jason Grimes",
"email": "jason@grimesit.com"
}
],
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"autoload": {
"psr-0": {"JasonGrimes": "src/"}
},
"autoload-dev": {
"psr-0": {"JasonGrimes\\Tests": "tests/"}
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,21 @@
<?php if ($paginator->getNumPages() > 1): ?>
<ul class="pagination">
<?php if ($paginator->getPrevUrl()): ?>
<li><a href="<?php echo $paginator->getPrevUrl(); ?>">&laquo; Previous</a></li>
<?php endif; ?>
<?php foreach ($paginator->getPages() as $page): ?>
<?php if ($page['url']): ?>
<li <?php echo $page['isCurrent'] ? 'class="active"' : ''; ?>>
<a href="<?php echo $page['url']; ?>"><?php echo $page['num']; ?></a>
</li>
<?php else: ?>
<li class="disabled"><span><?php echo $page['num']; ?></span></li>
<?php endif; ?>
<?php endforeach; ?>
<?php if ($paginator->getNextUrl()): ?>
<li><a href="<?php echo $paginator->getNextUrl(); ?>">Next &raquo;</a></li>
<?php endif; ?>
</ul>
<?php endif; ?>

View File

@@ -0,0 +1,19 @@
{% if paginator.numPages > 1 %}
<ul class="pagination">
{% if paginator.prevUrl %}
<li><a href="{{ paginator.prevUrl }}">&laquo; Previous</a></li>
{% endif %}
{% for page in paginator.pages %}
{% if page.url %}
<li {{ page.isCurrent ? 'class="active"' : '' }}><a href="{{ page.url }}">{{ page.num }}</a></li>
{% else %}
<li class="disabled"><span>{{ page.num }}</span></li>
{% endif %}
{% endfor %}
{% if paginator.nextUrl %}
<li><a href="{{ paginator.nextUrl }}">Next &raquo;</a></li>
{% endif %}
</ul>
{% endif %}

View File

@@ -0,0 +1,49 @@
<?php if ($paginator->getNumPages() > 1): ?>
<div class="input-group" style="width: 1px;">
<?php if ($paginator->getPrevUrl()): ?>
<span class="input-group-btn">
<a href="<?php echo $paginator->getPrevUrl(); ?>" class="btn btn-default" type="button">&laquo; Prev</a>
</span>
<?php endif; ?>
<select class="form-control paginator-select-page" style="width: auto; cursor: pointer; -webkit-appearance: none; -moz-appearance: none; appearance: none;">
<?php foreach ($paginator->getPages() as $page): ?>
<?php if ($page['url']): ?>
<option value="<?php echo $page['url']; ?>"<?php if ($page['isCurrent']) echo ' selected'; ?>>
Page <?php echo $page['num']; ?>
</option>
<?php else: ?>
<option disabled><?php echo $page['num']; ?></option>
<?php endif; ?>
<?php endforeach; ?>
</select>
<?php if ($paginator->getNextUrl()): ?>
<span class="input-group-btn">
<a href="<?php echo $paginator->getNextUrl(); ?>" class="btn btn-default" type="button">Next &raquo;</a>
</span>
<?php endif; ?>
</div>
<?php endif; ?>
<?php /* Depends on a little bit of javascript like this being included somewhere (this example requires jquery):
$(function() {
$('.paginator-select-page').on('change', function() {
document.location = $(this).val();
});
// Workaround to prevent iOS from zooming the page when clicking the select list:
$('.paginator-select-page')
.on('focus', function() {
if (/(iPad|iPhone|iPod)/g.test(navigator.userAgent)) {
$(this).css('font-size', '16px');
}
})
.on('blur', function() {
if (/(iPad|iPhone|iPod)/g.test(navigator.userAgent)) {
$(this).css('font-size', '');
}
})
;
});
*/ ?>

View File

@@ -0,0 +1,49 @@
{% if paginator.numPages > 1 %}
<div class="input-group" style="width: 1px;">
{% if paginator.prevUrl %}
<span class="input-group-btn">
<a href="{{ paginator.prevUrl }}" class="btn btn-default" type="button">&laquo; Prev</a>
</span>
{% endif %}
<select class="form-control paginator-select-page" style="width: auto; cursor: pointer; -webkit-appearance: none; -moz-appearance: none; appearance: none;">
{% for page in paginator.pages %}
{% if page.url %}
<option value="{{ page.url }}"{{ page.isCurrent ? 'selected' : '' }}>
Page {{ page.num }}
</option>
{% else %}
<option disabled>{{ page.num }}</option>
{% endif %}
{% endfor %}
</select>
{% if paginator.nextUrl %}
<span class="input-group-btn">
<a href="{{ paginator.nextUrl }}" class="btn btn-default" type="button">Next &raquo;</a>
</span>
{% endif %}
</div>
{% endif %}
{# Depends on this little bit of javascript being included somewhere:
$(function() {
$('.paginator-select-page').on('change', function() {
document.location = $(this).val();
});
// Workaround to prevent iOS from zooming the page when clicking the select list:
$('.paginator-select-page')
.on('focus', function() {
if (/(iPad|iPhone|iPod)/g.test(navigator.userAgent)) {
$(this).css('font-size', '16px');
}
})
.on('blur', function() {
if (/(iPad|iPhone|iPod)/g.test(navigator.userAgent)) {
$(this).css('font-size', '');
}
})
;
});
#}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="vendor/autoload.php"
>
<testsuites>
<testsuite name="Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@@ -0,0 +1,345 @@
<?php
namespace JasonGrimes;
class Paginator
{
const NUM_PLACEHOLDER = '(:num)';
protected $totalItems;
protected $numPages;
protected $itemsPerPage;
protected $currentPage;
protected $urlPattern;
protected $maxPagesToShow = 10;
protected $previousText = 'Previous';
protected $nextText = 'Next';
/**
* @param int $totalItems The total number of items.
* @param int $itemsPerPage The number of items per page.
* @param int $currentPage The current page number.
* @param string $urlPattern A URL for each page, with (:num) as a placeholder for the page number. Ex. '/foo/page/(:num)'
*/
public function __construct($totalItems, $itemsPerPage, $currentPage, $urlPattern = '')
{
$this->totalItems = $totalItems;
$this->itemsPerPage = $itemsPerPage;
$this->currentPage = $currentPage;
$this->urlPattern = $urlPattern;
$this->updateNumPages();
}
protected function updateNumPages()
{
$this->numPages = ($this->itemsPerPage == 0 ? 0 : (int) ceil($this->totalItems/$this->itemsPerPage));
}
/**
* @param int $maxPagesToShow
* @throws \InvalidArgumentException if $maxPagesToShow is less than 3.
*/
public function setMaxPagesToShow($maxPagesToShow)
{
if ($maxPagesToShow < 3) {
throw new \InvalidArgumentException('maxPagesToShow cannot be less than 3.');
}
$this->maxPagesToShow = $maxPagesToShow;
}
/**
* @return int
*/
public function getMaxPagesToShow()
{
return $this->maxPagesToShow;
}
/**
* @param int $currentPage
*/
public function setCurrentPage($currentPage)
{
$this->currentPage = $currentPage;
}
/**
* @return int
*/
public function getCurrentPage()
{
return $this->currentPage;
}
/**
* @param int $itemsPerPage
*/
public function setItemsPerPage($itemsPerPage)
{
$this->itemsPerPage = $itemsPerPage;
$this->updateNumPages();
}
/**
* @return int
*/
public function getItemsPerPage()
{
return $this->itemsPerPage;
}
/**
* @param int $totalItems
*/
public function setTotalItems($totalItems)
{
$this->totalItems = $totalItems;
$this->updateNumPages();
}
/**
* @return int
*/
public function getTotalItems()
{
return $this->totalItems;
}
/**
* @return int
*/
public function getNumPages()
{
return $this->numPages;
}
/**
* @param string $urlPattern
*/
public function setUrlPattern($urlPattern)
{
$this->urlPattern = $urlPattern;
}
/**
* @return string
*/
public function getUrlPattern()
{
return $this->urlPattern;
}
/**
* @param int $pageNum
* @return string
*/
public function getPageUrl($pageNum)
{
return str_replace(self::NUM_PLACEHOLDER, $pageNum, $this->urlPattern);
}
public function getNextPage()
{
if ($this->currentPage < $this->numPages) {
return $this->currentPage + 1;
}
return null;
}
public function getPrevPage()
{
if ($this->currentPage > 1) {
return $this->currentPage - 1;
}
return null;
}
public function getNextUrl()
{
if (!$this->getNextPage()) {
return null;
}
return $this->getPageUrl($this->getNextPage());
}
/**
* @return string|null
*/
public function getPrevUrl()
{
if (!$this->getPrevPage()) {
return null;
}
return $this->getPageUrl($this->getPrevPage());
}
/**
* Get an array of paginated page data.
*
* Example:
* array(
* array ('num' => 1, 'url' => '/example/page/1', 'isCurrent' => false),
* array ('num' => '...', 'url' => NULL, 'isCurrent' => false),
* array ('num' => 3, 'url' => '/example/page/3', 'isCurrent' => false),
* array ('num' => 4, 'url' => '/example/page/4', 'isCurrent' => true ),
* array ('num' => 5, 'url' => '/example/page/5', 'isCurrent' => false),
* array ('num' => '...', 'url' => NULL, 'isCurrent' => false),
* array ('num' => 10, 'url' => '/example/page/10', 'isCurrent' => false),
* )
*
* @return array
*/
public function getPages()
{
$pages = array();
if ($this->numPages <= 1) {
return array();
}
if ($this->numPages <= $this->maxPagesToShow) {
for ($i = 1; $i <= $this->numPages; $i++) {
$pages[] = $this->createPage($i, $i == $this->currentPage);
}
} else {
// Determine the sliding range, centered around the current page.
$numAdjacents = (int) floor(($this->maxPagesToShow - 3) / 2);
if ($this->currentPage + $numAdjacents > $this->numPages) {
$slidingStart = $this->numPages - $this->maxPagesToShow + 2;
} else {
$slidingStart = $this->currentPage - $numAdjacents;
}
if ($slidingStart < 2) $slidingStart = 2;
$slidingEnd = $slidingStart + $this->maxPagesToShow - 3;
if ($slidingEnd >= $this->numPages) $slidingEnd = $this->numPages - 1;
// Build the list of pages.
$pages[] = $this->createPage(1, $this->currentPage == 1);
if ($slidingStart > 2) {
$pages[] = $this->createPageEllipsis();
}
for ($i = $slidingStart; $i <= $slidingEnd; $i++) {
$pages[] = $this->createPage($i, $i == $this->currentPage);
}
if ($slidingEnd < $this->numPages - 1) {
$pages[] = $this->createPageEllipsis();
}
$pages[] = $this->createPage($this->numPages, $this->currentPage == $this->numPages);
}
return $pages;
}
/**
* Create a page data structure.
*
* @param int $pageNum
* @param bool $isCurrent
* @return Array
*/
protected function createPage($pageNum, $isCurrent = false)
{
return array(
'num' => $pageNum,
'url' => $this->getPageUrl($pageNum),
'isCurrent' => $isCurrent,
);
}
/**
* @return array
*/
protected function createPageEllipsis()
{
return array(
'num' => '...',
'url' => null,
'isCurrent' => false,
);
}
/**
* Render an HTML pagination control.
*
* @return string
*/
public function toHtml()
{
if ($this->numPages <= 1) {
return '';
}
$html = '<ul class="pagination">';
if ($this->getPrevUrl()) {
$html .= '<li><a href="' . htmlspecialchars($this->getPrevUrl()) . '">&laquo; '. $this->previousText .'</a></li>';
}
foreach ($this->getPages() as $page) {
if ($page['url']) {
$html .= '<li' . ($page['isCurrent'] ? ' class="active"' : '') . '><a href="' . htmlspecialchars($page['url']) . '">' . htmlspecialchars($page['num']) . '</a></li>';
} else {
$html .= '<li class="disabled"><span>' . htmlspecialchars($page['num']) . '</span></li>';
}
}
if ($this->getNextUrl()) {
$html .= '<li><a href="' . htmlspecialchars($this->getNextUrl()) . '">'. $this->nextText .' &raquo;</a></li>';
}
$html .= '</ul>';
return $html;
}
public function __toString()
{
return $this->toHtml();
}
public function getCurrentPageFirstItem()
{
$first = ($this->currentPage - 1) * $this->itemsPerPage + 1;
if ($first > $this->totalItems) {
return null;
}
return $first;
}
public function getCurrentPageLastItem()
{
$first = $this->getCurrentPageFirstItem();
if ($first === null) {
return null;
}
$last = $first + $this->itemsPerPage - 1;
if ($last > $this->totalItems) {
return $this->totalItems;
}
return $last;
}
public function setPreviousText($text)
{
$this->previousText = $text;
return $this;
}
public function setNextText($text)
{
$this->nextText = $text;
return $this;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,123 @@
<?php
namespace JasonGrimes\Tests;
use JasonGrimes\Paginator;
class PaginatorTest extends \PHPUnit_Framework_TestCase
{
/** @var Paginator */
protected $paginator;
public function setUp()
{
$numItems = 100;
$itemsPerPage = 10;
$currentPage = 5;
$urlPattern = '/example/page(:num)';
$this->paginator = new Paginator($numItems, $itemsPerPage, $currentPage, $urlPattern);
}
public function testGetNextPage()
{
$this->paginator->setCurrentPage(1);
$this->assertEquals(2, $this->paginator->getNextPage());
// If we're on the last page, getNextPage() returns null.
$this->paginator->setCurrentPage($this->paginator->getNumPages());
$this->assertNull($this->paginator->getNextPage());
}
public function testGetPrevPage()
{
$this->paginator->setCurrentPage(2);
$this->assertEquals(1, $this->paginator->getPrevPage());
// If we're on the first page, getPrevPage() returns null.
$this->paginator->setCurrentPage(1);
$this->assertNull($this->paginator->getPrevPage());
}
public function testGetNextUrl()
{
$this->paginator->setCurrentPage(1);
$this->paginator->setUrlPattern('/example/page(:num)');
$this->assertEquals('/example/page2', $this->paginator->getNextUrl());
// Returns null if on the last page.
$this->paginator->setCurrentPage($this->paginator->getNumPages());
$this->assertNull($this->paginator->getNextUrl());
}
public function testGetPrevUrl()
{
$this->paginator->setCurrentPage(2);
$this->paginator->setUrlPattern('/example/page(:num)');
$this->assertEquals('/example/page1', $this->paginator->getPrevUrl());
// Returns null if on the first page.
$this->paginator->setCurrentPage(1);
$this->assertNull($this->paginator->getPrevUrl());
}
/**
* @dataProvider getTestData
*/
public function testGetPages($numPages, $currentPage, $maxPages, $expected)
{
$paginator = new Paginator($numPages, 1, $currentPage);
$paginator->setMaxPagesToShow($maxPages);
$pages = $paginator->getPages();
$pageNums = array_map(function($page) { return $page['num']; }, $pages);
$this->assertEquals($expected, $pageNums);
}
public function getTestData()
{
return array(
// num pages, current page, max pages to show, expected pagination
array(13, 2, 5, array(1, 2, 3, 4, '...', 13)),
array(13, 4, 5, array(1, '...', 3, 4, 5, '...', 13)),
array(13, 5, 5, array(1, '...', 4, 5, 6, '...', 13)),
array(13, 11, 5, array(1, '...', 10, 11, 12, 13)),
array(13, 10, 5, array(1, '...', 9, 10, 11, '...', 13)),
array(20, 1, 10, array(1, 2, 3, 4, 5, 6, 7, 8, 9, '...', 20)),
array(20, 2, 10, array(1, 2, 3, 4, 5, 6, 7, 8, 9, '...', 20)),
array(20, 20, 10, array(1, '...', 12, 13, 14, 15, 16, 17, 18, 19, 20)),
array(20, 19, 10, array(1, '...', 12, 13, 14, 15, 16, 17, 18, 19, 20)),
array(20, 10, 10, array(1, '...', 7, 8, 9, 10, 11, 12, 13, 14, '...', 20)),
array(20, 9, 10, array(1, '...', 6, 7, 8, 9, 10, 11, 12, 13, '...', 20)),
array(5, 3, 10, array(1, 2, 3, 4, 5)),
array(1, 1, 10, array()), // No pagination if there's only one page.
array(20, 5, 3, array(1, '...', 5, '...', 20)),
);
}
/**
* @dataProvider getRangeData
*/
public function testGetItemRanges($numItems, $itemsPerPage, $currentPage, $expectedFirst, $expectedLast)
{
$paginator = new Paginator($numItems, $itemsPerPage, $currentPage);
$this->assertEquals($numItems, $paginator->getTotalItems());
$this->assertEquals($expectedFirst, $paginator->getCurrentPageFirstItem());
$this->assertEquals($expectedLast, $paginator->getCurrentPageLastItem());
}
public function getRangeData()
{
return array(
// $numItems, $itemsPerPage, $currentPage, $expectedFirstItem, $expectedLastItem
array(95, 10, 1, 1, 10),
array(95, 10, 2, 11, 20),
array(95, 10, 10, 91, 95),
array(95, 10, 11, null, null), // If current page exceeds total items, first and last item are null.
);
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,34 @@
<?php
/**
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;