diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..b77c4509 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.travis.yml export-ignore +/composer.lock export-ignore +/phpcs.xml export-ignore +/phpdoc.xml export-ignore +/phpunit.xml.dist export-ignore +/tests/ export-ignore diff --git a/.gitignore b/.gitignore index 700e7853..8c6f9e56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,493 +1,8 @@ /docs/ phpdoc.dist.xml phpunit.xml - - - -# Created by https://www.gitignore.io/api/vim,linux,macos,windows,composer,intellij,sublimetext,visualstudio,visualstudiocode +/build/ ### Composer ### composer.phar /vendor/ - -# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file -# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file -composer.lock - -### Intellij ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/dictionaries - -# Sensitive or high-churn files: -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.xml -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml - -# Gradle: -.idea/**/gradle.xml -.idea/**/libraries - -# CMake -cmake-build-debug/ - -# Mongo Explorer plugin: -.idea/**/mongoSettings.xml - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Ruby plugin and RubyMine -/.rakeTasks - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -### Intellij Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -.idea/sonarlint - -### Linux ### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### macOS ### -*.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### SublimeText ### -# cache files for sublime text -*.tmlanguage.cache -*.tmPreferences.cache -*.stTheme.cache - -# workspace files are user-specific -*.sublime-workspace - -# project files should be checked into the repository, unless a significant -# proportion of contributors will probably not be using SublimeText -# *.sublime-project - -# sftp configuration file -sftp-config.json - -# Package control specific files -Package Control.last-run -Package Control.ca-list -Package Control.ca-bundle -Package Control.system-ca-bundle -Package Control.cache/ -Package Control.ca-certs/ -Package Control.merged-ca-bundle -Package Control.user-ca-bundle -oscrypto-ca-bundle.crt -bh_unicode_properties.cache - -# Sublime-github package stores a github token in this file -# https://packagecontrol.io/packages/sublime-github -GitHub.sublime-settings - -### Vim ### -# swap -[._]*.s[a-v][a-z] -[._]*.sw[a-p] -[._]s[a-v][a-z] -[._]sw[a-p] -# session -Session.vim -# temporary -.netrwhist -# auto-generated tag files -tags - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history - -### Windows ### -# Windows thumbnail cache files -Thumbs.db -ehthumbs.db -ehthumbs_vista.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - -# Windows shortcuts -*.lnk - -### VisualStudio ### -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ -**/Properties/launchSettings.json - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Uncomment the next line to ignore your web deploy settings. -# By default, sensitive information, such as encrypted password -# should be stored in the .pubxml.user file. -#*.pubxml -*.pubxml.user -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Typescript v1 declaration files -typings/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -### VisualStudio Patch ### -# By default, sensitive information, such as encrypted password -# should be stored in the .pubxml.user file. - -# End of https://www.gitignore.io/api/vim,linux,macos,windows,composer,intellij,sublimetext,visualstudio,visualstudiocode diff --git a/.travis.yml b/.travis.yml index 5df24097..cbb6b8d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,20 +2,17 @@ language: php sudo: false php: - - 5.5 - - 5.6 - - 7.0.3 - 7.1 + - 7.2 before_script: - - if [[ $TRAVIS_PHP_VERSION = 5.5 ]] ; then echo yes | pecl install apcu-4.0.10; fi; - - if [[ $TRAVIS_PHP_VERSION = 7.0.3 ]] ; then echo yes | pecl install apcu; fi; - if [[ $TRAVIS_PHP_VERSION != 'hhvm' ]]; then phpenv config-add ./tests/apc.ini; fi; - - composer install --dev --prefer-source + - composer install script: - - ./vendor/bin/phpunit - - ./vendor/bin/phpdoc + - composer test + - composer cs-check + - composer docs deploy: provider: pages diff --git a/LICENSE b/LICENSE index 9dd6265a..d823fe49 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 prismic.io (https://prismic.io). +Copyright 2018 Prismic (https://prismic.io). Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. diff --git a/README.md b/README.md index 61419dfd..3841201f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ [![alt text](https://travis-ci.org/prismicio/php-kit.png?branch=master "Travis build")](https://travis-ci.org/prismicio/php-kit) -# PHP development kit for prismic.io +# PHP development kit for Prismic + +This kit supports PHP version >= 7.1. ## Getting started @@ -106,7 +108,7 @@ Some of the kit's tests check stuff that are built on top of APC and need APC to This software is licensed under the Apache 2 license, quoted below. -Copyright 2018 Prismic.io (https://prismic.io). +Copyright 2018 Prismic (https://prismic.io). Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. diff --git a/composer.json b/composer.json index 38f82e4b..35bd5dde 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,9 @@ { "name": "prismic/php-sdk", - "description": "PHP development kit for prismic.io", - + "description": "PHP development kit for Prismic", + "config": { + "sort-packages": true + }, "autoload": { "psr-4": { "Prismic\\": "src/Prismic" @@ -12,25 +14,35 @@ "Prismic\\Test\\": "tests/Prismic" } }, - - "license": "Apache 2 license", - + "license": "Apache-2.0", "minimum-stability": "stable", - "require": { - "php": ">=5.5.0", + "php": ">=7.1", "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", "guzzlehttp/guzzle": "^6.3" }, "require-dev": { - "phpunit/phpunit": "^4.8", - "phpdocumentor/phpdocumentor": "^2.3.1" + "phpdocumentor/phpdocumentor": "dev-master", + "phpunit/phpunit": "^7", + "squizlabs/php_codesniffer": "^3.3" }, "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } + }, + "scripts": { + "check": [ + "@cs-check", + "@test" + ], + "cs-check": "phpcs", + "cs-fix": "phpcbf", + "docs": "phpdoc", + "test": "phpunit --colors=always", + "test-coverage": "phpunit --colors=always --coverage-html build/report", + "serve": "php -S 0.0.0.0:8080 -t samples samples/document-explorer.php" } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..1b541f86 --- /dev/null +++ b/composer.lock @@ -0,0 +1,4421 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "9db44d7a6080a70f8126a098e01677b8", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2018-04-22T15:46:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-03-20T17:10:46+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + } + ], + "packages-dev": [ + { + "name": "cilex/cilex", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/Cilex/Cilex.git", + "reference": "7acd965a609a56d0345e8b6071c261fbdb926cb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Cilex/Cilex/zipball/7acd965a609a56d0345e8b6071c261fbdb926cb5", + "reference": "7acd965a609a56d0345e8b6071c261fbdb926cb5", + "shasum": "" + }, + "require": { + "cilex/console-service-provider": "1.*", + "php": ">=5.3.3", + "pimple/pimple": "~1.0", + "symfony/finder": "~2.1", + "symfony/process": "~2.1" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*", + "symfony/validator": "~2.1" + }, + "suggest": { + "monolog/monolog": ">=1.0.0", + "symfony/validator": ">=1.0.0", + "symfony/yaml": ">=1.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Cilex": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "description": "The PHP micro-framework for Command line tools based on the Symfony2 Components", + "homepage": "http://cilex.github.com", + "keywords": [ + "cli", + "microframework" + ], + "time": "2014-03-29T14:03:13+00:00" + }, + { + "name": "cilex/console-service-provider", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/Cilex/console-service-provider.git", + "reference": "25ee3d1875243d38e1a3448ff94bdf944f70d24e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Cilex/console-service-provider/zipball/25ee3d1875243d38e1a3448ff94bdf944f70d24e", + "reference": "25ee3d1875243d38e1a3448ff94bdf944f70d24e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "pimple/pimple": "1.*@dev", + "symfony/console": "~2.1" + }, + "require-dev": { + "cilex/cilex": "1.*@dev", + "silex/silex": "1.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Cilex\\Provider\\Console": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "description": "Console Service Provider", + "keywords": [ + "cilex", + "console", + "pimple", + "service-provider", + "silex" + ], + "time": "2012-12-19T10:50:58+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "46afded9720f40b9dc63542af4e3e43a1177acb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/46afded9720f40b9dc63542af4e3e43a1177acb0", + "reference": "46afded9720f40b9dc63542af4e3e43a1177acb0", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", + "psr/log": "^1.0", + "symfony/process": "^2.5 || ^3.0 || ^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "time": "2018-08-08T08:57:40+00:00" + }, + { + "name": "container-interop/container-interop", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "shasum": "" + }, + "require": { + "psr/container": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "homepage": "https://github.com/container-interop/container-interop", + "time": "2017-02-14T19:40:03+00:00" + }, + { + "name": "doctrine/annotations", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": "^7.1" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2017-12-06T07:11:42+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2017-07-22T11:58:36+00:00" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09T13:34:57+00:00" + }, + { + "name": "erusev/parsedown", + "version": "1.7.1", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/92e9c27ba0e74b8b028b111d1b6f956a15c01fc1", + "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "time": "2018-03-08T01:11:30+00:00" + }, + { + "name": "jms/metadata", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/metadata.git", + "reference": "6a06970a10e0a532fb52d3959547123b84a3b3ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/6a06970a10e0a532fb52d3959547123b84a3b3ab", + "reference": "6a06970a10e0a532fb52d3959547123b84a3b3ab", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "doctrine/cache": "~1.0", + "symfony/cache": "~3.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Metadata\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Class/method/property metadata management in PHP", + "keywords": [ + "annotations", + "metadata", + "xml", + "yaml" + ], + "time": "2016-12-05T10:18:33+00:00" + }, + { + "name": "jms/parser-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/parser-lib.git", + "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/parser-lib/zipball/c509473bc1b4866415627af0e1c6cc8ac97fa51d", + "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d", + "shasum": "" + }, + "require": { + "phpoption/phpoption": ">=0.9,<2.0-dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "description": "A library for easily creating recursive-descent parsers.", + "time": "2012-11-18T18:08:43+00:00" + }, + { + "name": "jms/serializer", + "version": "1.7.1", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/serializer.git", + "reference": "4fad8bbbe76e05de3b79ffa3db027058ed3813ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/4fad8bbbe76e05de3b79ffa3db027058ed3813ff", + "reference": "4fad8bbbe76e05de3b79ffa3db027058ed3813ff", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/instantiator": "^1.0.3", + "jms/metadata": "~1.1", + "jms/parser-lib": "1.*", + "php": ">=5.5.0", + "phpcollection/phpcollection": "~0.1", + "phpoption/phpoption": "^1.1" + }, + "conflict": { + "jms/serializer-bundle": "<1.2.1", + "twig/twig": "<1.12" + }, + "require-dev": { + "doctrine/orm": "~2.1", + "doctrine/phpcr-odm": "^1.3|^2.0", + "ext-pdo_sqlite": "*", + "jackalope/jackalope-doctrine-dbal": "^1.1.5", + "phpunit/phpunit": "^4.8|^5.0", + "propel/propel1": "~1.7", + "symfony/expression-language": "^2.6|^3.0", + "symfony/filesystem": "^2.1", + "symfony/form": "~2.1|^3.0", + "symfony/translation": "^2.1|^3.0", + "symfony/validator": "^2.2|^3.0", + "symfony/yaml": "^2.1|^3.0", + "twig/twig": "~1.12|~2.0" + }, + "suggest": { + "doctrine/cache": "Required if you like to use cache functionality.", + "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", + "symfony/yaml": "Required if you'd like to serialize data to YAML format." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\Serializer": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", + "homepage": "http://jmsyst.com/libs/serializer", + "keywords": [ + "deserialization", + "jaxb", + "json", + "serialization", + "xml" + ], + "time": "2017-05-15T08:35:42+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.23.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2017-06-19T01:22:40+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2018-06-11T23:09:50+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v1.4.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51", + "reference": "f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "files": [ + "lib/bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2015-09-19T14:15:08+00:00" + }, + { + "name": "padraic/humbug_get_contents", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/humbug/file_get_contents.git", + "reference": "dcb086060c9dd6b2f51d8f7a895500307110b7a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/humbug/file_get_contents/zipball/dcb086060c9dd6b2f51d8f7a895500307110b7a7", + "reference": "dcb086060c9dd6b2f51d8f7a895500307110b7a7", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "ext-openssl": "*", + "php": "^5.3 || ^7.0 || ^7.1 || ^7.2" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.1", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": false + }, + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Humbug\\": "src/" + }, + "files": [ + "src/function.php", + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Secure wrapper for accessing HTTPS resources with file_get_contents for PHP 5.3+", + "homepage": "https://github.com/padraic/file_get_contents", + "keywords": [ + "download", + "file_get_contents", + "http", + "https", + "ssl", + "tls" + ], + "time": "2018-02-12T18:47:17+00:00" + }, + { + "name": "padraic/phar-updater", + "version": "v1.0.6", + "source": { + "type": "git", + "url": "https://github.com/humbug/phar-updater.git", + "reference": "d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/humbug/phar-updater/zipball/d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1", + "reference": "d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1", + "shasum": "" + }, + "require": { + "padraic/humbug_get_contents": "^1.0", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Humbug\\SelfUpdate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + } + ], + "description": "A thing to make PHAR self-updating easy and secure.", + "keywords": [ + "humbug", + "phar", + "self-update", + "update" + ], + "time": "2018-03-30T12:52:15+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2018-07-08T19:23:20+00:00" + }, + { + "name": "phar-io/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2018-07-08T19:19:57+00:00" + }, + { + "name": "phpcollection/phpcollection", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-collection.git", + "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", + "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", + "shasum": "" + }, + "require": { + "phpoption/phpoption": "1.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + }, + "autoload": { + "psr-0": { + "PhpCollection": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "General-Purpose Collection Library for PHP", + "keywords": [ + "collection", + "list", + "map", + "sequence", + "set" + ], + "time": "2015-05-17T12:39:23+00:00" + }, + { + "name": "phpdocumentor/fileset", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/Fileset.git", + "reference": "bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/Fileset/zipball/bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0", + "reference": "bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/finder": "~2.1" + }, + "require-dev": { + "phpunit/phpunit": "~3.7" + }, + "type": "library", + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/", + "tests/unit/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Fileset component for collecting a set of files given directories and file paths", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "files", + "fileset", + "phpdoc" + ], + "time": "2013-08-06T21:07:42+00:00" + }, + { + "name": "phpdocumentor/graphviz", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/GraphViz.git", + "reference": "a906a90a9f230535f25ea31caf81b2323956283f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/GraphViz/zipball/a906a90a9f230535f25ea31caf81b2323956283f", + "reference": "a906a90a9f230535f25ea31caf81b2323956283f", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/", + "tests/unit" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2016-02-02T13:00:08+00:00" + }, + { + "name": "phpdocumentor/phpdocumentor", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/phpDocumentor2.git", + "reference": "1cf525c384a71c0d8cc7f414b8ba3eb78168e9f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/phpDocumentor2/zipball/1cf525c384a71c0d8cc7f414b8ba3eb78168e9f4", + "reference": "1cf525c384a71c0d8cc7f414b8ba3eb78168e9f4", + "shasum": "" + }, + "require": { + "cilex/cilex": "~1.0", + "erusev/parsedown": "~1.0", + "jms/serializer": ">=0.12 < 1.8.0", + "monolog/monolog": "~1.6", + "padraic/phar-updater": "^1.0", + "php": ">=5.3.3", + "phpdocumentor/fileset": "~1.0", + "phpdocumentor/graphviz": "~1.0", + "phpdocumentor/reflection": "^3.0", + "phpdocumentor/reflection-docblock": "~2.0", + "symfony/config": "~2.3", + "symfony/console": "~2.3", + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.0", + "symfony/stopwatch": "~2.3", + "symfony/validator": "~2.2", + "twig/twig": "~1.3", + "webmozart/assert": "^1.2", + "zendframework/zend-cache": "~2.1", + "zendframework/zend-config": "~2.1", + "zendframework/zend-filter": "~2.1", + "zendframework/zend-i18n": "~2.1", + "zendframework/zend-serializer": "~2.1", + "zendframework/zend-servicemanager": "~2.1", + "zendframework/zend-stdlib": "~2.1", + "zetacomponents/document": ">=1.3.1" + }, + "require-dev": { + "behat/behat": "^3.0", + "mikey179/vfsstream": "^1.2", + "mockery/mockery": "^0.9@dev", + "phpunit/phpunit": "^4.0", + "squizlabs/php_codesniffer": "^1.4", + "symfony/expression-language": "^2.4" + }, + "suggest": { + "ext-twig": "Enabling the twig extension improves the generation of twig based templates.", + "ext-xslcache": "Enabling the XSLCache extension improves the generation of xml based templates." + }, + "bin": [ + "bin/phpdoc.php", + "bin/phpdoc" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "2.9-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/", + "tests/unit/" + ], + "Cilex\\Provider": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Documentation Generator for PHP", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "api", + "application", + "dga", + "documentation", + "phpdoc" + ], + "time": "2018-04-20T14:43:14+00:00" + }, + { + "name": "phpdocumentor/reflection", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/Reflection.git", + "reference": "793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d", + "reference": "793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^1.0", + "php": ">=5.3.3", + "phpdocumentor/reflection-docblock": "~2.0", + "psr/log": "~1.0" + }, + "require-dev": { + "behat/behat": "~2.4", + "mockery/mockery": "~0.8", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/", + "tests/unit/", + "tests/mocks/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Reflection library to do Static Analysis for PHP Projects", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2016-05-21T08:42:32+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b", + "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2016-01-25T08:17:30+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-0": { + "PhpOption\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "time": "2015-07-25T16:39:46+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2018-08-05T17:53:17+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "6.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a", + "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.1", + "phpunit/php-file-iterator": "^2.0", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.1", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-xdebug": "^2.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2018-06-01T07:51:50+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cecbc684605bb0cc288828eb5d65d93d5c676d3c", + "reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2018-06-11T11:44:00+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2018-02-01T13:07:23+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2018-02-01T13:16:43+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "7.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "34705f81bddc3f505b9599a2ef96e2b4315ba9b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/34705f81bddc3f505b9599a2ef96e2b4315ba9b8", + "reference": "34705f81bddc3f505b9599a2ef96e2b4315ba9b8", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.0", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpunit/phpunit-mock-objects": "*" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2018-08-22T06:39:21+00:00" + }, + { + "name": "pimple/pimple", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/2019c145fe393923f3441b23f29bbdfaa5c58c4d", + "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", + "homepage": "http://pimple.sensiolabs.org", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2013-11-22T08:30:29+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "shasum": "" + }, + "require": { + "php": "^7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2018-07-12T15:12:46+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "366541b989927187c4ca70490a35615d3fef2dce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce", + "reference": "366541b989927187c4ca70490a35615d3fef2dce", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "time": "2018-06-10T07:54:39+00:00" + }, + { + "name": "sebastian/environment", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2017-07-01T08:51:00+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2017-04-03T13:19:02+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.3.1", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "628a481780561150481a9ec74709092b9759b3ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/628a481780561150481a9ec74709092b9759b3ec", + "reference": "628a481780561150481a9ec74709092b9759b3ec", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2018-07-26T23:47:18+00:00" + }, + { + "name": "symfony/config", + "version": "v2.8.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "06c0be4cdd8363f3ec8d592c9a4d1b981d5052af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/06c0be4cdd8363f3ec8d592c9a4d1b981d5052af", + "reference": "06c0be4cdd8363f3ec8d592c9a4d1b981d5052af", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/filesystem": "~2.3|~3.0.0", + "symfony/polyfill-ctype": "~1.8" + }, + "require-dev": { + "symfony/yaml": "~2.7|~3.0.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T11:13:39+00:00" + }, + { + "name": "symfony/console", + "version": "v2.8.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "0c1fcbb9afb5cff992c982ff99c0434f0146dcfc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/0c1fcbb9afb5cff992c982ff99c0434f0146dcfc", + "reference": "0c1fcbb9afb5cff992c982ff99c0434f0146dcfc", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/debug": "^2.7.2|~3.0.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/process": "~2.1|~3.0.0" + }, + "suggest": { + "psr/log-implementation": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T11:13:39+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2016-07-30T07:22:48+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "84ae343f39947aa084426ed1138bb96bf94d1f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/84ae343f39947aa084426ed1138bb96bf94d1f12", + "reference": "84ae343f39947aa084426ed1138bb96bf94d1f12", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T09:03:18+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v3.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "b2da5009d9bacbd91d83486aa1f44c793a8c380d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b2da5009d9bacbd91d83486aa1f44c793a8c380d", + "reference": "b2da5009d9bacbd91d83486aa1f44c793a8c380d", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2016-07-20T05:43:46+00:00" + }, + { + "name": "symfony/finder", + "version": "v2.8.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "f0de0b51913eb2caab7dfed6413b87e14fca780e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/f0de0b51913eb2caab7dfed6413b87e14fca780e", + "reference": "f0de0b51913eb2caab7dfed6413b87e14fca780e", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T11:13:39+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2018-08-06T14:22:27+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8", + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2018-08-06T14:22:27+00:00" + }, + { + "name": "symfony/process", + "version": "v2.8.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "cc83afdb5ac99147806b3bb65a3ff1227664f596" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/cc83afdb5ac99147806b3bb65a3ff1227664f596", + "reference": "cc83afdb5ac99147806b3bb65a3ff1227664f596", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T11:13:39+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v2.8.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "12a4b0c2a1788adf16a5548ab18ab9e8801d71d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/12a4b0c2a1788adf16a5548ab18ab9e8801d71d8", + "reference": "12a4b0c2a1788adf16a5548ab18ab9e8801d71d8", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "time": "2018-07-24T10:05:38+00:00" + }, + { + "name": "symfony/translation", + "version": "v3.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "eee6c664853fd0576f21ae25725cfffeafe83f26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/eee6c664853fd0576f21ae25725cfffeafe83f26", + "reference": "eee6c664853fd0576f21ae25725cfffeafe83f26", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/config": "<2.8" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/intl": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "time": "2016-07-30T07:22:48+00:00" + }, + { + "name": "symfony/validator", + "version": "v2.8.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/validator.git", + "reference": "30352cf38e35ef34cf60676ee72ff3f84c551fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/validator/zipball/30352cf38e35ef34cf60676ee72ff3f84c551fac", + "reference": "30352cf38e35ef34cf60676ee72ff3f84c551fac", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation": "~2.4|~3.0.0" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0", + "egulias/email-validator": "^1.2.1", + "symfony/config": "~2.2|~3.0.0", + "symfony/expression-language": "~2.4|~3.0.0", + "symfony/http-foundation": "~2.3|~3.0.0", + "symfony/intl": "~2.7.25|^2.8.18|~3.2.5", + "symfony/property-access": "~2.3|~3.0.0", + "symfony/yaml": "^2.0.5|~3.0.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", + "doctrine/cache": "For using the default cached annotation reader and metadata cache.", + "egulias/email-validator": "Strict (RFC compliant) email validation", + "symfony/config": "", + "symfony/expression-language": "For using the 2.4 Expression validator", + "symfony/http-foundation": "", + "symfony/intl": "", + "symfony/property-access": "For using the 2.4 Validator API", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Validator\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Validator Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T11:13:39+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" + }, + { + "name": "twig/twig", + "version": "v1.35.4", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "7e081e98378a1e78c29cc9eba4aefa5d78a05d2a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/7e081e98378a1e78c29cc9eba4aefa5d78a05d2a", + "reference": "7e081e98378a1e78c29cc9eba4aefa5d78a05d2a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-ctype": "^1.8" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/debug": "^2.7", + "symfony/phpunit-bridge": "^3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.35-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + }, + { + "name": "Twig Team", + "homepage": "https://twig.symfony.com/contributors", + "role": "Contributors" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "time": "2018-07-13T07:12:17+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2018-01-29T19:49:41+00:00" + }, + { + "name": "zendframework/zend-cache", + "version": "2.8.2", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-cache.git", + "reference": "4983dff629956490c78b88adcc8ece4711d7d8a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-cache/zipball/4983dff629956490c78b88adcc8ece4711d7d8a3", + "reference": "4983dff629956490c78b88adcc8ece4711d7d8a3", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "zendframework/zend-eventmanager": "^2.6.3 || ^3.2", + "zendframework/zend-servicemanager": "^2.7.8 || ^3.3", + "zendframework/zend-stdlib": "^2.7.7 || ^3.1" + }, + "provide": { + "psr/cache-implementation": "1.0", + "psr/simple-cache-implementation": "1.0" + }, + "require-dev": { + "cache/integration-tests": "^0.16", + "phpbench/phpbench": "^0.13", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-serializer": "^2.6", + "zendframework/zend-session": "^2.7.4" + }, + "suggest": { + "ext-apc": "APC or compatible extension, to use the APC storage adapter", + "ext-apcu": "APCU >= 5.1.0, to use the APCu storage adapter", + "ext-dba": "DBA, to use the DBA storage adapter", + "ext-memcache": "Memcache >= 2.0.0 to use the Memcache storage adapter", + "ext-memcached": "Memcached >= 1.0.0 to use the Memcached storage adapter", + "ext-mongo": "Mongo, to use MongoDb storage adapter", + "ext-mongodb": "MongoDB, to use the ExtMongoDb storage adapter", + "ext-redis": "Redis, to use Redis storage adapter", + "ext-wincache": "WinCache, to use the WinCache storage adapter", + "ext-xcache": "XCache, to use the XCache storage adapter", + "mongodb/mongodb": "Required for use with the ext-mongodb adapter", + "mongofill/mongofill": "Alternative to ext-mongo - a pure PHP implementation designed as a drop in replacement", + "zendframework/zend-serializer": "Zend\\Serializer component", + "zendframework/zend-session": "Zend\\Session component" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8.x-dev", + "dev-develop": "2.9.x-dev" + }, + "zf": { + "component": "Zend\\Cache", + "config-provider": "Zend\\Cache\\ConfigProvider" + } + }, + "autoload": { + "files": [ + "autoload/patternPluginManagerPolyfill.php" + ], + "psr-4": { + "Zend\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Caching implementation with a variety of storage options, as well as codified caching strategies for callbacks, classes, and output", + "keywords": [ + "ZendFramework", + "cache", + "psr-16", + "psr-6", + "zf" + ], + "time": "2018-05-01T21:58:00+00:00" + }, + { + "name": "zendframework/zend-config", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-config.git", + "reference": "2920e877a9f6dca9fa8f6bd3b1ffc2e19bb1e30d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-config/zipball/2920e877a9f6dca9fa8f6bd3b1ffc2e19bb1e30d", + "reference": "2920e877a9f6dca9fa8f6bd3b1ffc2e19bb1e30d", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-filter": "^2.6", + "zendframework/zend-i18n": "^2.5", + "zendframework/zend-json": "^2.6.1", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" + }, + "suggest": { + "zendframework/zend-filter": "Zend\\Filter component", + "zendframework/zend-i18n": "Zend\\I18n component", + "zendframework/zend-json": "Zend\\Json to use the Json reader or writer classes", + "zendframework/zend-servicemanager": "Zend\\ServiceManager for use with the Config Factory to retrieve reader and writer instances" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev", + "dev-develop": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Config\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides a nested object property based user interface for accessing this configuration data within application code", + "homepage": "https://github.com/zendframework/zend-config", + "keywords": [ + "config", + "zf2" + ], + "time": "2016-02-04T23:01:10+00:00" + }, + { + "name": "zendframework/zend-eventmanager", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-eventmanager.git", + "reference": "a5e2583a211f73604691586b8406ff7296a946dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/a5e2583a211f73604691586b8406ff7296a946dd", + "reference": "a5e2583a211f73604691586b8406ff7296a946dd", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "athletic/athletic": "^0.1", + "container-interop/container-interop": "^1.1.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-stdlib": "^2.7.3 || ^3.0" + }, + "suggest": { + "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", + "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev", + "dev-develop": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\EventManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Trigger and listen to events within a PHP application", + "homepage": "https://github.com/zendframework/zend-eventmanager", + "keywords": [ + "event", + "eventmanager", + "events", + "zf2" + ], + "time": "2018-04-25T15:33:34+00:00" + }, + { + "name": "zendframework/zend-filter", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-filter.git", + "reference": "7b997dbe79459f1652deccc8786d7407fb66caa9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-filter/zipball/7b997dbe79459f1652deccc8786d7407fb66caa9", + "reference": "7b997dbe79459f1652deccc8786d7407fb66caa9", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "zendframework/zend-stdlib": "^2.7.7 || ^3.1" + }, + "conflict": { + "zendframework/zend-validator": "<2.10.1" + }, + "require-dev": { + "pear/archive_tar": "^1.4.3", + "phpunit/phpunit": "^5.7.23 || ^6.4.3", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-crypt": "^3.2.1", + "zendframework/zend-servicemanager": "^2.7.8 || ^3.3", + "zendframework/zend-uri": "^2.6" + }, + "suggest": { + "zendframework/zend-crypt": "Zend\\Crypt component, for encryption filters", + "zendframework/zend-i18n": "Zend\\I18n component for filters depending on i18n functionality", + "zendframework/zend-servicemanager": "Zend\\ServiceManager component, for using the filter chain functionality", + "zendframework/zend-uri": "Zend\\Uri component, for the UriNormalize filter" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8.x-dev", + "dev-develop": "2.9.x-dev" + }, + "zf": { + "component": "Zend\\Filter", + "config-provider": "Zend\\Filter\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Zend\\Filter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides a set of commonly needed data filters", + "keywords": [ + "ZendFramework", + "filter", + "zf" + ], + "time": "2018-04-11T16:20:04+00:00" + }, + { + "name": "zendframework/zend-hydrator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-hydrator.git", + "reference": "22652e1661a5a10b3f564cf7824a2206cf5a4a65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-hydrator/zipball/22652e1661a5a10b3f564cf7824a2206cf5a4a65", + "reference": "22652e1661a5a10b3f564cf7824a2206cf5a4a65", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "^2.0@dev", + "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", + "zendframework/zend-filter": "^2.6", + "zendframework/zend-inputfilter": "^2.6", + "zendframework/zend-serializer": "^2.6.1", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" + }, + "suggest": { + "zendframework/zend-eventmanager": "^2.6.2 || ^3.0, to support aggregate hydrator usage", + "zendframework/zend-filter": "^2.6, to support naming strategy hydrator usage", + "zendframework/zend-serializer": "^2.6.1, to use the SerializableStrategy", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3, to support hydrator plugin manager usage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-release-1.0": "1.0-dev", + "dev-release-1.1": "1.1-dev", + "dev-master": "2.0-dev", + "dev-develop": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Hydrator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-hydrator", + "keywords": [ + "hydrator", + "zf2" + ], + "time": "2016-02-18T22:38:26+00:00" + }, + { + "name": "zendframework/zend-i18n", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-i18n.git", + "reference": "6d69af5a04e1a4de7250043cb1322f077a0cdb7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/6d69af5a04e1a4de7250043cb1322f077a0cdb7f", + "reference": "6d69af5a04e1a4de7250043cb1322f077a0cdb7f", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", + "zendframework/zend-cache": "^2.6.1", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-config": "^2.6", + "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", + "zendframework/zend-filter": "^2.6.1", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", + "zendframework/zend-validator": "^2.6", + "zendframework/zend-view": "^2.6.3" + }, + "suggest": { + "ext-intl": "Required for most features of Zend\\I18n; included in default builds of PHP", + "zendframework/zend-cache": "Zend\\Cache component", + "zendframework/zend-config": "Zend\\Config component", + "zendframework/zend-eventmanager": "You should install this package to use the events in the translator", + "zendframework/zend-filter": "You should install this package to use the provided filters", + "zendframework/zend-i18n-resources": "Translation resources", + "zendframework/zend-servicemanager": "Zend\\ServiceManager component", + "zendframework/zend-validator": "You should install this package to use the provided validators", + "zendframework/zend-view": "You should install this package to use the provided view helpers" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.9.x-dev", + "dev-develop": "2.10.x-dev" + }, + "zf": { + "component": "Zend\\I18n", + "config-provider": "Zend\\I18n\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Zend\\I18n\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Provide translations for your application, and filter and validate internationalized values", + "keywords": [ + "ZendFramework", + "i18n", + "zf" + ], + "time": "2018-05-16T16:39:13+00:00" + }, + { + "name": "zendframework/zend-json", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-json.git", + "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-json/zipball/4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", + "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-stdlib": "^2.7.7 || ^3.1" + }, + "suggest": { + "zendframework/zend-json-server": "For implementing JSON-RPC servers", + "zendframework/zend-xml2json": "For converting XML documents to JSON" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev", + "dev-develop": "3.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Json\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP", + "keywords": [ + "ZendFramework", + "json", + "zf" + ], + "time": "2018-01-04T17:51:34+00:00" + }, + { + "name": "zendframework/zend-serializer", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-serializer.git", + "reference": "0172690db48d8935edaf625c4cba38b79719892c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/0172690db48d8935edaf625c4cba38b79719892c", + "reference": "0172690db48d8935edaf625c4cba38b79719892c", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "zendframework/zend-json": "^2.5 || ^3.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.25 || ^6.4.4", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-math": "^2.6 || ^3.0", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" + }, + "suggest": { + "zendframework/zend-math": "(^2.6 || ^3.0) To support Python Pickle serialization", + "zendframework/zend-servicemanager": "(^2.7.5 || ^3.0.3) To support plugin manager support" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.9.x-dev", + "dev-develop": "2.10.x-dev" + }, + "zf": { + "component": "Zend\\Serializer", + "config-provider": "Zend\\Serializer\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Zend\\Serializer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides an adapter based interface to simply generate storable representation of PHP types by different facilities, and recover", + "keywords": [ + "ZendFramework", + "serializer", + "zf" + ], + "time": "2018-05-14T18:45:18+00:00" + }, + { + "name": "zendframework/zend-servicemanager", + "version": "2.7.11", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-servicemanager.git", + "reference": "99ec9ed5d0f15aed9876433c74c2709eb933d4c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/99ec9ed5d0f15aed9876433c74c2709eb933d4c7", + "reference": "99ec9ed5d0f15aed9876433c74c2709eb933d4c7", + "shasum": "" + }, + "require": { + "container-interop/container-interop": "~1.0", + "php": "^5.5 || ^7.0" + }, + "require-dev": { + "athletic/athletic": "dev-master", + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-di": "~2.5", + "zendframework/zend-mvc": "~2.5" + }, + "suggest": { + "ocramius/proxy-manager": "ProxyManager 0.5.* to handle lazy initialization of services", + "zendframework/zend-di": "Zend\\Di component" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev", + "dev-develop": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\ServiceManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-servicemanager", + "keywords": [ + "servicemanager", + "zf2" + ], + "time": "2018-06-22T14:49:54+00:00" + }, + { + "name": "zendframework/zend-stdlib", + "version": "2.7.7", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-stdlib.git", + "reference": "0e44eb46788f65e09e077eb7f44d2659143bcc1f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/0e44eb46788f65e09e077eb7f44d2659143bcc1f", + "reference": "0e44eb46788f65e09e077eb7f44d2659143bcc1f", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-hydrator": "~1.1" + }, + "require-dev": { + "athletic/athletic": "~0.1", + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-config": "~2.5", + "zendframework/zend-eventmanager": "~2.5", + "zendframework/zend-filter": "~2.5", + "zendframework/zend-inputfilter": "~2.5", + "zendframework/zend-serializer": "~2.5", + "zendframework/zend-servicemanager": "~2.5" + }, + "suggest": { + "zendframework/zend-eventmanager": "To support aggregate hydrator usage", + "zendframework/zend-filter": "To support naming strategy hydrator usage", + "zendframework/zend-serializer": "Zend\\Serializer component", + "zendframework/zend-servicemanager": "To support hydrator plugin manager usage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-release-2.7": "2.7-dev", + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Stdlib\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-stdlib", + "keywords": [ + "stdlib", + "zf2" + ], + "time": "2016-04-12T21:17:31+00:00" + }, + { + "name": "zetacomponents/base", + "version": "1.9.1", + "source": { + "type": "git", + "url": "https://github.com/zetacomponents/Base.git", + "reference": "489e20235989ddc97fdd793af31ac803972454f1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zetacomponents/Base/zipball/489e20235989ddc97fdd793af31ac803972454f1", + "reference": "489e20235989ddc97fdd793af31ac803972454f1", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "~5.7", + "zetacomponents/unit-test": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "src" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Sergey Alexeev" + }, + { + "name": "Sebastian Bergmann" + }, + { + "name": "Jan Borsodi" + }, + { + "name": "Raymond Bosman" + }, + { + "name": "Frederik Holljen" + }, + { + "name": "Kore Nordmann" + }, + { + "name": "Derick Rethans" + }, + { + "name": "Vadym Savchuk" + }, + { + "name": "Tobias Schlitt" + }, + { + "name": "Alexandru Stanoi" + } + ], + "description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.", + "homepage": "https://github.com/zetacomponents", + "time": "2017-11-28T11:30:00+00:00" + }, + { + "name": "zetacomponents/document", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/zetacomponents/Document.git", + "reference": "688abfde573cf3fe0730f82538fbd7aa9fc95bc8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zetacomponents/Document/zipball/688abfde573cf3fe0730f82538fbd7aa9fc95bc8", + "reference": "688abfde573cf3fe0730f82538fbd7aa9fc95bc8", + "shasum": "" + }, + "require": { + "zetacomponents/base": "*" + }, + "require-dev": { + "zetacomponents/unit-test": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Sebastian Bergmann" + }, + { + "name": "Kore Nordmann" + }, + { + "name": "Derick Rethans" + }, + { + "name": "Tobias Schlitt" + }, + { + "name": "Alexandru Stanoi" + } + ], + "description": "The Document components provides a general conversion framework for different semantic document markup languages like XHTML, Docbook, RST and similar.", + "homepage": "https://github.com/zetacomponents", + "time": "2013-12-19T11:40:00+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "phpdocumentor/phpdocumentor": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1", + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*" + }, + "platform-dev": [] +} diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 00000000..d351e324 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,37 @@ + + + Coding Standard for the Prismic PHP Kit based on Zend Framework Coding Standard + + + src + tests + + + + + + + + + + + + + + + + + + + + + + + + + + + */tests/* + + + diff --git a/samples/document-explorer.php b/samples/document-explorer.php new file mode 100644 index 00000000..1b7f1a7e --- /dev/null +++ b/samples/document-explorer.php @@ -0,0 +1,205 @@ + 'https://your-repository-name.cdn.prismic.io/api/v2', + 'token' => null, + ]; + + require_once __DIR__ . '/../vendor/autoload.php'; + + $finder = new Finder(); + echo (string) $finder; + + + class Finder + { + /** @var Api */ + private $api; + + /** @var stdClass */ + private $document; + + public function __construct() + { + try { + $this->api = Api::get(PRISMIC_CONFIG['api'], PRISMIC_CONFIG['token']); + $document = isset($_GET['id']) ? $this->findById($_GET['id']) : null; + $document = $document ? $document : $this->mostRecent(); + $this->document = $document; + } catch (Exception\ExceptionInterface $e) { + $this->invalidRepo($e); + exit; + } + } + + public function mostRecent() :? stdClass + { + /** @var SearchForm $form */ + $form = $this->api->forms()->everything; + $form = $form->ref($this->api->ref()); + $form = $form->orderings('[document.last_publication_date desc]'); + $response = $form->submit(); + if (isset($response->results) && count($response->results) >= 1) { + return current($response->results); + } + return null; + } + + public function findById(string $id) :? stdClass + { + return $this->api->getByID($id); + } + + public function __toString() : string + { + return $this->header() . $this->body() . $this->footer(); + } + + public function body() : string + { + $markup = []; + $markup[] = '
'; + $markup[] = '
'; + $title = sprintf( + 'Viewing Document ID# %s of type “%s”', + $this->document->id, + $this->document->type + ); + $markup[] = sprintf('

%s

', $title); + $markup[] = '
'; + $markup[] = '
'; + $markup[] = $this->printJson(); + $markup[] = '
'; + $markup[] = '
'; + $markup[] = $this->listLinks(); + $markup[] = $this->listRecentDocs(); + $markup[] = '
'; + return implode("\n", $markup); + } + + private function printJson() + { + $markup = ['
'];
+            $markup[] = htmlentities(json_encode($this->document, JSON_PRETTY_PRINT));
+            $markup[] = '
'; + return implode("\n", $markup); + } + + private function recentDocs(int $count = 10) : array + { + /** @var SearchForm $form */ + $form = $this->api->forms()->everything; + $form = $form->ref($this->api->ref()); + $form = $form->orderings('[document.last_publication_date desc]'); + $response = $form->submit(); + $out = []; + if (isset($response->results) && count($response->results) >= 1) { + foreach ($response->results as $doc) { + $out[] = $doc; + if (count($out) >= $count) { + break; + } + } + } + return $out; + } + + private function listRecentDocs(int $count = 10) : string + { + $markup = []; + $markup[] = '
'; + $markup[] = '
Recent Documents
'; + foreach ($this->recentDocs($count) as $link) { + $markup[] = sprintf( + 'ID: %1$s, Type: %2$s', + $link->id, + $link->type + ); + } + $markup[] = '
'; + return implode("\n", $markup); + } + + private function listLinks() : string + { + $markup = []; + $markup[] = '
'; + $markup[] = '
Linked Documents
'; + $seen = []; + foreach ($this->document->linked_documents as $link) { + if (in_array($link->id, $seen)) { + continue; + } + $seen[] = $link->id; + $markup[] = sprintf( + 'ID: %1$s, Type: %2$s', + $link->id, + $link->type + ); + } + $markup[] = '
'; + return implode("\n", $markup); + } + + public function header() : string + { + return <<<'HEADER' + + + + + + Prismic Document Browser + + + +
+HEADER; + } + + public function footer() : string + { + return '
'; + } + + private function invalidRepo(Exception\ExceptionInterface $e) + { + $markup = []; + $markup[] = '

Failed to Retrieve Api Data

'; + $markup[] = '

Check the repository URL and access token you configured before running this script.

'; + $markup[] = sprintf('

%s', $e->getMessage()); + $markup[] = '

'; + + echo $this->header() . implode("\n", $markup) . $this->footer(); + } + } +} diff --git a/samples/dom-helpers-examples.php b/samples/dom-helpers-examples.php index 8ff1f147..032623ab 100644 --- a/samples/dom-helpers-examples.php +++ b/samples/dom-helpers-examples.php @@ -13,7 +13,7 @@ class ExampleLinkResolver extends LinkResolver { - public function resolve($link) + public function resolve($link) : string { if ($link->isBroken) { return '/404'; diff --git a/samples/usage.php b/samples/usage.php index 6950cb4d..aa091f3d 100644 --- a/samples/usage.php +++ b/samples/usage.php @@ -4,11 +4,11 @@ use Prismic\Api; -$options = array( +$options = [ 'prismic.ref' => false, 'prismic.api' => "https://your-repository-name.prismic.io/api/v2", 'prismic.token' => "Your permanent token", -); +]; // retrieve the main information from the api, form and repositories ... $api = Api::get($options['prismic.api'], $options['prismic.token']); diff --git a/src/Prismic/Api.php b/src/Prismic/Api.php index 14633674..7dcba937 100644 --- a/src/Prismic/Api.php +++ b/src/Prismic/Api.php @@ -1,26 +1,21 @@ the kit's README file) */ class Api @@ -29,7 +24,7 @@ class Api /** * Kit version number */ - const VERSION = "3.0.0"; + const VERSION = "5.0.0"; /** * Name of the cookie that will be used to remember the preview reference @@ -42,70 +37,112 @@ class Api const EXPERIMENTS_COOKIE = "io.prismic.experiment"; /** - * string the API's access token to be used with each API call + * The API's access token to be used with each API call + * @var string|null */ protected $accessToken; + /** - * ApiData the raw data of the /api document (prefer to use this class's instance methods) + * An instance of ApiData containing information about types, tags and refs etc + * @var ApiData */ protected $data; + /** - * CacheInterface the cache object specifying how to store the cache + * The cache instance + * @var CacheInterface */ private $cache; + /** - * Client + * Guzzle HTTP Client + * @var ClientInterface */ private $httpClient; - /** - * Private constructor, not be used outside of this class. - */ private function __construct( - $data /**< string */, - $accessToken = null /**< optional access token, if the API is private */, - Client $httpClient = null, - CacheInterface $cache = null) - { + ApiData $data, + ?string $accessToken = null, + ?ClientInterface $httpClient = null, + ?CacheInterface $cache = null + ) { $this->data = $data; $this->accessToken = $accessToken; - $this->httpClient = is_null($httpClient) ? new Client() : $httpClient; - $this->cache = is_null($cache) ? self::defaultCache() : $cache; + $this->httpClient = is_null($httpClient) ? new Client() : $httpClient; + $this->cache = is_null($cache) ? self::defaultCache() : $cache; + } + + /** + * This is the factory method with which to retrieve your API client instance + * + * If your API is set to "public" or "open", you can instantiate your Api object just like this: + * Api::get('https://your-repository-name.prismic.io/api/v2') + * + * @param string $action The URL of your repository API's endpoint + * @param string $accessToken A permanent access token to use if your repository API is set to private + * @param ClientInterface $httpClient Custom Guzzle http client + * @param CacheInterface $cache Cache implementation + * @param int $apiCacheTTL Max time to keep the API object in cache (in seconds) + * @return self + */ + public static function get( + string $action, + ?string $accessToken = null, + ?ClientInterface $httpClient = null, + ?CacheInterface $cache = null, + int $apiCacheTTL = 5 + ) : self { + $cache = is_null($cache) ? self::defaultCache() : $cache; + $cacheKey = $action . (empty($accessToken) ? "" : ("#" . $accessToken)); + $apiData = $cache->get($cacheKey); + + if (is_string($apiData) && ! empty($apiData)) { + return new self(unserialize($apiData), $accessToken, $httpClient, $cache); + } + + $url = $accessToken ? Utils::buildUrl($action, [ 'access_token' => $accessToken]) : $action; + $httpClient = is_null($httpClient) ? new Client() : $httpClient; + try { + /** @var \Psr\Http\Message\ResponseInterface $response */ + $response = $httpClient->request('GET', $url); + } catch (GuzzleException $guzzleException) { + throw Exception\RequestFailureException::fromGuzzleException($guzzleException); + } + + $apiData = ApiData::withJsonString((string) $response->getBody()); + $api = new self($apiData, $accessToken, $httpClient, $cache); + $cache->set($cacheKey, serialize($apiData), $apiCacheTTL); + + return $api; } /** * Returns all of the repository's references (queryable points in time) * - * @return array the array of references, with their IDs, labels, ... + * @return Ref[] */ - public function refs() + public function refs() : array { - $refs = $this->data->getRefs(); - $groupBy = array(); - foreach ($refs as $ref) { - if (isset($groupBy[$ref->getLabel()])) { - $arr = $groupBy[$ref->getLabel()]; - array_push($arr, $ref); - $groupBy[$ref->getLabel()] = $arr; - } else { - $groupBy[$ref->getLabel()] = array($ref); + $groupBy = []; + foreach ($this->data->getRefs() as $ref) { + $label = $ref->getLabel(); + if (! isset($groupBy[$label])) { + $groupBy[$label] = $ref; } } - $results = array(); - foreach ($groupBy as $label => $values) { - $results[$label] = $values[0]; - } - - return $results; + return $groupBy; } /** - * @param string $label the label of the requested ref + * Return the ref identified by the given label * - * @return Ref a reference or null + * @param string $label The label of the requested ref + * + * @return Ref|null a reference or null */ - public function getRef($label) { + public function getRefFromLabel(string $label) :? Ref + { $refs = $this->refs(); return $refs[$label]; } @@ -116,7 +153,7 @@ public function getRef($label) { * * @return array the array of bookmarks */ - public function bookmarks() + public function bookmarks() : array { return $this->data->getBookmarks(); } @@ -132,7 +169,7 @@ public function bookmarks() * * @return string|null the ID string for a given bookmark name */ - public function bookmark($name) + public function bookmark(string $name) :? string { $bookmarks = $this->bookmarks(); if (isset($bookmarks[$name])) { @@ -146,11 +183,11 @@ public function bookmark($name) * Returns the master ref repository: the ref which is to be used to query content * that is live right now. * - * @return string the master ref + * @return Ref the master ref */ - public function master() + public function master() : Ref { - $masters = array_filter($this->data->getRefs(), function ($ref) { + $masters = array_filter($this->data->getRefs(), function (Ref $ref) { return $ref->isMasterRef() == true; }); @@ -158,45 +195,20 @@ public function master() } /** - * Returns all forms of type Prismic::SearchForm that are available for this repository's API. - * The intended syntax of a call is: api->forms()->everything->query(query)->ref(ref)->submit(). - * Learn more about those keywords in prismic.io's documentation on our developers' portal. - * - * @return all forms + * Returns the form of type Prismic::SearchForm based on its name. + * The intended syntax of a call is: api->form('everything')->query(query)->ref(ref)->submit(). + * Learn more about those keywords in Prismic's documentation on our developers' portal. */ - public function forms() + public function form(string $formName) : SearchForm { $forms = $this->data->getForms(); - $rforms = new \stdClass(); - foreach ($forms as $key => $form) { - - $fields = array(); - foreach ($form->fields as $name => $field) { - $maybeDefault = isset($field->default) ? $field->default : null; - $isMultiple = isset($field->multiple) ? $field->multiple : false; - $fields[$name] = new FieldForm($field->type, $isMultiple, $maybeDefault); - } + $formObject = Form::withJsonObject($forms[$formName]); + $data = $formObject->defaultData(); - $f = new Form( - isset($form->name) ? $form->name : null, - $form->method, - isset($form->rel) ? $form->rel : null, - $form->enctype, - $form->action, - $fields - ); - - $data = $f->defaultData(); - $rforms->$key = new SearchForm($this, $f, $data); - } - - return $rforms; + return new SearchForm($this->httpClient, $this->cache, $formObject, $data); } - /** - * @return \Prismic\Experiments - */ - public function getExperiments() + public function getExperiments() : Experiments { return $this->data->getExperiments(); } @@ -204,15 +216,20 @@ public function getExperiments() /** * Return the URL to display a given preview * @param string $token as received from Prismic server to identify the content to preview - * @param Prismic::LinkResolver $linkResolver the link resolver to build URL for your site + * @param LinkResolver $linkResolver the link resolver to build URL for your site * @param string $defaultUrl the URL to default to return if the preview doesn't correspond to a document * (usually the home page of your site) * @return string the URL you should redirect the user to preview the requested change */ - public function previewSession($token, $linkResolver, $defaultUrl) + public function previewSession(string $token, LinkResolver $linkResolver, string $defaultUrl) : string { - $response = $this->getHttpClient()->get($token); - $response = json_decode($response->getBody(true)); + try { + $response = $this->getHttpClient()->request('GET', $token); + } catch (GuzzleException $guzzleException) { + throw Exception\RequestFailureException::fromGuzzleException($guzzleException); + } + /** @var \Psr\Http\Message\ResponseInterface $response */ + $response = \json_decode($response->getBody()); if (isset($response->mainDocument)) { $documents = $this ->query(Predicates::at("document.id", $response->mainDocument), ['ref' => $token, 'lang' => '*']) @@ -227,120 +244,52 @@ public function previewSession($token, $linkResolver, $defaultUrl) } /** - * Returning the URL of the endpoint to initiate OAuth authentication. - * - * @return string the URL of the endpoint + * Return the URL of the endpoint to initiate OAuth authentication. */ - public function oauthInitiateEndpoint() + public function oauthInitiateEndpoint() : string { return $this->data->getOauthInitiate(); } /** - * Returning the URL of the endpoint to use OAuth authentication. - * - * @return string the URL of the endpoint + * Return the URL of the endpoint to use OAuth authentication. */ - public function oauthTokenEndpoint() + public function oauthTokenEndpoint() : string { return $this->data->getOauthToken(); } /** * Accessing raw data returned by the /api endpoint - * - * @return ApiData the raw data */ - public function getData() + public function getData() : ApiData { return $this->data; } /** * Accessing the cache object specifying how to store the cache - * - * @return CacheInterface the cache object itself */ - public function getCache() + public function getCache() : CacheInterface { return $this->cache; } /** * Accessing the underlying Guzzle HTTP client - * - * @return HttpAdapterInterface */ - public function getHttpClient() + public function getHttpClient() : ClientInterface { return $this->httpClient; } - /** - * This is the endpoint to build your API, and is a static method. - * If your API is set to "public" or "open", you can instantiate your Api object just like this: - * Api::get('https://your-repository-name.prismic.io/api/v2') - * - * @param string $action the URL of your repository API's endpoint - * @param string $accessToken a permanent access token to use to access your content, for instance if your repository API is set to private - * @param Client $httpClient Custom Guzzle http client - * @param CacheInterface $cache Cache implementation - * @param int $apiCacheTTL max time to keep the API object in cache (in seconds) - * - * \throws RuntimeException - * - * @return Api the Api object, usable to perform queries - */ - public static function get($action, $accessToken = null, $httpClient = null, CacheInterface $cache = null, $apiCacheTTL = 5) - { - $cache = is_null($cache) ? self::defaultCache() : $cache; - $cacheKey = $action . (is_null($accessToken) ? "" : ("#" . $accessToken)); - $apiData = $cache->get($cacheKey); - $api = $apiData ? new Api(unserialize($apiData), $accessToken, $httpClient, $cache) : null; - if ($api) { - return $api; - } else { - $url = $action . ($accessToken ? '?access_token=' . $accessToken : ''); - $httpClient = is_null($httpClient) ? new Client() : $httpClient; - $response = $httpClient->get($url); - $response = json_decode($response->getBody(true)); - $experiments = isset($response->experiments) - ? Experiments::parse($response->experiments) - : new Experiments(array(), array()); - - if (!$response) { - throw new \RuntimeException('Unable to decode the json response'); - } - - $apiData = new ApiData( - array_map( - function ($ref) { - return Ref::parse($ref); - }, - $response->refs - ), - (array)$response->bookmarks, - (array)$response->types, - $response->tags, - (array)$response->forms, - $experiments, - $response->oauth_initiate, - $response->oauth_token - ); - - $api = new Api($apiData, $accessToken, $httpClient, $cache); - $cache->set($cacheKey, serialize($apiData), $apiCacheTTL); - - return $api; - } - } - /** * Submit several requests in parallel * + * @TODO Discover the use-case for this method and either refactor it or remove it * @return array */ - public function submit() + public function submit() : array { $numargs = func_num_args(); if ($numargs == 1 && is_array(func_get_arg(0))) { @@ -348,7 +297,7 @@ public function submit() } else { $forms = func_get_args(); } - $responses = array(); + $responses = []; // Get what we can from the cache $all_urls = []; @@ -379,8 +328,8 @@ public function submit() $cacheDuration = (int) $groups[1]; } $json = json_decode($response->getBody(true)); - if (!isset($json)) { - throw new \RuntimeException("Unable to decode json response"); + if (! isset($json)) { + throw new Exception\RuntimeException("Unable to decode json response"); } if ($cacheDuration !== null) { $expiration = $cacheDuration; @@ -397,10 +346,8 @@ public function submit() /** * If a preview cookie is set, return the ref stored in that cookie - * - * @return string|null */ - private function getPreviewRef() + private function getPreviewRef() :? string { $cookieNames = [ str_replace(['.',' '], '_', self::PREVIEW_COOKIE), @@ -417,10 +364,8 @@ private function getPreviewRef() /** * If an experiment cookie is set, return the ref as determined by \Prismic\Experiments::refFromCookie - * - * @return string|null */ - private function getExperimentRef() + private function getExperimentRef() :? string { $cookieNames = [ str_replace(['.',' '], '_', self::EXPERIMENTS_COOKIE), @@ -438,20 +383,16 @@ private function getExperimentRef() /** * Whether the current ref in use is a preview, i.e. the user is in preview mode - * - * @return bool */ - public function inPreview() + public function inPreview() : bool { return null !== $this->getPreviewRef(); } /** - * Whether the current ref in use is an experiment. - * - * @return bool + * Whether the current ref in use is an experiment */ - public function inExperiment() + public function inExperiment() : bool { return null !== $this->getExperimentRef() && false === $this->inPreview(); } @@ -460,10 +401,8 @@ public function inExperiment() * Return the ref currently in use * * In order of preference, returns the preview cookie, the experiments cookie or the master ref otherwise - * - * @return string */ - public function ref() + public function ref() : string { $preview = $this->getPreviewRef(); if ($preview) { @@ -480,15 +419,16 @@ public function ref() * Shortcut to query on the default reference. * Use the reference from previews or experiment cookie, fallback to the master reference otherwise. * - * @param string|array|\Prismic\Predicate $q the query, as a string, predicate or array of predicates - * @param array $options query options: pageSize, orderings, etc. - * - * @return Prismic::Response the response, including documents and pagination information + * @param string|array|Predicate $q the query, as a string, predicate or array of predicates + * @param array $options query options: pageSize, orderings, etc. + * @return stdClass */ - public function query($q, $options = array()) { + public function query($q, array $options = []) : stdClass + { $ref = $this->ref(); - $form = $this->forms()->everything->ref($ref); - if ($q != null && $q != "") { + /** @var SearchForm $form */ + $form = $this->form('everything')->ref($ref); + if (! empty($q)) { $form = $form->query($q); } foreach ($options as $key => $value) { @@ -501,12 +441,13 @@ public function query($q, $options = array()) { * Return the first document matching the query * Use the reference from previews or experiment cookie, fallback to the master reference otherwise. * - * @param string|array|\Prismic\Predicate $q the query, as a string, predicate or array of predicates - * @param array $options query options: pageSize, orderings, etc. + * @param string|array|Predicate $q the query, as a string, predicate or array of predicates + * @param array $options query options: pageSize, orderings, etc. * - * @return Prismic::Document the resulting document, or null + * @return stdClass|null the resulting document, or null */ - public function queryFirst($q, $options = array()) { + public function queryFirst($q, array $options = []) :? stdClass + { $documents = $this->query($q, $options)->results; if (count($documents) > 0) { return $documents[0]; @@ -520,10 +461,11 @@ public function queryFirst($q, $options = array()) { * @param string $id the requested id * @param array $options query options: pageSize, orderings, etc. * - * @return Prismic::Document the resulting document (null if no match) + * @return stdClass|null the resulting document (null if no match) */ - public function getByID($id, $options = array()) { - if(!isset($options['lang'])) $options['lang'] = '*'; + public function getByID(string $id, array $options = []) :? stdClass + { + $options = $this->prepareDefaultQueryOptions($options); return $this->queryFirst(Predicates::at("document.id", $id), $options); } @@ -533,24 +475,25 @@ public function getByID($id, $options = array()) { * @param string $type the custom type of the requested document * @param string $uid the requested uid * @param array $options query options: pageSize, orderings, etc. - * - * @return Prismic::Document the resulting document (null if no match) + * @return stdClass|null the resulting document (null if no match) */ - public function getByUID($type, $uid, $options = array()) { - if(!isset($options['lang'])) $options['lang'] = '*'; + public function getByUID(string $type, string $uid, array $options = []) :? stdClass + { + $options = $this->prepareDefaultQueryOptions($options); return $this->queryFirst(Predicates::at("my.".$type.".uid", $uid), $options); } /** * Return a set of document from their ids * - * @param array $ids array of strings, the requested ids - * @param array $options query options: pageSize, orderings, etc. + * @param array $ids array of strings, the requested ids + * @param array $options query options: pageSize, orderings, etc. * - * @return Prismic::Response the response, including documents and pagination information + * @return stdClass the response, including documents and pagination information */ - public function getByIDs($ids, $options = array()) { - if(!isset($options['lang'])) $options['lang'] = '*'; + public function getByIDs(array $ids, array $options = []) : stdClass + { + $options = $this->prepareDefaultQueryOptions($options); return $this->query(Predicates::in("document.id", $ids), $options); } @@ -560,18 +503,17 @@ public function getByIDs($ids, $options = array()) { * @param string $type the custom type of the requested document * @param array $options query options: pageSize, orderings, etc. * - * @return Prismic::Document the resulting document (null if no match) + * @return stdClass|null the resulting document (null if no match) */ - public function getSingle($type, $options = array()) { + public function getSingle(string $type, array $options = []) :? stdClass + { return $this->queryFirst(Predicates::at("document.type", $type), $options); } /** * Use the APC cache if APC is activated on the server, otherwise fallback to the noop cache (no cache) - * - * @return ApcCache::NoCache */ - public static function defaultCache() + public static function defaultCache() : CacheInterface { if (extension_loaded('apc') && ini_get('apc.enabled')) { return new ApcCache(); @@ -579,4 +521,17 @@ public static function defaultCache() return new NoCache(); } + /** + * Given an options array for a query, fill the lang parameter with a default value + * @param array $options + * @return array + */ + private function prepareDefaultQueryOptions(array $options) : array + { + if (! isset($options['lang'])) { + $options['lang'] = '*'; + } + + return $options; + } } diff --git a/src/Prismic/ApiData.php b/src/Prismic/ApiData.php index d51bcb8a..32fcbfd6 100644 --- a/src/Prismic/ApiData.php +++ b/src/Prismic/ApiData.php @@ -1,28 +1,59 @@ refs = $refs; $this->bookmarks = $bookmarks; @@ -57,82 +88,111 @@ public function __construct( $this->oauth_token = $oauth_token; } + /** + * Return a new ApiData instance from the given JSON string + * @param string $json + * @return self + */ + public static function withJsonString(string $json) : self + { + $data = json_decode($json); + if (! $data) { + throw new Exception\RuntimeException(sprintf( + 'Unable to decode JSON response: %s', + json_last_error_msg() + ), json_last_error()); + } + return self::withJsonObject($data); + } + + /** + * Return a new ApiData instance from the given JSON decoded object + * @param stdClass $json + * @return self + */ + public static function withJsonObject(stdClass $json) : self + { + $experiments = isset($json->experiments) + ? Experiments::parse($json->experiments) + : Experiments::parse(new stdClass); + return new self( + array_map( + function ($ref) { + return Ref::parse($ref); + }, + $json->refs + ), + (array)$json->bookmarks, + (array)$json->types, + $json->tags, + (array)$json->forms, + $experiments, + $json->oauth_initiate, + $json->oauth_token + ); + } + /** * Get the refs - * - * @return array + * @return Ref[] */ - public function getRefs() + public function getRefs() : array { return $this->refs; } /** * Get the bookmarks - * - * @return array */ - public function getBookmarks() + public function getBookmarks() : array { return $this->bookmarks; } /** * Get the types - * - * @return array */ - public function getTypes() + public function getTypes() : array { return $this->types; } /** * Get the tags - * - * @return array */ - public function getTags() + public function getTags() : array { return $this->tags; } /** * Get the forms - * - * @return array */ - public function getForms() + public function getForms() : array { return $this->forms; } /** * Get the Experiments - * - * @return Experiments */ - public function getExperiments() + public function getExperiments() : Experiments { return $this->experiments; } /** * Get the endpoint to initiate OAuth - * - * @return string */ - public function getOauthInitiate() + public function getOauthInitiate() : string { return $this->oauth_initiate; } /** * Get the endpoint to run OAuth - * - * @return string */ - public function getOauthToken() + public function getOauthToken() : string { return $this->oauth_token; } diff --git a/src/Prismic/Cache/ApcCache.php b/src/Prismic/Cache/ApcCache.php index 6560ff59..0333aa5c 100644 --- a/src/Prismic/Cache/ApcCache.php +++ b/src/Prismic/Cache/ApcCache.php @@ -28,7 +28,7 @@ public function has($key) public function get($key) { $value = \apcu_fetch($key, $success); - if (!$success) { + if (! $success) { return null; } return $value; diff --git a/src/Prismic/Cache/CacheInterface.php b/src/Prismic/Cache/CacheInterface.php index 82666781..3031884a 100644 --- a/src/Prismic/Cache/CacheInterface.php +++ b/src/Prismic/Cache/CacheInterface.php @@ -41,7 +41,7 @@ public function get($key); * Stores a new cache entry * * @param string $key the key of the cache entry - * @param \stdClass $value the value of the entry + * @param mixed $value the value of the entry * @param int $ttl the time (in seconds) until this cache entry expires * @return void */ diff --git a/src/Prismic/Dom/BlockGroup.php b/src/Prismic/Dom/BlockGroup.php index 7cf47999..ebe48830 100644 --- a/src/Prismic/Dom/BlockGroup.php +++ b/src/Prismic/Dom/BlockGroup.php @@ -1,4 +1,5 @@ maybeTag = $maybeTag; $this->blocks = $blocks; @@ -47,7 +48,7 @@ public function addBlock($block) * * @return string the tag to use if should be (values are either "ul", "ol" or null). */ - public function getTag() + public function getTag() :? string { return $this->maybeTag; } @@ -57,7 +58,7 @@ public function getTag() * * @return array the array of BlockInterface objects that are being grouped here */ - public function getBlocks() + public function getBlocks() : array { return $this->blocks; } diff --git a/src/Prismic/Dom/Date.php b/src/Prismic/Dom/Date.php index f27091a4..40404580 100644 --- a/src/Prismic/Dom/Date.php +++ b/src/Prismic/Dom/Date.php @@ -1,4 +1,5 @@ getTag() && $block->type === 'o-list-item') { $lastOne->addBlock($block); } elseif ($block->type === 'list-item') { - $newBlockGroup = new BlockGroup('ul', array()); + $newBlockGroup = new BlockGroup('ul', []); $newBlockGroup->addBlock($block); array_push($groups, $newBlockGroup); } else { if ($block->type === 'o-list-item') { - $newBlockGroup = new BlockGroup('ol', array()); + $newBlockGroup = new BlockGroup('ol', []); $newBlockGroup->addBlock($block); array_push($groups, $newBlockGroup); } else { - $newBlockGroup = new BlockGroup(null, array()); + $newBlockGroup = new BlockGroup(null, []); $newBlockGroup->addBlock($block); array_push($groups, $newBlockGroup); } @@ -80,7 +80,7 @@ public static function asHtml($richText, $linkResolver = null, $htmlSerializer = } else { $tag = null; } - $newBlockGroup = new BlockGroup($tag, array()); + $newBlockGroup = new BlockGroup($tag, []); $newBlockGroup->addBlock($block); array_push($groups, $newBlockGroup); } @@ -154,15 +154,15 @@ private static function insertSpans($text, array $spans, $linkResolver = null, $ return htmlentities($text, null, 'UTF-8'); } - $tagsStart = array(); - $tagsEnd = array(); + $tagsStart = []; + $tagsEnd = []; foreach ($spans as $span) { - if (!array_key_exists($span->start, $tagsStart)) { - $tagsStart[$span->start] = array(); + if (! array_key_exists($span->start, $tagsStart)) { + $tagsStart[$span->start] = []; } - if (!array_key_exists($span->end, $tagsEnd)) { - $tagsEnd[$span->end] = array(); + if (! array_key_exists($span->end, $tagsEnd)) { + $tagsEnd[$span->end] = []; } array_push($tagsStart[$span->start], $span); array_push($tagsEnd[$span->end], $span); @@ -170,7 +170,7 @@ private static function insertSpans($text, array $spans, $linkResolver = null, $ $c = null; $html = ''; - $stack = array(); + $stack = []; for ($pos = 0, $len = strlen($text) + 1; $pos < $len; $pos++) { // Looping to length + 1 to catch closing tags if (array_key_exists($pos, $tagsEnd)) { @@ -179,16 +179,18 @@ private static function insertSpans($text, array $spans, $linkResolver = null, $ $tag = array_pop($stack); // Continue only if block contains content. if ($tag && $tag['span']) { - $innerHtml = trim(RichText::serialize($tag['span'], $tag['text'], $linkResolver, $htmlSerializer)); - if (count($stack) == 0) { - // The tag was top level - $html .= $innerHtml; - } else { - // Add the content to the parent tag - $last = array_pop($stack); - $last['text'] = $last['text'] . $innerHtml; - array_push($stack, $last); - } + $innerHtml = trim( + RichText::serialize($tag['span'], $tag['text'], $linkResolver, $htmlSerializer) + ); + if (count($stack) == 0) { + // The tag was top level + $html .= $innerHtml; + } else { + // Add the content to the parent tag + $last = array_pop($stack); + $last['text'] = $last['text'] . $innerHtml; + array_push($stack, $last); + } } } } @@ -201,10 +203,10 @@ private static function insertSpans($text, array $spans, $linkResolver = null, $ usort($sspans, $spanSort); foreach ($sspans as $span) { // Open a tag - array_push($stack, array( + array_push($stack, [ 'span' => $span, 'text' => '' - )); + ]); } } if ($pos < strlen($text)) { @@ -216,10 +218,10 @@ private static function insertSpans($text, array $spans, $linkResolver = null, $ // Inner text of a span $last_idx = count($stack) - 1; $last = $stack[$last_idx]; - $stack[$last_idx] = array( + $stack[$last_idx] = [ 'span' => $last['span'], 'text' => $last['text'] . htmlentities($c, null, 'UTF-8') - ); + ]; } } } @@ -238,7 +240,7 @@ private static function insertSpans($text, array $spans, $linkResolver = null, $ * * @return string the HTML representation of the element */ - private static function serialize($element, $content, $linkResolver, $htmlSerializer) + private static function serialize($element, $content, $linkResolver, $htmlSerializer) : string { if ($htmlSerializer) { $custom = $htmlSerializer($element, $content); @@ -286,17 +288,19 @@ private static function serialize($element, $content, $linkResolver, $htmlSerial $providerAttr = ' data-oembed-provider="' . strtolower($element->oembed->provider_name) . '"'; } if ($element->oembed->html) { - return ( - '
' . - $element->oembed->html . - '
' + return sprintf( + '
%s
', + $element->oembed->embed_url, + strtolower($element->oembed->type), + $providerAttr, + $element->oembed->html ); } return ''; } // Spans - $attributes = array(); + $attributes = []; switch ($element->type) { case 'strong': $nodeName = 'strong'; @@ -307,10 +311,10 @@ private static function serialize($element, $content, $linkResolver, $htmlSerial case 'hyperlink': $nodeName = 'a'; if (isset($element->data->target)) { - $attributes = array_merge(array( + $attributes = array_merge([ 'target' => $element->data->target, 'rel' => 'noopener', - ), $attributes); + ], $attributes); } if ($element->data->link_type === 'Document') { $attributes['href'] = $linkResolver ? $linkResolver($element->data) : ''; diff --git a/src/Prismic/Exception/ExceptionInterface.php b/src/Prismic/Exception/ExceptionInterface.php new file mode 100644 index 00000000..07155a80 --- /dev/null +++ b/src/Prismic/Exception/ExceptionInterface.php @@ -0,0 +1,9 @@ +guzzleException = $e; + return $exception; + } + + /** + * Factory to wrap a Guzzle Request Exception when we should have access to a request and a response + */ + protected static function fromGuzzleRequestException(RequestException $e) : self + { + $response = $e->getResponse(); + $code = $response ? $response->getStatusCode() : 0; + $reason = $response ? $response->getReasonPhrase() : 'No Response'; + $request = $e->getRequest(); + $url = $request->getUri(); + + $message = sprintf( + 'The %s request to the repository %s resulted in a %d %s error. Complete URL: %s', + $request->getMethod(), + $url->getHost(), + $code, + $reason, + (string) $url + ); + + $exception = new static($message, $code, $e); + $exception->guzzleException = $e; + return $exception; + } + + public function getResponse() :? ResponseInterface + { + if (! $this->guzzleException instanceof RequestException) { + return null; + } + return $this->guzzleException->getResponse(); + } + + public function getRequest() :? RequestInterface + { + if (! $this->guzzleException instanceof RequestException) { + return null; + } + return $this->guzzleException->getRequest(); + } +} diff --git a/src/Prismic/Exception/RuntimeException.php b/src/Prismic/Exception/RuntimeException.php new file mode 100644 index 00000000..f5a99523 --- /dev/null +++ b/src/Prismic/Exception/RuntimeException.php @@ -0,0 +1,9 @@ +id = $id; + $this->googleId = $googleId; + $this->name = $name; + $this->variations = $variations; + } + + public function getId() : string + { + return $this->id; + } + + public function getGoogleId() :? string + { + return $this->googleId; + } + + public function getName() : string + { + return $this->name; + } + + /** + * @return Variation[] + */ + public function getVariations() : array + { + return $this->variations; + } + + public static function parse(stdClass $json) : self + { + $googleId = (isset($json->googleId) ? $json->googleId : null); + $vars = array_map(function ($varJson) { + return Variation::parse($varJson); + }, $json->variations); + return new self( + $json->id, + $googleId, + $json->name, + $vars + ); + } +} diff --git a/src/Prismic/Experiments.php b/src/Prismic/Experiments.php index aa2cf040..1379631c 100644 --- a/src/Prismic/Experiments.php +++ b/src/Prismic/Experiments.php @@ -1,55 +1,65 @@ draft = $draft; + $this->draft = $draft; $this->running = $running; } /** - * @return Experiment + * Return the current running Experiment */ - public function getCurrent() + public function getCurrent() :? Experiment { - if (count($this->running) > 0) - { + if (count($this->running) > 0) { return $this->running[0]; } return null; } /** - * @param string|null $cookie - * - * @return Ref|null + * Given the value of an experiment cookie, return the corresponding Ref as a string + * @param null|string $cookie + * @return null|string */ - public function refFromCookie($cookie) + public function refFromCookie(?string $cookie) :? string { - if ($cookie == null) return null; + if (empty($cookie)) { + return null; + } $splitted = explode(" ", $cookie); - if (count($splitted) >= 2) - { + if (count($splitted) >= 2) { $experiment = $this->findRunningById($splitted[0]); - if ($experiment == null) return null; + if (! $experiment) { + return null; + } + /** @var Variation[] $variations */ $variations = $experiment->getVariations(); $varIndex = (int)($splitted[1]); if ($varIndex > -1 && $varIndex < count($variations)) { @@ -59,18 +69,12 @@ public function refFromCookie($cookie) return null; } - /** - * @return array - */ - public function getDraft() + public function getDraft() : array { return $this->draft; } - /** - * @return array - */ - public function getRunning() + public function getRunning() : array { return $this->running; } @@ -78,171 +82,34 @@ public function getRunning() /** * Parses a given experiments. Not meant to be used except for testing. * - * @param $json the json bit retrieved from the API that represents experiments. - * @return Prismic::Experiments the manipulable object for the experiments. + * @param stdClass $json the json bit retrieved from the API that represents experiments. + * @return self the manipulable object for the experiments. */ - public static function parse(\stdClass $json) + public static function parse(stdClass $json) : self { - return new Experiments( - array_map(function ($exp) { return Experiment::parse($exp); }, $json->draft), - array_map(function ($exp) { return Experiment::parse($exp); }, $json->running) + return new self( + array_map(function ($exp) { + return Experiment::parse($exp); + }, $json->draft), + array_map(function ($exp) { + return Experiment::parse($exp); + }, $json->running) ); } /** + * Find the running experiment with the given Google ID * @param string $id - * - * @return Experiment|null + * @return null|Experiment */ - private function findRunningById($id) + private function findRunningById(string $id) :? Experiment { /** @var Experiment $exp */ - foreach ($this->running as $exp) - { - if ($exp->getGoogleId() == $id) { + foreach ($this->running as $exp) { + if ($exp->getGoogleId() === $id) { return $exp; } } return null; } } - -/** - * Class Experiment - * - * @package Prismic - */ -class Experiment { - - /** @var string */ - private $id; - /** @var string */ - private $googleId; - /** @var string */ - private $name; - /** @var array */ - private $variations; - - /** - * @param string $id - * @param string $googleId - * @param string $name - * @param array $variations - */ - public function __construct($id, $googleId, $name, array $variations) - { - $this->id = $id; - $this->googleId = $googleId; - $this->name = $name; - $this->variations = $variations; - } - - /** - * @return string - */ - public function getId() { - return $this->id; - } - - /** - * @return string - */ - public function getGoogleId() { - return $this->googleId; - } - - /** - * @return string - */ - public function getName() { - return $this->name; - } - - /** - * @return array - */ - public function getVariations() { - return $this->variations; - } - - /** - * Parses a given experiment. Not meant to be used except for testing. - * - * @param $json the json bit retrieved from the API that represents a experiment. - * - * @return Prismic::Variation the manipulable object for that experiment. - */ - public static function parse(\stdClass $json) - { - $googleId = (isset($json->googleId) ? $json->googleId : 0); - $vars = array_map(function ($varJson) { return Variation::parse($varJson); }, $json->variations); - return new Experiment( - $json->id, - $googleId, - $json->name, - $vars - ); - } - -} - -/** - * Class Variation - * - * @package Prismic - */ -class Variation -{ - /** @var string */ - private $id; - /** @var string */ - private $ref; - /** @var string */ - private $label; - - /** - * @param string $id - * @param string $ref - * @param string $label - */ - public function __construct($id, $ref, $label) - { - $this->id = $id; - $this->ref = $ref; - $this->label = $label; - } - - /** - * @return string - */ - public function getId() { - return $this->id; - } - - /** - * @return string - */ - public function getRef() { - return $this->ref; - } - - /** - * @return string - */ - public function getLabel() { - return $this->label; - } - - /** - * Parses a given variation. Not meant to be used except for testing. - * - * @param $json the json bit retrieved from the API that represents a variation. - * - * @return Prismic::Variation the manipulable object for that variation. - */ - public static function parse(\stdClass $json) - { - return new Variation($json->id, $json->ref, $json->label); - } - -} diff --git a/src/Prismic/FieldForm.php b/src/Prismic/FieldForm.php index 24ac6fc7..3be479fd 100644 --- a/src/Prismic/FieldForm.php +++ b/src/Prismic/FieldForm.php @@ -1,23 +1,26 @@ type = $type; $this->multiple = $multiple; @@ -37,30 +40,24 @@ public function __construct($type, $multiple, $defaultValue) /** * Returns the type of the field. - * - * @return string the type of the field. */ - public function getType() + public function getType() : string { return $this->type; } /** * Returns the default value. - * - * @return string the default value. */ - public function getDefaultValue() + public function getDefaultValue() :? string { return $this->defaultValue; } /** * Returns whether the parameter can be used multiple times. - * - * @return boolean true if the parameter can be used multiple times, false otherwise. */ - public function isMultiple() + public function isMultiple() : bool { return $this->multiple; } diff --git a/src/Prismic/Form.php b/src/Prismic/Form.php index a1c38756..35610764 100644 --- a/src/Prismic/Form.php +++ b/src/Prismic/Form.php @@ -1,55 +1,81 @@ maybeName = $maybeName; - $this->method = $method; - $this->maybeRel = $maybeRel; + private function __construct( + ?string $name = null, + string $method, + ?string $rel = null, + string $enctype, + string $action, + array $fields + ) { + $this->name = $name; + $this->method = $method; + $this->rel = $rel; $this->enctype = $enctype; - $this->action = $action; - $this->fields = $fields; + $this->action = $action; + $this->fields = $fields; } /** @@ -57,18 +83,18 @@ public function __construct($maybeName, $method, $maybeRel, $enctype, $action, $ * * @return array the array of arguments that will be passed */ - public function defaultData() + public function defaultData() : array { /** * @var string $key * @var FieldForm $field */ - $dft = array(); + $dft = []; foreach ($this->fields as $key => $field) { $default = $field->getDefaultValue(); if (isset($default)) { if ($field->isMultiple()) { - $default = array($default); + $default = [$default]; } $dft[$key] = $default; } @@ -77,63 +103,97 @@ public function defaultData() return $dft; } + /** + * Return a new instance from a JSON string + * @param string $json + * @return self + */ + public static function withJsonString(string $json) : self + { + $data = \json_decode($json); + return self::withJsonObject($data); + } + + /** + * Return a new instance from unserialized JSON + * @param stdClass $json + * @return self + */ + public static function withJsonObject(stdClass $json) : self + { + $fields = []; + foreach ($json->fields as $name => $field) { + $default = isset($field->default) ? $field->default : null; + $multiple = isset($field->multiple) ? $field->multiple : false; + $fields[$name] = new FieldForm($field->type, $multiple, $default); + } + + return new self( + isset($json->name) ? $json->name : null, + $json->method, + isset($json->rel) ? $json->rel : null, + $json->enctype, + $json->action, + $fields + ); + } + /** * Returns the name - * - * @return string the name */ - public function getName() + public function getName() :? string { - return $this->maybeName; + return $this->name; } /** * Returns the method - * - * @return string the method */ - public function getMethod() + public function getMethod() : string { return $this->method; } /** * Returns the rel - * - * @return string the rel */ - public function getRel() + public function getRel() :? string { - return $this->maybeRel; + return $this->rel; } /** * Returns the enctype - * - * @return string the enctype */ - public function getEnctype() + public function getEnctype() : string { return $this->enctype; } /** * Returns the action - * - * @return string the action */ - public function getAction() + public function getAction() : string { return $this->action; } /** * Returns the fields - * - * @return string the fields + * @return FieldForm[] */ - public function getFields() + public function getFields() : array { return $this->fields; } + + /** + * Return a single field by name + */ + public function getField(string $name) :? FieldForm + { + return isset($this->fields[$name]) + ? $this->fields[$name] + : null; + } } diff --git a/src/Prismic/LinkResolver.php b/src/Prismic/LinkResolver.php index 3ced1817..60c7e785 100644 --- a/src/Prismic/LinkResolver.php +++ b/src/Prismic/LinkResolver.php @@ -1,10 +1,11 @@ prismic.io's API documentation + * Prismic's API documentation * to better understand the idea. */ abstract class LinkResolver @@ -24,9 +25,9 @@ abstract class LinkResolver * * @param object $link The document link * - * @return string The URL of the link + * @return string|null The URL of the link */ - abstract public function resolve($link); + abstract public function resolve($link) :? string; /** * What happens when the link resolver gets called. @@ -34,9 +35,9 @@ abstract public function resolve($link); * * @param object $link The document link * - * @return string The URL of the link + * @return string|null The URL of the link */ - public function __invoke($link) + public function __invoke($link) :? string { return $this->resolve($link); } diff --git a/src/Prismic/Predicate.php b/src/Prismic/Predicate.php index a7bc83d4..8094cfc0 100644 --- a/src/Prismic/Predicate.php +++ b/src/Prismic/Predicate.php @@ -1,4 +1,5 @@ getTimestamp() * 1000; } - return new SimplePredicate("date.before", $fragment, array($before)); + return new SimplePredicate("date.before", $fragment, [$before]); } /** - * @param string $fragment - * @param DateTime|int $after + * @param string $fragment + * @param DateTime|string $after * * @return SimplePredicate */ - public static function dateAfter($fragment, $after) { + public static function dateAfter(string $fragment, $after) : SimplePredicate + { if ($after instanceof DateTime) { $after = $after->getTimestamp() * 1000; } - return new SimplePredicate("date.after", $fragment, array($after)); + return new SimplePredicate("date.after", $fragment, [$after]); } /** - * @param string $fragment - * @param DateTime|int $before - * @param DateTime|int $after + * @param string $fragment + * @param DateTime|string $before + * @param DateTime|string $after * * @return SimplePredicate */ - public static function dateBetween($fragment, $before, $after) { + public static function dateBetween(string $fragment, $before, $after) : SimplePredicate + { if ($before instanceof DateTime) { $before = $before->getTimestamp() * 1000; } if ($after instanceof DateTime) { $after = $after->getTimestamp() * 1000; } - return new SimplePredicate("date.between", $fragment, array($before, $after)); + return new SimplePredicate("date.between", $fragment, [$before, $after]); } /** * @param string $fragment - * @param string $day + * @param int $day * * @return SimplePredicate */ - public static function dayOfMonth($fragment, $day) { - return new SimplePredicate("date.day-of-month", $fragment, array($day)); + public static function dayOfMonth(string $fragment, int $day) : SimplePredicate + { + return new SimplePredicate("date.day-of-month", $fragment, [$day]); } /** * @param string $fragment - * @param string $day + * @param int $day * * @return SimplePredicate */ - public static function dayOfMonthBefore($fragment, $day) { - return new SimplePredicate("date.day-of-month-before", $fragment, array($day)); + public static function dayOfMonthBefore(string $fragment, int $day) : SimplePredicate + { + return new SimplePredicate("date.day-of-month-before", $fragment, [$day]); } /** * @param string $fragment - * @param string $day + * @param int $day * * @return SimplePredicate */ - public static function dayOfMonthAfter($fragment, $day) { - return new SimplePredicate("date.day-of-month-after", $fragment, array($day)); + public static function dayOfMonthAfter(string $fragment, int $day) : SimplePredicate + { + return new SimplePredicate("date.day-of-month-after", $fragment, [$day]); } /** - * @param string $fragment - * @param string $day + * @param string $fragment + * @param string|int $day * * @return SimplePredicate */ - public static function dayOfWeek($fragment, $day) { - return new SimplePredicate("date.day-of-week", $fragment, array($day)); + public static function dayOfWeek(string $fragment, $day) : SimplePredicate + { + return new SimplePredicate("date.day-of-week", $fragment, [$day]); } /** - * @param string $fragment - * @param string $day + * @param string $fragment + * @param string|int $day * * @return SimplePredicate */ - public static function dayOfWeekBefore($fragment, $day) { - return new SimplePredicate("date.day-of-week-before", $fragment, array($day)); + public static function dayOfWeekBefore(string $fragment, $day) : SimplePredicate + { + return new SimplePredicate("date.day-of-week-before", $fragment, [$day]); } /** - * @param string $fragment - * @param string $day + * @param string $fragment + * @param string|int $day * * @return SimplePredicate */ - public static function dayOfWeekAfter($fragment, $day) { - return new SimplePredicate("date.day-of-week-after", $fragment, array($day)); + public static function dayOfWeekAfter(string $fragment, $day) : SimplePredicate + { + return new SimplePredicate("date.day-of-week-after", $fragment, [$day]); } /** - * @param string $fragment - * @param string $month + * @param string $fragment + * @param string|int $month * * @return SimplePredicate */ - public static function month($fragment, $month) { - return new SimplePredicate("date.month", $fragment, array($month)); + public static function month(string $fragment, $month) : SimplePredicate + { + return new SimplePredicate("date.month", $fragment, [$month]); } /** - * @param string $fragment - * @param string $month + * @param string $fragment + * @param string|int $month * * @return SimplePredicate */ - public static function monthBefore($fragment, $month) { - return new SimplePredicate("date.month-before", $fragment, array($month)); + public static function monthBefore(string $fragment, $month) : SimplePredicate + { + return new SimplePredicate("date.month-before", $fragment, [$month]); } /** - * @param string $fragment - * @param string $month + * @param string $fragment + * @param string|int $month * * @return SimplePredicate */ - public static function monthAfter($fragment, $month) { - return new SimplePredicate("date.month-after", $fragment, array($month)); + public static function monthAfter(string $fragment, $month) : SimplePredicate + { + return new SimplePredicate("date.month-after", $fragment, [$month]); } /** * @param string $fragment - * @param string $year + * @param int $year * * @return SimplePredicate */ - public static function year($fragment, $year) { - return new SimplePredicate("date.year", $fragment, array($year)); + public static function year(string $fragment, int $year) : SimplePredicate + { + return new SimplePredicate("date.year", $fragment, [$year]); } /** * @param string $fragment - * @param string $hour + * @param int $hour * * @return SimplePredicate */ - public static function hour($fragment, $hour) { - return new SimplePredicate("date.hour", $fragment, array($hour)); + public static function hour(string $fragment, int $hour) : SimplePredicate + { + return new SimplePredicate("date.hour", $fragment, [$hour]); } /** * @param string $fragment - * @param string $hour + * @param int $hour * * @return SimplePredicate */ - public static function hourBefore($fragment, $hour) { - return new SimplePredicate("date.hour-before", $fragment, array($hour)); + public static function hourBefore(string $fragment, int $hour) : SimplePredicate + { + return new SimplePredicate("date.hour-before", $fragment, [$hour]); } /** * @param string $fragment - * @param string $hour + * @param int $hour * * @return SimplePredicate */ - public static function hourAfter($fragment, $hour) { - return new SimplePredicate("date.hour-after", $fragment, array($hour)); + public static function hourAfter(string $fragment, int $hour) : SimplePredicate + { + return new SimplePredicate("date.hour-after", $fragment, [$hour]); } /** * @param string $fragment - * @param string $latitude - * @param string $longitude - * @param string $radius + * @param float $latitude + * @param float $longitude + * @param float $radius * * @return SimplePredicate */ - public static function near($fragment, $latitude, $longitude, $radius) { - return new SimplePredicate("geopoint.near", $fragment, array($latitude, $longitude, $radius)); + public static function near(string $fragment, float $latitude, float $longitude, float $radius) : SimplePredicate + { + return new SimplePredicate("geopoint.near", $fragment, [$latitude, $longitude, $radius]); } - } diff --git a/src/Prismic/Ref.php b/src/Prismic/Ref.php index 39fdffbb..1b4c1b72 100644 --- a/src/Prismic/Ref.php +++ b/src/Prismic/Ref.php @@ -1,11 +1,14 @@ id = $id; - $this->ref = $ref; - $this->label = $label; - $this->isMasterRef = $isMasterRef; + private function __construct( + string $id, + string $ref, + string $label, + bool $isMasterRef, + ?int $maybeScheduledAt = null + ) { + $this->id = $id; + $this->ref = $ref; + $this->label = $label; + $this->isMasterRef = $isMasterRef; $this->maybeScheduledAt = $maybeScheduledAt; } /** * Returns the ID of the ref - * - * @return string the ID of the ref */ - public function getId() + public function getId() : string { return $this->id; } /** * Returns the reference of the ref - * - * @return string the ID of the ref */ - public function getRef() + public function getRef() : string { return $this->ref; } /** * Returns the display label of the ref - * - * @return string the display label of the ref */ - public function getLabel() + public function getLabel() : string { return $this->label; } /** * Checks if the ref is the master ref - * - * @return boolean true if it is the master ref, false otherwise */ - public function isMasterRef() + public function isMasterRef() : bool { return $this->isMasterRef; } /** * Returns the time at which the ref is scheduled, if it is - * - * @return int|null Javacript timestamp for the scheduled release or null if not scheduled + * This is a 13 digit Javacript timestamp including miliseconds */ - public function getScheduledAt() + public function getScheduledAt() :? int { return $this->maybeScheduledAt; } /** * Return the scheduled time as a unix timestamp - * - * @return int|null Unix timestamp for the scheduled release or null if not scheduled */ - public function getScheduledAtTimestamp() + public function getScheduledAtTimestamp() :? int { - if (null === $this->getScheduledAt()) { + if (null === $this->maybeScheduledAt) { return null; } - return (int) floor($this->getScheduledAt() / 1000); + return (int) \floor($this->maybeScheduledAt / 1000); } /** * Return the DateTime of the scheduled release if any - * - * @return DateTime|null The release date or null */ - public function getScheduledDate() + public function getScheduledDate() :? DateTimeImmutable { - if (null === $this->getScheduledAt()) { + if (null === $this->maybeScheduledAt) { return null; } - $date = new DateTime; - $date->setTimestamp($this->getScheduledAtTimestamp()); - - return $date; + return DateTimeImmutable::createFromFormat( + 'U', + (string) $this->getScheduledAtTimestamp() + ); } /** - * Returns the ref as a displayable information: the ref's ID. - * - * @return string the ref's ID + * Returns the ref as a displayable information: the ref's ID */ - public function __toString() + public function __toString() : string { - return (string) $this->getRef(); + return $this->ref; } /** * Parses a ref. - * - * @param $json the json bit retrieved from the API that represents a ref. - * @return Prismic::Ref the manipulable object for that ref. + * @throws Exception\InvalidArgumentException if the JSON object has missing properties */ - public static function parse($json) + public static function parse(stdClass $json) : self { + if (! isset($json->id, $json->ref, $json->label)) { + throw new Exception\InvalidArgumentException( + 'The properties id, ref and label should exist in the JSON object for a Ref' + ); + } return new Ref( $json->id, $json->ref, $json->label, isset($json->{'isMasterRef'}) ? $json->isMasterRef : false, - isset($json->{'scheduledAt'}) ? $json->scheduledAt : null // @todo: convert value into \DateTime ? + isset($json->{'scheduledAt'}) ? $json->scheduledAt : null ); } } diff --git a/src/Prismic/SearchForm.php b/src/Prismic/SearchForm.php index b3677a22..f1f0ad27 100644 --- a/src/Prismic/SearchForm.php +++ b/src/Prismic/SearchForm.php @@ -1,7 +1,15 @@ form('everything')->ref($ref)->submit() * * And here's an example of a more complex query: - * $result = $api->form('products')->query('[[:d = any(document.tags, ["Featured"])]]')->pageSize(10)->page(2)->ref($ref)->submit() + * $result = $api->form('products') + * ->query('[[:d = any(document.tags, ["Featured"])]]')->pageSize(10)->page(2)->ref($ref)->submit() * * Note that setting the ref is mandatory, or your submit call will fail. * @@ -22,37 +31,48 @@ class SearchForm { /** - * Prismic::Api the API object containing all the information to know where to query + * Cache Instance + * @var CacheInterface */ - private $api; + private $cache; + + /** + * Http Client + * @var ClientInterface + */ + private $client; + /** - * Prismic::Form the REST form we're querying on in the API + * The REST form we're querying on in the API + * @var Form */ private $form; + /** - * array the parameters we're getting ready to submit + * The parameters we're getting ready to submit + * @var array */ private $data; /** * Constructs a SearchForm object - * @param Prismic::Api $api the API object containing all the information to know where to query - * @param Prismic::Form $form the REST form we're querying on in the API - * @param array $data the parameters we're getting ready to submit + * @param ClientInterface $httpClient An HTTP Client for sending Requests + * @param CacheInterface $cache A cache for storing responses + * @param Form $form the REST form we're querying on in the API + * @param array $data the parameters we're getting ready to submit */ - public function __construct(Api $api, Form $form, array $data) + public function __construct(ClientInterface $httpClient, CacheInterface $cache, Form $form, array $data) { - $this->api = $api; - $this->form = $form; - $this->data = $data; + $this->client = $httpClient; + $this->cache = $cache; + $this->form = $form; + $this->data = $data; } /** * Get the parameters we're about to submit. - * - * @return array */ - public function getData() + public function getData() : array { return $this->data; } @@ -63,157 +83,172 @@ public function getData() * * Checks that the parameter is expected in the RESTful form before allowing to add it. * - * @param string $key the name of the parameter - * @param string $value the value of the parameter + * @param string $key the name of the parameter + * @param string|int $value the value of the parameter * - * \throws RuntimeException + * @throws Exception\ExceptionInterface * - * @return \Prismic\SearchForm a clone of the SearchForm object with the new parameter added + * @return self A clone of the SearchForm object with the new parameter added */ - public function set($key, $value) + public function set(string $key, $value) : self { - $data = $this->data; - if (isset($key) && isset($value)) { - $fields = $this->form->getFields(); - /** @var FieldForm $field */ - $field = $fields[$key]; + if (empty($key)) { + throw new Exception\InvalidArgumentException('Form parameter key must be a non-empty string'); + } + if (! is_scalar($value)) { + throw new Exception\InvalidArgumentException('Form parameter value must be scalar'); + } + $fields = $this->form->getFields(); + if (! isset($fields[$key])) { + throw new Exception\InvalidArgumentException(sprintf( + 'Unknown form field parameter "%s"', + $key + )); + } - if (is_int($value) && $field->getType() != "Integer") { - throw new \RuntimeException("Cannot use a Int as value for field " . $key); - } + /** @var FieldForm $field */ + $field = $fields[$key]; - if ($field->isMultiple()) { - $values = isset($data[$key]) ? $data[$key] : array(); - if (is_array($values)) { - array_push($values, $value); - } else { - $values = array($value); - } - $data[$key] = $values; - } else { - $data[$key] = $value; - } + if ($field->getType() === 'String' && ! is_string($value)) { + throw new Exception\InvalidArgumentException(sprintf( + 'The field %s expects a string parameter, received %s', + $key, + gettype($value) + )); + } + + if ($field->getType() === 'Integer' && ! is_numeric($value)) { + throw new Exception\InvalidArgumentException(sprintf( + 'The field %s expects an integer parameter, received %s', + $key, + gettype($value) + )); + } + + + $data = $this->data; + if ($field->isMultiple()) { + $data[$key] = isset($data[$key]) ? $data[$key] : []; + $data[$key] = is_array($data[$key]) ? $data[$key] : [$data[$key]]; + $data[$key][] = $value; + } else { + $data[$key] = $value; } - return new SearchForm($this->api, $this->form, $data); + + return new self($this->client, $this->cache, $this->form, $data); } /** - * Set the repository's ref. + * Set the repository ref to query at * - * @param string|\Prismic\Ref $ref the ref we wish to query on, or its ID. - * - * @return Prismic::SearchForm a clone of the SearchForm object with the new ref parameter added + * @param string|Ref $ref the ref we wish to query on, or its ID. + * @return self */ - public function ref($ref) + public function ref($ref) : self { - if ($ref instanceof \Prismic\Ref) { - $ref = $ref->getRef(); + if ($ref instanceof Ref) { + $ref = (string) $ref; } return $this->set("ref", $ref); } /** * Set the after parameter: the id of the document to start the results from (excluding that document). - * * @param string $documentId - * - * @return Prismic::SearchForm a clone of the SearchForm object with the new after parameter added + * @return self */ - public function after($documentId) + public function after(string $documentId) : self { return $this->set("after", $documentId); } /** - * Set the fetch parameter: restrict the fields to retrieve for a document. You can pass in parameter - * an array of strings, or several strings. + * Set the fetch parameter: restrict the fields to retrieve for a document + * + * Pass multiple string arguments or an array of strings to unpack with the splat operator * - * @return Prismic::SearchForm a clone of the SearchForm object with the new fetch parameter added + * @param string[] $fields + * @return self */ - public function fetch() + public function fetch(string ...$fields) : self { - $numargs = func_num_args(); - if ($numargs == 1 && is_array(func_get_arg(0))) { - $fields = func_get_arg(0); - } else { - $fields = func_get_args(); - } - return $this->set("fetch", join(",", $fields)); + return $this->set("fetch", implode(",", $fields)); } /** - * Set the fetchLinks parameter: additional fields to retrieve for DocumentLink, You can pass in parameter - * an array of strings, or several strings. + * Set the fetchLinks parameter: additional fields to retrieve for DocumentLink * - * @return Prismic::SearchForm a clone of the SearchForm object with the new fetchLinks parameter added + * Pass multiple string arguments or an array of strings to unpack with the splat operator + * + * @param string[] $fields + * @return self */ - public function fetchLinks() + public function fetchLinks(string ...$fields) : self { - $numargs = func_num_args(); - if ($numargs == 1 && is_array(func_get_arg(0))) { - $fields = func_get_arg(0); - } else { - $fields = func_get_args(); - } return $this->set("fetchLinks", join(",", $fields)); } + /** + * Set the graphQuery parameter: GraphQL syntax based to select fields + * @param string $query + * @return self + */ + public function graphQuery(string $query) : self + { + return $this->set("graphQuery", $query); + } + /** * Set the language for the query documents. - * - * @param int $lang - * @return Prismic::SearchForm a clone of the SearchForm object with the new lang parameter added + * @param string $lang + * @return self */ - public function lang($lang) + public function lang(string $lang) : self { return $this->set("lang", $lang); } /** * Set the query's page size, for the pagination. - * - * @param int $pageSize - * @return Prismic::SearchForm a clone of the SearchForm object with the new pageSize parameter added + * @param int $pageSize + * @return self */ - public function pageSize($pageSize) + public function pageSize(int $pageSize) : self { return $this->set("pageSize", $pageSize); } /** - * Set the query's page, for the pagination. - * - * @param int $page - * - * @return Prismic::SearchForm a clone of the SearchForm object with the new page parameter added + * Set the query result page number, for the pagination. + * @param int $page + * @return self */ - public function page($page) + public function page(int $page) : self { return $this->set("page", $page); } /** * Set the query's ordering, setting in what order the documents must be retrieved. - * - * @return Prismic::SearchForm a clone of the SearchForm object with the new orderings parameter added */ - public function orderings() + public function orderings(string ...$fields) : self { - if (func_num_args() == 0) return $this; - $orderings = "[" . join(",", array_map(function($order) { return preg_replace('/(^\[|\]$)/', '', $order); }, func_get_args())) . "]"; + $fields = array_filter($fields); + if (empty($fields)) { + return $this; + } + $orderings = "[" . implode(",", array_map(function ($order) { + return preg_replace('/(^\[|\]$)/', '', $order); + }, $fields)) . "]"; return $this->set("orderings", $orderings); } /** * Submit the current API call, and unmarshalls the result into PHP objects. - * - * @return Prismic::Response the result of the call - * - * \throws RuntimeException */ - public function submit() + public function submit() : stdClass { - return $this->submit_raw(); + return $this->submitRaw(); } /** @@ -222,99 +257,119 @@ public function submit() * This uses a copy of the SearchForm with a page size of 1 (the smallest * allowed) since all we care about is one of the returned non-result * fields. - * - * @return int Total number of results - * - * \throws RuntimeException */ - public function count() + public function count() :? int { - return $this->pageSize(1)->submit_raw()->total_results_size; + $response = $this->pageSize(1)->submitRaw(); + return isset($response->total_results_size) + ? (int) $response->total_results_size + : null; } /** - * Set the query's predicates themselves. - * You can pass a String representing a query as parameter, or one or multiple Predicates to build an "AND" query - * - * @return Prismic::SearchForm a clone of the SearchForm object with the new predicate or predicates added + * Set query predicates + * You can provide a single string, or one or multiple Predicate instances to build an "AND" query */ - public function query() + public function query(...$params) : self { - $numargs = func_num_args(); - if ($numargs == 0) return clone $this; - $first = func_get_arg(0); - if ($numargs == 1 && is_string($first)) { - return $this->set("q", $first); + // Filter empty args and return early if appropriate + $params = array_filter($params); + if (empty($params)) { + return clone $this; } - if ($numargs == 1 && is_array($first)) { - $predicates = $first; - } else { - $predicates = func_get_args(); + $first = current($params); + // Unpack a single array argument + if (count($params) === 1 && is_array($first)) { + $params = $first; + } + $this->assertValidQueryParameters($params); + if (count($params) === 1 && is_string($first)) { + return $this->set("q", $first); } - $query = "[" . join("", array_map(function($predicate) { return $predicate->q(); }, $predicates)) . "]"; + $query = "[" . implode("", array_map(function ($predicate) { + /** @var Predicate $predicate */ + return $predicate->q(); + }, $params)) . "]"; return $this->set("q", $query); } + /** + * Assert that the parameters used for a query contain either a single string, or an array of Predicates + * @param array $params + * @throws Exception\InvalidArgumentException + */ + private function assertValidQueryParameters(array $params) : void + { + if (count($params) === 1 && is_string(current($params))) { + return; + } + foreach ($params as $param) { + if (! $param instanceof Predicate) { + throw new Exception\InvalidArgumentException( + 'Query parameters should consist of a single string or multiple Predicate instances' + ); + } + } + } + /** * Get the URL for this form - * - * @return string the URL */ - public function url() + public function url() : string { - $url = $this->form->getAction() . '?' . http_build_query($this->data); - $url = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', $url); - return $url; + return Utils::buildUrl($this->form->getAction(), $this->data); } /** * Checks if the results for this form are already cached - * - * @return boolean true if the results for this form are fresh in the cache, false otherwise */ - public function isCached() + public function isCached() : bool { - return $this->api->getCache()->has($this->url()); + return $this->cache->has($this->url()); } /** * Performs the actual submit call, without the unmarshalling. * - * \throws RuntimeException if the Form type is not supported + * @throws Exception\RuntimeException if the Form type is not supported or the Response body is invalid + * @throws Exception\RequestFailureException if something went wrong retrieving data from the API * - * @return the raw (unparsed) response. + * @return stdClass Unserialized JSON Response */ - private function submit_raw() + private function submitRaw() : stdClass { - if ($this->form->getMethod() == 'GET' && - $this->form->getEnctype() == 'application/x-www-form-urlencoded' && - $this->form->getAction() + if ($this->form->getMethod() !== 'GET' || + $this->form->getEnctype() !== 'application/x-www-form-urlencoded' || + ! $this->form->getAction() ) { - $url = $this->url(); - $cacheKey = $this->url(); - - $response = $this->api->getCache()->get($cacheKey); - - if ($response) { - return $response; - } - $response = $this->api->getHttpClient()->get($url); - $cacheControl = $response->getHeader('Cache-Control')[0]; - $cacheDuration = null; - if (preg_match('/^max-age\s*=\s*(\d+)$/', $cacheControl, $groups) == 1) { - $cacheDuration = (int) $groups[1]; - } - $json = json_decode($response->getBody(true)); - if (!isset($json)) { - throw new \RuntimeException("Unable to decode json response"); - } - if ($cacheDuration !== null) { - $expiration = $cacheDuration; - $this->api->getCache()->set($cacheKey, $json, $expiration); - } - return $json; + throw new Exception\RuntimeException("Form type not supported"); } - throw new \RuntimeException("Form type not supported"); - } + $url = $this->url(); + $cacheKey = $this->url(); + + $cachedJson = $this->cache->get($cacheKey); + if ($cachedJson) { + return $cachedJson; + } + try { + /** @var \Psr\Http\Message\ResponseInterface $response */ + $response = $this->client->request('GET', $url); + } catch (GuzzleException $guzzleException) { + throw Exception\RequestFailureException::fromGuzzleException($guzzleException); + } + $cacheControl = $response->getHeader('Cache-Control')[0]; + $cacheDuration = null; + if (preg_match('/^max-age\s*=\s*(\d+)$/', $cacheControl, $groups) == 1) { + $cacheDuration = (int) $groups[1]; + } + $json = \json_decode((string) $response->getBody()); + if (! isset($json)) { + throw new Exception\RuntimeException("Unable to decode json response"); + } + if ($cacheDuration !== null) { + $this->cache->set($cacheKey, $json, $cacheDuration); + } + return $json; + } } diff --git a/src/Prismic/SimplePredicate.php b/src/Prismic/SimplePredicate.php index 011f280e..ca89cfb6 100644 --- a/src/Prismic/SimplePredicate.php +++ b/src/Prismic/SimplePredicate.php @@ -1,23 +1,26 @@ name = $name; $this->fragment = $fragment; @@ -27,10 +30,10 @@ public function __construct($name, $fragment, array $args = array()) /** * @return string */ - public function q() + public function q() : string { $query = "[:d = " . $this->name . "("; - if ($this->name == "similar") { + if ($this->name === "similar") { $query .= "\"" . $this->fragment . "\""; } else { $query .= $this->fragment; @@ -47,18 +50,18 @@ public function q() * * @return string */ - private static function serializeField($value) { + private static function serializeField($value) : string + { if (is_string($value)) { return "\"" . $value . "\""; } if (is_array($value)) { - $str_array = array(); + $str_array = []; foreach ($value as $elt) { - array_push($str_array, SimplePredicate::serializeField($elt)); + array_push($str_array, static::serializeField($elt)); } - return "[" . join(", ", $str_array) . "]"; + return "[" . implode(", ", $str_array) . "]"; } return (string)$value; } - } diff --git a/src/Prismic/Utils.php b/src/Prismic/Utils.php new file mode 100644 index 00000000..00f2e406 --- /dev/null +++ b/src/Prismic/Utils.php @@ -0,0 +1,20 @@ +id = $id; + $this->ref = $ref; + $this->label = $label; + } + + public function getId() : string + { + return $this->id; + } + + public function getRef() : string + { + return $this->ref; + } + + public function getLabel() : string + { + return $this->label; + } + + public static function parse(stdClass $json) : self + { + return new Variation($json->id, $json->ref, $json->label); + } +} diff --git a/tests/Prismic/ApiDataTest.php b/tests/Prismic/ApiDataTest.php new file mode 100644 index 00000000..319e77fe --- /dev/null +++ b/tests/Prismic/ApiDataTest.php @@ -0,0 +1,60 @@ +getJsonFixture('data.json'); + $this->data = ApiData::withJsonString($json); + } + + public function testApiDataCanBeCreatedFromJsonString() + { + $json = $this->getJsonFixture('data.json'); + $data = ApiData::withJsonString($json); + $this->assertInstanceOf(ApiData::class, $data); + } + + /** + * @expectedException Prismic\Exception\RuntimeException + * @expectedExceptionMessage Unable to decode JSON response + */ + public function testWithJsonStringThrowsExceptionForInvalidJson() + { + ApiData::withJsonString('wtf?'); + } + + public function testApiDataHasExpectedValues() + { + $this->assertCount(3, $this->data->getRefs()); + $this->assertContainsOnlyInstancesOf(Ref::class, $this->data->getRefs()); + + $this->assertCount(3, $this->data->getBookmarks()); + $this->assertContainsOnly('string', $this->data->getBookmarks()); + + $this->assertCount(6, $this->data->getTypes()); + $this->assertContainsOnly('string', $this->data->getTypes()); + + $this->assertCount(4, $this->data->getTags()); + $this->assertContainsOnly('string', $this->data->getTags()); + + $this->assertCount(2, $this->data->getForms()); + $this->assertContainsOnlyInstancesOf(stdClass::class, $this->data->getForms()); + + $this->assertInstanceOf(Experiments::class, $this->data->getExperiments()); + + $this->assertSame('http://lesbonneschoses.prismic.io/auth', $this->data->getOauthInitiate()); + $this->assertSame('http://lesbonneschoses.prismic.io/auth/token', $this->data->getOauthToken()); + } +} diff --git a/tests/Prismic/ApiTest.php b/tests/Prismic/ApiTest.php index ec09f0b7..aecfb370 100644 --- a/tests/Prismic/ApiTest.php +++ b/tests/Prismic/ApiTest.php @@ -1,45 +1,115 @@ api = $this->getMockBuilder(Prismic\Api::class) - ->disableOriginalConstructor() - ->setMethods(['master', 'getExperiments']) - ->getMock(); + unset($_COOKIE); + + $this->apiData = ApiData::withJsonString($this->getJsonFixture('data.json')); + $this->httpClient = $this->prophesize(GuzzleClient::class); + $this->cache = $this->prophesize(CacheInterface::class); + } + + protected function getApi() : Api + { + return Api::get( + 'https://whatever.prismic.io/api/v2', + 'My-Access-Token', + $this->httpClient->reveal(), + $this->cache->reveal(), + 99 + ); + } + + protected function getApiWithDefaultData() : Api + { + $key = 'https://whatever.prismic.io/api/v2#My-Access-Token'; + $cachedData = serialize($this->apiData); + $this->cache->get($key)->willReturn($cachedData); + $this->httpClient->request()->shouldNotBeCalled(); + + return $this->getApi(); + } - $master = new Prismic\Ref('Master', 'Master-Ref-String', 'Master', true, null); + public function testCachedApiDataWillBeUsedIfAvailable() + { + $api = $this->getApiWithDefaultData(); + $this->assertSame(serialize($this->apiData), serialize($api->getData())); + } - $this->api - ->method('master') - ->willReturn($master); + public function testGetIsCalledOnHttpClientWhenTheCacheIsEmpty() + { + $key = 'https://whatever.prismic.io/api/v2#My-Access-Token'; + $this->cache->get($key)->willReturn(null); + $url = 'https://whatever.prismic.io/api/v2?access_token=My-Access-Token'; + $response = $this->prophesize(ResponseInterface::class); + $response->getBody()->willReturn($this->getJsonFixture('data.json')); + $this->httpClient->request('GET', $url)->willReturn($response->reveal()); + + $this->cache->set( + Argument::type('string'), + Argument::type('string'), + 99 + )->shouldBeCalled(); + + $api = $this->getApi(); + $this->assertInstanceOf(ClientInterface::class, $api->getHttpClient()); + $this->assertSame(serialize($this->apiData), serialize($api->getData())); + } - $this->experiments = $this->getMockBuilder(Prismic\Experiments::class) - ->disableOriginalConstructor() - ->setMethods(['refFromCookie']) - ->getMock(); + public function testMasterRefIsReturnedWhenNeitherPreviewOrExperimentsAreActive() + { + $api = $this->getApiWithDefaultData(); + $this->assertSame($this->expectedMasterRef, $api->ref()); + } - $this->api - ->method('getExperiments') - ->willReturn($this->experiments); + public function testMasterRefIsReturnedByMasterMethod() + { + $api = $this->getApiWithDefaultData(); + $ref = $api->master(); + $this->assertInstanceOf(Prismic\Ref::class, $ref); + $this->assertSame($this->expectedMasterRef, (string) $ref); } - public function testRef() + public function testInPreviewAndInExperimentIsFalseWhenNoCookiesAreSet() { - $this->assertSame('Master-Ref-String', $this->api->ref()); + $api = $this->getApiWithDefaultData(); + $this->assertFalse($api->inPreview()); + $this->assertFalse($api->inExperiment()); } - public function getCookieData() + public function getPreviewRefs() { return [ [ @@ -58,87 +128,117 @@ public function getCookieData() ], [ [ - 'io.prismic.experiment' => 'experiment', - 'other' => 'other', + 'io_prismic_preview' => 'preview', ], - 'experiment' - ], - [ - [ - 'foo' => 'foo', - 'other' => 'other', - ], - 'Master-Ref-String' + 'preview' ], ]; } /** - * @dataProvider getCookieData + * @dataProvider getPreviewRefs */ - public function testCorrectRefIsReturned($cookie, $expect) + public function testPreviewRefIsReturnedWhenPresentInSuperGlobal(array $cookie, string $expect) { - // Make sure that Prismic\Experiments::refFromCookie returns a 'valid' ref - $this->experiments->method('refFromCookie')->willReturn('experiment'); $_COOKIE = $cookie; - $this->assertSame($expect, $this->api->ref()); + $api = $this->getApiWithDefaultData(); + $this->assertSame($expect, $api->ref()); } - public function testRefDoesNotReturnStaleExperimentRef() + public function testInPreviewIsTrueWhenPreviewCookieIsSet() { - // Make sure that Prismic\Experiments::refFromCookie returns null, i.e. no experiment running - $this->experiments->method('refFromCookie')->willReturn(null); $_COOKIE = [ - 'io.prismic.experiment' => 'Stale Experiment Cookie Value', + 'io.prismic.preview' => 'whatever', ]; - $this->assertSame('Master-Ref-String', $this->api->ref()); + $api = $this->getApiWithDefaultData(); + $this->assertTrue($api->inPreview()); } - /** - * @depends testCorrectRefIsReturned - */ - public function testInPreviewIsTrueWhenPreviewCookieIsSet() + public function testRefDoesNotReturnStaleExperimentRef() { - $cookieValue = 'Preview Ref Cookie Value'; $_COOKIE = [ - 'io.prismic.preview' => $cookieValue, + 'io.prismic.experiment' => 'Stale Experiment Cookie Value', ]; - $this->assertTrue($this->api->inPreview()); + $api = $this->getApiWithDefaultData(); + $this->assertSame($this->expectedMasterRef, $api->ref()); } - /** - * @depends testCorrectRefIsReturned - */ - public function testInExperimentIsTrueWhenExperimentCookieIsSet() + public function testCorrectExperimentRefIsReturnedWhenCookieIsSet() { - $cookieValue = 'Experiment Cookie Value'; - $this->experiments->method('refFromCookie')->willReturn('Experiment Ref'); + $runningGoogleCookie = '_UQtin7EQAOH5M34RQq6Dg 1'; + $expectedRef = 'VDUUmHIKAZQKk9uq'; // The ref at index 1 for the variations in this experiment $_COOKIE = [ - 'io.prismic.experiment' => $cookieValue, + 'io.prismic.experiment' => $runningGoogleCookie, ]; - $this->assertTrue($this->api->inExperiment()); + $api = $this->getApiWithDefaultData(); + $this->assertSame($expectedRef, $api->ref()); + $this->assertTrue($api->inExperiment()); } /** - * @depends testInExperimentIsTrueWhenExperimentCookieIsSet + * @depends testCorrectExperimentRefIsReturnedWhenCookieIsSet */ public function testPreviewRefTrumpsExperimentRefWhenSet() { - $this->experiments->method('refFromCookie')->willReturn('Experiment Ref'); + $runningGoogleCookie = '_UQtin7EQAOH5M34RQq6Dg 1'; $_COOKIE = [ - 'io.prismic.experiment' => 'Experiment Cookie Value', + 'io.prismic.experiment' => $runningGoogleCookie, 'io.prismic.preview' => 'Preview Ref Cookie Value', ]; - $this->assertTrue($this->api->inPreview()); - $this->assertFalse($this->api->inExperiment()); + $api = $this->getApiWithDefaultData(); + $this->assertTrue($api->inPreview()); + $this->assertFalse($api->inExperiment()); } - public function testInPreviewAndInExperimentIsFalseWhenNoCookiesAreSet() + public function testBookmarkReturnsCorrectDocumentId() { - $_COOKIE = []; - $this->assertFalse($this->api->inPreview()); - $this->assertFalse($this->api->inExperiment()); + $api = $this->getApiWithDefaultData(); + $this->assertSame('Ue0EDd_mqb8Dhk3j', $api->bookmark('about')); + $this->assertNull($api->bookmark('unknown-bookmark')); } + public function testFormsReturnsOnlyFormInstances() + { + $api = $this->getApiWithDefaultData(); + $everything = $api->form('everything'); + $this->assertTrue(isset($everything)); + $this->assertInstanceOf(SearchForm::class, $everything); + } + + public function testRefsGroupsRefsByLabel() + { + $api = $this->getApiWithDefaultData(); + $refs = $api->refs(); + $this->assertArrayHasKey('Master', $refs); + $this->assertArrayHasKey('San Francisco Grand opening', $refs); + $this->assertContainsOnlyInstancesOf(Prismic\Ref::class, $refs); + } + + public function testRefsContainsOnlyFirstEncounteredRefWithLabel() + { + $api = $this->getApiWithDefaultData(); + $refs = $api->refs(); + $this->assertSame('UgjWRd_mqbYHvPJa', (string) $refs['San Francisco Grand opening']); + } + + public function testGetRefFromLabelReturnsExpectedRef() + { + $api = $this->getApiWithDefaultData(); + $ref = $api->getRefFromLabel('San Francisco Grand opening'); + $this->assertSame('UgjWRd_mqbYHvPJa', (string) $ref); + } + + public function testUsefulExceptionIsThrownWhenApiCannotBeReached() + { + $client = new Client(['connect_timeout' => 0.01]); + try { + $api = Api::get('http://example.example', null, $client); + $this->fail('No exception was thrown'); + } catch (Prismic\Exception\RequestFailureException $e) { + $this->assertContains('example.example', $e->getMessage()); + $this->assertInstanceOf(RequestInterface::class, $e->getRequest()); + $this->assertNull($e->getResponse()); + } + } } diff --git a/tests/Prismic/CacheTest.php b/tests/Prismic/CacheTest.php index b06bbade..123180b5 100644 --- a/tests/Prismic/CacheTest.php +++ b/tests/Prismic/CacheTest.php @@ -1,10 +1,11 @@ assertNull($this->cache->get('key1')); $this->assertNull($this->cache->get('key2')); } + + public function testSetGetReturnsExpectedValue() + { + $data = \json_decode($this->getJsonFixture('data.json')); + $this->cache->set('key', $data); + $result = $this->cache->get('key'); + $this->assertEquals($data, $result); + } + + public function testLongUrlBasedCacheKeysArePersistedCorrectly() + { + $data = \json_decode($this->getJsonFixture('data.json')); + $url = $data->forms->everything->action; + $url .= '?access_token=AVeryLongAccessTokenForPermanentAccessToTheRepository&q=SomeQueryString'; + $this->cache->set($url, $data); + $result = $this->cache->get($url); + $this->assertEquals($data, $result); + } } diff --git a/tests/Prismic/Dom/DateTest.php b/tests/Prismic/Dom/DateTest.php index 9ac947b7..452eab8f 100644 --- a/tests/Prismic/Dom/DateTest.php +++ b/tests/Prismic/Dom/DateTest.php @@ -1,12 +1,14 @@ links = json_decode(file_get_contents(__DIR__.'/../../fixtures/links.json')); + $this->links = json_decode($this->getJsonFixture('links.json')); $this->linkResolver = new FakeLinkResolver(); } diff --git a/tests/Prismic/Dom/RichTextTest.php b/tests/Prismic/Dom/RichTextTest.php index 4ac1a16a..e1a3cebf 100644 --- a/tests/Prismic/Dom/RichTextTest.php +++ b/tests/Prismic/Dom/RichTextTest.php @@ -1,18 +1,20 @@ richText = json_decode(file_get_contents(__DIR__.'/../../fixtures/rich-text.json')); + $this->richText = json_decode($this->getJsonFixture('rich-text.json')); $this->linkResolver = new FakeLinkResolver(); } @@ -87,7 +89,7 @@ public function testHtmlSerializer() '' . '' ); - $htmlSerializer = function($element, $content) { + $htmlSerializer = function ($element, $content) { if ($element->type === 'heading3') { $classes = 'custom'; if (isset($element->label)) { diff --git a/tests/Prismic/ExperimentTest.php b/tests/Prismic/ExperimentTest.php index 9d35ceaf..05841e0b 100644 --- a/tests/Prismic/ExperimentTest.php +++ b/tests/Prismic/ExperimentTest.php @@ -1,16 +1,17 @@ getJsonFixture('experiments.json')); $this->experiments = Experiments::parse($experimentsJson); } @@ -39,7 +40,5 @@ public function testCookieParsing() $this->assertNull($this->experiments->refFromCookie("_UQtin7EQAOH5M34RQq6Dg -1"), "Index overflow negative index"); $this->assertNull($this->experiments->refFromCookie("NotAGoodLookingId 0"), "Unknown Google ID"); $this->assertNull($this->experiments->refFromCookie("NotAGoodLookingId 1"), "Unknown Google ID"); - } - } diff --git a/tests/Prismic/FakeLinkResolver.php b/tests/Prismic/FakeLinkResolver.php index 0116fab2..3ec7a4a4 100644 --- a/tests/Prismic/FakeLinkResolver.php +++ b/tests/Prismic/FakeLinkResolver.php @@ -1,4 +1,5 @@ isBroken) { return 'http://host/404'; diff --git a/tests/Prismic/GuzzleClient.php b/tests/Prismic/GuzzleClient.php new file mode 100644 index 00000000..0418d94c --- /dev/null +++ b/tests/Prismic/GuzzleClient.php @@ -0,0 +1,20 @@ +assertEquals('[:d = not(document.type, "blog-post")]', $predicate->q()); } - public function testAnyPredicate() { - $p = Predicates::any("document.tags", array("Macaron", "Cupcakes")); + $p = Predicates::any("document.tags", ["Macaron", "Cupcakes"]); $this->assertEquals('[:d = any(document.tags, ["Macaron", "Cupcakes"])]', $p->q()); } @@ -56,5 +56,4 @@ public function testGeopointNear() $p = Predicates::near("my.store.coordinates", 40.689757, -74.0451453, 15); $this->assertEquals("[:d = geopoint.near(my.store.coordinates, 40.689757, -74.0451453, 15)]", $p->q()); } - } diff --git a/tests/Prismic/RefTest.php b/tests/Prismic/RefTest.php index 1af859cb..a77f7055 100644 --- a/tests/Prismic/RefTest.php +++ b/tests/Prismic/RefTest.php @@ -1,22 +1,25 @@ refs) { - $this->refs = json_decode(file_get_contents(__DIR__.'/../fixtures/refs.json')); + if (! $this->refs) { + $this->refs = \json_decode($this->getJsonFixture('refs.json')); } - $out = array(); - foreach($this->refs->refs as $ref) { - $out[] = array($ref); + $out = []; + foreach ($this->refs->refs as $ref) { + $out[] = [$ref]; } return $out; } @@ -34,9 +37,9 @@ public function testParseRefs($json) $this->assertInternalType('string', $ref->getLabel()); $this->assertStringMatchesFormat('%s', $ref->getLabel()); $this->assertInternalType('boolean', $ref->isMasterRef()); - if(!is_null($ref->getScheduledAt())) { + if (! is_null($ref->getScheduledAt())) { $this->assertInternalType('int', $ref->getScheduledAt()); - $this->assertEquals(13, strlen($ref->getScheduledAt()), 'Expected a 13 digit number'); + $this->assertEquals(13, strlen((string)$ref->getScheduledAt()), 'Expected a 13 digit number'); } } @@ -46,9 +49,13 @@ public function testParseRefs($json) public function testGetScheduledAtTimestamp($json) { $ref = Ref::parse($json); - if(!is_null($ref->getScheduledAtTimestamp())) { + + if (! is_null($ref->getScheduledAtTimestamp())) { $this->assertInternalType('int', $ref->getScheduledAtTimestamp()); - $this->assertEquals(10, strlen($ref->getScheduledAtTimestamp()), 'Expected a 10 digit number'); + $this->assertEquals(10, strlen((string)$ref->getScheduledAtTimestamp()), 'Expected a 10 digit number'); + } else { + // Squash No assertions warning in PHP Unit + $this->assertNull($ref->getScheduledAtTimestamp()); } } @@ -67,9 +74,9 @@ public function testToStringSerialisesToRef($json) public function testGetScheduledDate($json) { $ref = Ref::parse($json); - if(!is_null($ref->getScheduledAtTimestamp())) { + if (! is_null($ref->getScheduledAtTimestamp())) { $date = $ref->getScheduledDate(); - $this->assertInstanceOf('DateTime', $date); + $this->assertInstanceOf(DateTimeImmutable::class, $date); $this->assertSame($ref->getScheduledAtTimestamp(), $date->getTimestamp()); $this->assertNotSame($date, $ref->getScheduledDate(), 'Returned date should be a new instance every time'); } else { @@ -77,4 +84,11 @@ public function testGetScheduledDate($json) } } + /** + * @expectedException Prismic\Exception\ExceptionInterface + */ + public function testExceptionThrownForInvalidJsonObject() + { + Ref::parse(new stdClass); + } } diff --git a/tests/Prismic/SearchFormTest.php b/tests/Prismic/SearchFormTest.php new file mode 100644 index 00000000..97f2c142 --- /dev/null +++ b/tests/Prismic/SearchFormTest.php @@ -0,0 +1,459 @@ +apiData = ApiData::withJsonString($this->getJsonFixture('data.json')); + $this->form = Form::withJsonObject($this->apiData->getForms()['blogs']); + $this->httpClient = $this->prophesize(GuzzleClient::class); + $this->cache = $this->prophesize(CacheInterface::class); + } + + protected function getSearchForm() : SearchForm + { + return new SearchForm( + $this->httpClient->reveal(), + $this->cache->reveal(), + $this->form, + $this->form->defaultData() + ); + } + + public function testGetDataReturnsArray() + { + $form = $this->getSearchForm(); + $this->assertInternalType('array', $form->getData()); + } + + /** + * @expectedException \Prismic\Exception\InvalidArgumentException + * @expectedExceptionMessage Form parameter key must be a non-empty string + */ + public function testSetWithAnEmptyKeyThrowsException() + { + $form = $this->getSearchForm(); + $form->set('', 'foo'); + } + + /** + * @expectedException \Prismic\Exception\InvalidArgumentException + * @expectedExceptionMessage Form parameter value must be scalar + */ + public function testSetWithANonScalarValueThrowsException() + { + $form = $this->getSearchForm(); + $form->set('page', ['an-array']); + } + + /** + * @expectedException \Prismic\Exception\InvalidArgumentException + * @expectedExceptionMessage Unknown form field parameter + */ + public function testSetWithAnUnknownKeyThrowsException() + { + $form = $this->getSearchForm(); + $form->set('whatever', 'foo'); + } + + /** + * @expectedException \Prismic\Exception\InvalidArgumentException + * @expectedExceptionMessage expects a string parameter + */ + public function testSetStringParamWithNonStringThrowsException() + { + $form = $this->getSearchForm(); + $form->set('lang', 1); + } + + /** + * @expectedException \Prismic\Exception\InvalidArgumentException + * @expectedExceptionMessage expects an integer parameter + */ + public function testSetIntParamWithNonNumberThrowsException() + { + $form = $this->getSearchForm(); + $form->set('page', 'foo'); + } + + protected function assertSearchFormClone(SearchForm $a, SearchForm $b) + { + $this->assertNotSame($a, $b); + } + + public function testSetIsSuccessfulForSingleScalarValue() + { + $form = $this->getSearchForm(); + $data = $form->getData(); + $this->assertEquals('1', $data['page']); + + $clone = $form->set('page', 10); + + $this->assertSearchFormClone($form, $clone); + + $data = $clone->getData(); + $this->assertEquals('10', $data['page']); + } + + public function testSetAppendsForMultipleFields() + { + $form = $this->getSearchForm(); + $data = $form->getData(); + $this->assertCount(1, $data['q']); + $this->assertNotContains('some-value', $data['q']); + $clone = $form->set('q', 'some-value'); + $data = $clone->getData(); + $this->assertCount(2, $data['q']); + $this->assertContains('some-value', $data['q']); + } + + public function testRefAcceptsString() + { + $form = $this->getSearchForm(); + $clone = $form->ref('some-ref'); + $this->assertSearchFormClone($form, $clone); + $data = $clone->getData(); + $this->assertSame('some-ref', $data['ref']); + } + + public function testRefAcceptsRef() + { + $ref = current($this->apiData->getRefs()); + $form = $this->getSearchForm(); + $clone = $form->ref($ref); + $data = $clone->getData(); + $this->assertSame((string) $ref, $data['ref']); + } + + private function assertScalarOptionIsSet(SearchForm $form, string $key, $expectedValue) + { + $data = $form->getData(); + $this->assertArrayHasKey($key, $data); + $this->assertSame($expectedValue, $data[$key]); + } + + private function assertScalarOptionIsNotSet(SearchForm $form, string $key) + { + $data = $form->getData(); + $this->assertArrayNotHasKey($key, $data); + } + + public function testAfter() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->after('Whatever'), + 'after', + 'Whatever' + ); + } + + public function testLang() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->lang('en-gb'), + 'lang', + 'en-gb' + ); + } + + public function testPageSize() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->pageSize(99), + 'pageSize', + 99 + ); + } + + public function testPage() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->page(99), + 'page', + 99 + ); + } + + public function testFetchWithStringArgs() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->fetch('one', 'two', 'three'), + 'fetch', + 'one,two,three' + ); + } + + public function testFetchWithArrayArg() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->fetch(...['one','two','three']), + 'fetch', + 'one,two,three' + ); + } + + public function testFetchLinksWithStringArgs() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->fetchLinks('one', 'two', 'three'), + 'fetchLinks', + 'one,two,three' + ); + } + + public function testGraphQueryWithStringArg() + { + $query = '{ + blogpost { + title + } + }'; + + $this->assertScalarOptionIsSet( + $this->getSearchForm()->graphQuery($query), + 'graphQuery', + $query + ); + } + + public function testOrderingsWithStringArgs() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->orderings('one', 'two', 'three'), + 'orderings', + '[one,two,three]' + ); + } + + public function testOrderingsStripsSquareBrackets() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->orderings('[my.foo desc]', '[my.bar]'), + 'orderings', + '[my.foo desc,my.bar]' + ); + } + + public function testOrderingsWillAcceptUnpackedArrays() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->orderings(...['[my.a]', 'my.b', 'my.c desc']), + 'orderings', + '[my.a,my.b,my.c desc]' + ); + } + + public function testOrderingsFiltersEmptyValues() + { + $this->assertScalarOptionIsSet( + $this->getSearchForm()->orderings(...['', 'my.b', '', 'my.c desc']), + 'orderings', + '[my.b,my.c desc]' + ); + } + + public function testOrderingsIsNotSetWhenOnlyEmptyValuesAreProvided() + { + $this->assertScalarOptionIsNotSet( + $this->getSearchForm()->orderings(...['', '']), + 'orderings' + ); + } + + public function testStringQueryIsUnprocessedInQuery() + { + $form = $this->getSearchForm()->query('[:d = at(document.id, "ValidIdentifier")]'); + $data = $form->getData(); + $this->assertArrayHasKey('q', $data); + $this->assertContains('[:d = at(document.id, "ValidIdentifier")]', $data['q']); + } + + public function testSinglePredicateArgumentInQuery() + { + $predicate = Predicates::at('document.id', 'SomeId'); + $expect = sprintf('[%s]', $predicate->q()); + $form = $this->getSearchForm()->query($predicate); + $data = $form->getData(); + $this->assertContains($expect, $data['q']); + } + + public function testMultiplePredicatesInQuery() + { + $predicateA = Predicates::at('document.id', 'SomeId'); + $predicateB = Predicates::any('document.tags', 'Some Tag'); + $expect = sprintf('[%s%s]', $predicateA->q(), $predicateB->q()); + $form = $this->getSearchForm()->query($predicateA, $predicateB); + $data = $form->getData(); + $this->assertContains($expect, $data['q']); + } + + public function testUnpackedPredicateArrayInQuery() + { + $query = [ + Predicates::at('document.id', 'SomeId'), + Predicates::any('document.tags', 'Some Tag'), + ]; + $expect = sprintf('[%s%s]', $query[0]->q(), $query[1]->q()); + $form = $this->getSearchForm()->query(...$query); + $data = $form->getData(); + $this->assertContains($expect, $data['q']); + } + + public function testRegularArrayArgumentInQuery() + { + $query = [ + Predicates::at('document.id', 'SomeId'), + Predicates::any('document.tags', 'Some Tag'), + ]; + $expect = sprintf('[%s%s]', $query[0]->q(), $query[1]->q()); + $form = $this->getSearchForm()->query($query); + $data = $form->getData(); + $this->assertContains($expect, $data['q']); + } + + public function testEmptyArgumentToQueryHasNoEffect() + { + $form = $this->getSearchForm()->query(''); + $data = $form->getData(); + $field = $this->form->getField('q'); + $this->assertCount(1, $data['q']); + $this->assertContains($field->getDefaultValue(), $data['q']); + } + + public function testUrlRemovesPhpArrayKeys() + { + $form = $this->getSearchForm()->query('query_string'); + $url = $form->url(); + $query = parse_url($url, PHP_URL_QUERY); + $this->assertSame(2, substr_count($query, 'q=')); + } + + public function testCachedResponseWillBeReturnedInSubmit() + { + $cachedJson = \json_decode('{"some":"data"}'); + $this->cache->get(Argument::type('string'))->willReturn($cachedJson); + $response = $this->getSearchForm()->submit(); + $this->assertSame($cachedJson, $response); + } + + /** + * @expectedException \Prismic\Exception\RuntimeException + * @expectedExceptionMessage Form type not supported + */ + public function testExceptionIsThrownForInvalidForm() + { + $formJson = '{ + "method": "POST", + "enctype": "application/x-www-form-urlencoded", + "action": "https://whatever/api/v2/documents/search", + "fields": {} + }'; + $form = Form::withJsonString($formJson); + $searchForm = new SearchForm( + $this->httpClient->reveal(), + $this->cache->reveal(), + $form, + $form->defaultData() + ); + $searchForm->submit(); + } + + public function testGuzzleExceptionsAreWrappedInSubmit() + { + $guzzleException = new \GuzzleHttp\Exception\TransferException('A Guzzle Exception'); + /** @var \Prophecy\Prophecy\ObjectProphecy $this->httpClient */ + $this->httpClient->request('GET', Argument::type('string'))->willThrow($guzzleException); + $this->cache->get(Argument::type('string'))->willReturn(null); + $form = $this->getSearchForm(); + try { + $form->submit(); + $this->fail('No exception was thrown'); + } catch (\Prismic\Exception\RequestFailureException $e) { + $this->assertSame($guzzleException, $e->getPrevious()); + } + } + + private function prepareResponse(?string $body = null) : Response + { + $body = $body ? $body : '{"data":"data"}'; + $response = new Response( + 200, + ['Cache-Control' => 'max-age=999'], + $body + ); + $this->httpClient->request('GET', Argument::type('string'))->willReturn($response); + return $response; + } + + public function testResponseJsonIsReturned() + { + $this->prepareResponse(); + $this->cache->get(Argument::type('string'))->willReturn(null); + $this->cache->set( + Argument::type('string'), + Argument::type(\stdClass::class), + 999 + )->shouldBeCalled(); + $form = $this->getSearchForm(); + $response = $form->submit(); + $this->assertInstanceOf(\stdClass::class, $response); + $this->assertSame('data', $response->data); + } + + public function testCountReturnsIntWhenPresentInResponseBody() + { + $this->prepareResponse('{"total_results_size":10}'); + $this->cache->get(Argument::type('string'))->willReturn(null); + $this->cache->set( + Argument::type('string'), + Argument::type(\stdClass::class), + 999 + )->shouldBeCalled(); + $form = $this->getSearchForm(); + $this->assertSame(10, $form->count()); + } + + /** + * @expectedException \Prismic\Exception\RuntimeException + * @expectedExceptionMessage Unable to decode json response + */ + public function testExceptionIsThrownForInvalidJson() + { + $this->prepareResponse('Invalid JSON String'); + $this->cache->get(Argument::type('string'))->willReturn(null); + $this->cache->set()->shouldNotBeCalled(); + $form = $this->getSearchForm(); + $form->submit(); + } +} diff --git a/tests/Prismic/TestCase.php b/tests/Prismic/TestCase.php new file mode 100644 index 00000000..deb38cfc --- /dev/null +++ b/tests/Prismic/TestCase.php @@ -0,0 +1,20 @@ + '1234']; + $this->assertEquals(Utils::buildUrl('https://test.prismic.io/api/v2', $parameters), $url); + } + + public function testBuildUrl2() + { + $url = 'https://test.prismic.io/api/v2/documents/search?integrationFieldsRef=1234&page=2&pageSize=3&graphQuery=%7B%20blogpost%20%7B%20title%20%7D%20%7D'; + $parameters = [ + 'page' => '2', + 'pageSize' => '3', + 'graphQuery' => '{ blogpost { title } }' + ]; + $this->assertEquals(Utils::buildUrl('https://test.prismic.io/api/v2/documents/search?integrationFieldsRef=1234', $parameters), $url); + } +} diff --git a/tests/fixtures/data.json b/tests/fixtures/data.json index 6dd93f2f..900f3003 100644 --- a/tests/fixtures/data.json +++ b/tests/fixtures/data.json @@ -10,6 +10,11 @@ "id": "UkL0hcuvzYUANCrr", "ref": "UgjWRd_mqbYHvPJa", "label": "San Francisco Grand opening" + }, + { + "id": "SaGrandOpening2ndRef", + "ref": "SaGrandOpening2ndRef", + "label": "San Francisco Grand opening" } ], "bookmarks": { @@ -39,8 +44,109 @@ "type": "String" } } + }, + "blogs": { + "name": "Blog Posts", + "method": "GET", + "rel": "collection", + "enctype": "application/x-www-form-urlencoded", + "action": "https://lesbonneschoses.prismic.io/api/v2/documents/search", + "fields": { + "ref": { + "type": "String", + "multiple": false + }, + "q": { + "default": "[[:d = any(document.type, [\"blog-post\"])]]", + "type": "String", + "multiple": true + }, + "lang": { + "type": "String", + "multiple": false + }, + "page": { + "type": "Integer", + "multiple": false, + "default": "1" + }, + "pageSize": { + "type": "Integer", + "multiple": false, + "default": "20" + }, + "after": { + "type": "String", + "multiple": false + }, + "fetch": { + "type": "String", + "multiple": false + }, + "fetchLinks": { + "type": "String", + "multiple": false + }, + "graphQuery": { + "type": "String", + "multiple": false + }, + "orderings": { + "type": "String", + "multiple": false + }, + "referer": { + "type": "String", + "multiple": false + }, + "access_token": { + "default": "a-permanent-access-token", + "type": "String", + "multiple": false + } + } } }, "oauth_initiate": "http://lesbonneschoses.prismic.io/auth", - "oauth_token": "http://lesbonneschoses.prismic.io/auth/token" + "oauth_token": "http://lesbonneschoses.prismic.io/auth/token", + "experiments" : { + "draft": [ + { + "id": "xxxxxxxxxxoGelsX", + "name": "Exp 2", + "variations": [ + { + "id": "VDUBBawGAKoGelsZ", + "label": "Base", + "ref": "VDUBBawGALAGelsa" + }, + { + "id": "VDUE-awGALAGemME", + "label": "var 1", + "ref": "VDUUmHIKAZQKk9uq" + } + ] + } + ], + "running": [ + { + "googleId": "_UQtin7EQAOH5M34RQq6Dg", + "id": "VDUBBawGAKoGelsX", + "name": "Exp 1", + "variations": [ + { + "id": "VDUBBawGAKoGelsZ", + "label": "Base", + "ref": "VDUBBawGALAGelsa" + }, + { + "id": "VDUE-awGALAGemME", + "label": "var 1", + "ref": "VDUUmHIKAZQKk9uq" + } + ] + } + ] + } + }