diff --git a/.env.travis b/.env.travis new file mode 100644 index 0000000000..ee2f7476ba --- /dev/null +++ b/.env.travis @@ -0,0 +1,5 @@ +DB_TYPE=MySQLi +DB_HOST=127.0.0.1 +DB_NAME=ushahidi +DB_PASS= +DB_USER=travis diff --git a/.travis.yml b/.travis.yml index d3aa010937..f053b1ded0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,41 +1,45 @@ sudo: false -notifications: - hipchat: - rooms: - secure: fb2eYR4DVBestPl/DSG7lnUWT46Rmr9BfRsZFe4dhrS3ZetkZ1XZueF6SCtB4yukaJoDlA7y98FgQ7eGx6OGToc4ALnPpwd3BdfJ5RV/PK/6LG7u5Mp4+DfB4lG1q9IjuHF7dhBPSk2sRd8ewtwV5JR4SHKYfHxSR9Ekwmn1Xyo= - template: - - '%{repository}#%{build_number} (%{branch} - %{commit} - : %{author}): %{message}' - format: html - notify: true - slack: - secure: NxhzhKGYnZYZiWVZM4w1PlZpTy9bbmNlvbqjL+9d4PvK4hFzPwQU12CchhBPeXNGLWBHg/ti6Scn/t5XIS3YJrkk4ydWmJBht5UId8uFZ1A7GCUnNNPTt2RG55lbJJdZSj01rOGZjEQbE5RyckEjgRzhZjdZ+HsjoPaRzWIBrvE= +#notifications: +# slack: +# secure: NxhzhKGYnZYZiWVZM4w1PlZpTy9bbmNlvbqjL+9d4PvK4hFzPwQU12CchhBPeXNGLWBHg/ti6Scn/t5XIS3YJrkk4ydWmJBht5UId8uFZ1A7GCUnNNPTt2RG55lbJJdZSj01rOGZjEQbE5RyckEjgRzhZjdZ+HsjoPaRzWIBrvE= language: php php: -- '5.5' - '5.6' +- '7.0' +- '7.1' env: - coverage="--coverage" - coverage="" matrix: exclude: - - php: '5.5' + - php: '7.0' + env: coverage="--coverage" + - php: '7.1' env: coverage="--coverage" allow_failures: - env: coverage="--coverage" + - php: '7.1' fast_finish: true cache: directories: - "$HOME/.composer/cache" services: - mysql +before_install: +- mysql -e 'CREATE DATABASE ushahidi;' +- mysql -e "select version();" +- mysql -e "SET GLOBAL sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'" +- cp .env.travis .env install: - composer install --no-interaction before_script: -- "./bin/tests install" +- composer pre-test +- if [ "${coverage}" == "" ]; then php -S localhost:8000 -t httpdocs httpdocs/index.php & fi +- if [ "${coverage}" != "" ]; then php -S localhost:8000 -t httpdocs httpdocs/coverage.php & fi - mysql -e 'SET @@GLOBAL.wait_timeout=1800' script: -- "./bin/tests run --no-install $coverage" +- if [ "${coverage}" == "" ]; then composer test; fi +- if [ "${coverage}" != "" ]; then composer run coverage --timeout=0; fi - composer lint after_success: - if [ "${coverage}" != "" ]; then travis_retry bin/coveralls -v; fi diff --git a/Homestead.yaml b/Homestead.yaml new file mode 100644 index 0000000000..85fb500a08 --- /dev/null +++ b/Homestead.yaml @@ -0,0 +1,27 @@ +ip: 192.168.33.110 +memory: 1024 +cpus: 1 +provider: virtualbox +authorize: ~/.ssh/id_rsa.pub +keys: + - ~/.ssh/id_rsa +folders: + - + map: "./" + to: /vagrant + type: "nfs" + - + map: "./" + to: /home/vagrant/Code/platform-api + type: "nfs" +sites: + - + map: api.ushahidi.app + to: /home/vagrant/Code/platform-api/httpdocs + - + map: ushv3.dev + to: /home/vagrant/Code/platform-api/httpdocs +databases: + - ushahidi +name: platform-api +hostname: platform-api diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 595f052dbe..cd5b43c9c6 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,8 @@ This pull request makes the following changes: - -Test these changes by: -- +Test checklist: +- [ ] Fixes ushahidi/platform# . diff --git a/Puppetfile b/Puppetfile deleted file mode 100644 index 8f243c9a21..0000000000 --- a/Puppetfile +++ /dev/null @@ -1,6 +0,0 @@ -forge "https://forgeapi.puppetlabs.com" - -mod "puppetlabs/apt" -mod "puppetlabs/mysql" -mod "puppetlabs/apache" -mod "tPl0ch/composer" diff --git a/README.md b/README.md index d3945567d4..beb83ee87c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Ushahidi 3 ============ [![Build Status](https://travis-ci.org/ushahidi/platform.png)](https://travis-ci.org/ushahidi/platform) -[![Stories up next](https://badge.waffle.io/ushahidi/platform.png?label=Stage: Backlog&title=Backlog)](https://waffle.io/ushahidi/platform) +[![Stories up next](https://badge.waffle.io/ushahidi/platform.png?label=Stage:Backlog&title=Backlog)](https://waffle.io/ushahidi/platform) [![Coverage Status](https://coveralls.io/repos/github/ushahidi/platform/badge.svg)](https://coveralls.io/github/ushahidi/platform) [Download][download] @@ -26,7 +26,7 @@ Ushahidi is an open source web application for information collection, visualiza ### I'm a developer, should I contribute to Ushahidi v3? -Yes! Development moves pretty quickly but the tech stack is getting more and more stable. If you're keen to help build something awesome, [Jump on board..][getin] +Yes! Development moves pretty quickly but the tech stack is getting more and more stable. If you're keen to help build something awesome, [jump on board..][getin] ## Using the Platform diff --git a/Vagrantfile b/Vagrantfile index 5069ca4f7a..25e0fd1f40 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,34 +1,44 @@ -# Basic apache dev box complete with phpunit -# ready to go for ushahidi dev -Vagrant.configure("2") do |config| - config.vm.box = "puppetlabs/ubuntu-14.04-64-puppet" # vagrantcloud - config.vm.hostname = "ushahidi-platform.dev" - config.vm.network "private_network", ip: "192.168.33.110" - config.vm.synced_folder "./", "/var/www", id: "vagrant-root", :nfs => true - config.vm.network "forwarded_port", guest: 22, host: 2210 - config.ssh.port = 2210 - - config.vm.provider :virtualbox do |virtualbox| - virtualbox.customize ["modifyvm", :id, "--name", "ushahidi-platform"] - virtualbox.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] - virtualbox.customize ["modifyvm", :id, "--memory", "512"] - virtualbox.customize ["setextradata", :id, "--VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root", "1"] - end - - config.vm.provision :shell do |shell| - # upgrade all packages (including puppet) before using the puppet provisioner. - # this excludes grub-pc since the hard drive id changes between VMs and will cause - # an interactive prompt to appear and then error out, breaking the provisioning step. - shell.inline = "DEBIAN_FRONTEND=noninteractive apt-mark hold grub-pc && apt-get update -y && apt-get upgrade -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'" - end - - config.vm.provision :puppet do |puppet| - puppet.environment_path = "puppet/" - puppet.environment = "platform" - puppet.options = ["--verbose"] - puppet.facter = { - # Optionally pass in a github oauth token through an environment variable - "github_token" => ENV.fetch('github_token', '') - } - end +# -*- mode: ruby -*- +# vi: set ft=ruby : + +require 'json' +require 'yaml' + +VAGRANTFILE_API_VERSION ||= "2" +confDir = $confDir ||= File.expand_path("vendor/laravel/homestead", File.dirname(__FILE__)) + +homesteadYamlPath = File.expand_path("Homestead.yaml", File.dirname(__FILE__)) +homesteadJsonPath = File.expand_path("Homestead.json", File.dirname(__FILE__)) +afterScriptPath = "after.sh" +aliasesPath = "aliases" + +require File.expand_path(confDir + '/scripts/homestead.rb') + +Vagrant.require_version '>= 1.9.0' + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + if File.exist? aliasesPath then + config.vm.provision "file", source: aliasesPath, destination: "/tmp/bash_aliases" + config.vm.provision "shell" do |s| + s.inline = "awk '{ sub(\"\r$\", \"\"); print }' /tmp/bash_aliases > /home/vagrant/.bash_aliases" + end + end + + if File.exist? homesteadYamlPath then + settings = YAML::load(File.read(homesteadYamlPath)) + elsif File.exist? homesteadJsonPath then + settings = JSON.parse(File.read(homesteadJsonPath)) + else + abort "Homestead settings file not found in #{confDir}" + end + + Homestead.configure(config, settings) + + if File.exist? afterScriptPath then + config.vm.provision "shell", path: afterScriptPath, privileged: false + end + + if defined? VagrantPlugins::HostsUpdater + config.hostsupdater.aliases = settings['sites'].map { |site| site['map'] } + end end diff --git a/application/classes/ORM.php b/application/classes/ORM.php deleted file mode 100755 index 357cde9c57..0000000000 --- a/application/classes/ORM.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @package Ushahidi\Application\Models - * @copyright 2013 Ushahidi - * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) - */ - -class ORM extends Kohana_ORM { - - /** - * Callback function to check if fk exists - */ - public function fk_exists($model_name, $field, $value) - { - return ORM::factory($model_name, $value)->loaded(); - } - -} diff --git a/application/classes/Unittest/Database/TestCase.php b/application/classes/Unittest/Database/TestCase.php deleted file mode 100644 index e333c48540..0000000000 --- a/application/classes/Unittest/Database/TestCase.php +++ /dev/null @@ -1,60 +0,0 @@ - - * @package Ushahidi\Unittest - * @copyright 2013 Ushahidi - * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) - */ - -abstract class Unittest_Database_TestCase extends Kohana_Unittest_Database_TestCase { - - /** - * Creates a connection to the unittesting database - * Overriding to fix database type in DSN - must be lowercase - * - * @return PDO - */ - public function getConnection() - { - // Get the unittesting db connection - $config = Kohana::$config->load('database.'.$this->_database_connection); - - if($config['type'] !== 'pdo') - { - // Replace MySQLi with MySQL since MySQLi isn't valid for a DSN - $type = $config['type'] === 'MySQLi' ? 'MySQL' : $config['type']; - - $config['connection']['dsn'] = strtolower($type).':'. - 'host='.$config['connection']['hostname'].';'. - 'dbname='.$config['connection']['database']; - } - - $pdo = new PDO( - $config['connection']['dsn'], - $config['connection']['username'], - $config['connection']['password'] - ); - - return $this->createDefaultDBConnection($pdo, $config['connection']['database']); - } - - /** - * Returns the database operation executed in test setup. - * Overriding to fix Mysql 5.5 truncate errors - * - * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation - */ - protected function getSetUpOperation() - { - //return PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT(); - $cascadeTruncates = TRUE; - return new PHPUnit_Extensions_Database_Operation_Composite(array( - new Unittest_Database_Operation_MySQL55Truncate($cascadeTruncates), - PHPUnit_Extensions_Database_Operation_Factory::INSERT() - )); - } - -} diff --git a/application/classes/Ushahidi/Console/Webhook.php b/application/classes/Ushahidi/Console/Webhook.php index 3126844583..9386ff2e30 100644 --- a/application/classes/Ushahidi/Console/Webhook.php +++ b/application/classes/Ushahidi/Console/Webhook.php @@ -30,7 +30,6 @@ class Ushahidi_Console_Webhook extends Command private $postRepository; private $webhookRepository; private $webhookJobRepository; - private $signer; private $client; public function setDatabase(Database $db) @@ -48,11 +47,6 @@ public function setPostRepo(PostRepository $repo) $this->postRepository = $repo; } - public function setSigner(Signer $signer) - { - $this->signer = $signer; - } - public function setWebhookJobRepo(WebhookJobRepository $repo) { $this->webhookJobRepository = $repo; @@ -126,7 +120,7 @@ private function generateRequest($webhook_request) // This is an asynchronous request, we don't expect a result // this can be extended to allow for handling of the returned promise - $promise = $this->client->requestAsync('POST', $webhook->url, [ + $promise = $this->client->request('POST', $webhook->url, [ 'headers' => [ 'X-Platform-Signature' => $signature, 'Accept' => 'application/json' diff --git a/application/classes/Ushahidi/Core.php b/application/classes/Ushahidi/Core.php index 55f3c578f2..1bede426b7 100644 --- a/application/classes/Ushahidi/Core.php +++ b/application/classes/Ushahidi/Core.php @@ -73,6 +73,11 @@ public static function init() and Kohana::$config->load('features.private.enabled'); }); + // Intercom config settings + $di->set('site.intercomAppToken', function() use ($di) { + return Kohana::$config->load('site.intercomAppToken'); + }); + // Roles config settings $di->set('roles.enabled', function() use ($di) { return Kohana::$config->load('features.roles.enabled'); @@ -149,7 +154,6 @@ public static function init() $di->setter['Ushahidi\Console\Application']['injectCommands'][] = $di->lazyNew('Ushahidi_Console_Webhook'); $di->setter['Ushahidi_Console_Webhook']['setDatabase'] = $di->lazyGet('kohana.db'); $di->setter['Ushahidi_Console_Webhook']['setPostRepo'] = $di->lazyGet('repository.post'); - $di->setter['Ushahidi_Console_Webhook']['setSigner'] = $di->lazyGet('tool.signer'); $di->setter['Ushahidi_Console_Webhook']['setWebhookRepo'] = $di->lazyGet('repository.webhook'); $di->setter['Ushahidi_Console_Webhook']['setWebhookJobRepo'] = $di->lazyGet('repository.webhook.job'); @@ -289,6 +293,7 @@ public static function init() // Validation Trait $di->setter['Ushahidi\Core\Tool\ValidationEngineTrait']['setValidation'] = $di->newFactory('Ushahidi_ValidationEngine'); + $di->params['Ushahidi_ValidationEngine']['array'] = []; // Formatter mapping $di->params['Ushahidi\Factory\FormatterFactory']['map'] = [ @@ -351,53 +356,8 @@ public static function init() // Set Formatter factory $di->params['Ushahidi\Factory\FormatterFactory']['factory'] = $di->newFactory('Ushahidi_Formatter_Collection'); - // Helpers, tools, etc - $di->set('tool.hasher.password', $di->lazyNew('Ushahidi_Hasher_Password')); - $di->set('tool.signer', $di->lazyNew('Ushahidi\Core\Tool\Signer')); - $di->set('tool.authenticator.password', $di->lazyNew('Ushahidi_Authenticator_Password')); - $di->set('tool.validation', $di->lazyNew('Ushahidi_ValidationEngine')); $di->set('tool.jsontranscode', $di->lazyNew('Ushahidi\Core\Tool\JsonTranscode')); - $di->set('tool.acl', $di->lazyNew('Ushahidi_Acl')); - $di->setter['Ushahidi_Acl']['setRoleRepo'] = $di->lazyGet('repository.role'); - - // Register filesystem adpater types - // Currently supported: Local filesysten, AWS S3 v3, Rackspace - // the naming scheme must match the cdn type set in config/cdn - $di->set('adapter.local', $di->lazyNew( - 'Ushahidi_FilesystemAdapter_Local', - [ - 'config' => $di->lazyGet('cdn.config') - ] - ) - ); - $di->set('adapter.aws', $di->lazyNew( - 'Ushahidi_FilesystemAdapter_AWS', - [ - 'config' => $di->lazyGet('cdn.config') - ] - ) - ); - $di->set('adapter.rackspace', $di->lazyNew( - 'Ushahidi_FilesystemAdapter_Rackspace', - [ - 'config' => $di->lazyGet('cdn.config') - ] - ) - ); - - // Media Filesystem - // The Ushahidi filesystem adapter returns a flysystem adapter for a given - // cdn type based on the provided configuration - $di->set('tool.filesystem', $di->lazyNew('Ushahidi_Filesystem')); - $di->params['Ushahidi_Filesystem'] = [ - 'adapter' => $di->lazy(function () use ($di) { - $adapter_type = $di->get('cdn.config'); - $fsa = $di->get('adapter.' . $adapter_type['type']); - - return $fsa->getAdapter(); - }) - ]; // Formatters $di->set('formatter.entity.api', $di->lazyNew('Ushahidi_Formatter_API')); @@ -472,14 +432,24 @@ public static function init() 'upload' => $di->lazyGet('tool.uploader'), ]; + // Form Stage repository parameters + $di->params['Ushahidi_Repository_Form_Stage'] = [ + 'form_repo' => $di->lazyGet('repository.form') + ]; + + // Form Attribute repository parameters + $di->params['Ushahidi_Repository_Form_Attribute'] = [ + 'form_stage_repo' => $di->lazyGet('repository.form_stage'), + 'form_repo' => $di->lazyGet('repository.form') + ]; + // Post repository parameters $di->params['Ushahidi_Repository_Post'] = [ 'form_attribute_repo' => $di->lazyGet('repository.form_attribute'), 'form_stage_repo' => $di->lazyGet('repository.form_stage'), 'form_repo' => $di->lazyGet('repository.form'), 'post_value_factory' => $di->lazyGet('repository.post_value_factory'), - 'bounding_box_factory' => $di->newFactory('Util_BoundingBox'), - 'tag_repo' => $di->lazyGet('repository.tag') + 'bounding_box_factory' => $di->newFactory('Util_BoundingBox') ]; $di->set('repository.post.datetime', $di->lazyNew('Ushahidi_Repository_Post_Datetime')); @@ -494,6 +464,11 @@ public static function init() $di->set('repository.post.markdown', $di->lazyNew('Ushahidi_Repository_Post_Markdown')); $di->set('repository.post.title', $di->lazyNew('Ushahidi_Repository_Post_Title')); $di->set('repository.post.media', $di->lazyNew('Ushahidi_Repository_Post_Media')); + $di->set('repository.post.tags', $di->lazyNew('Ushahidi_Repository_Post_Tags')); + + $di->params['Ushahidi_Repository_Post_Tags'] = [ + 'tag_repo' => $di->lazyGet('repository.tag') + ]; // The post value repo factory $di->set('repository.post_value_factory', $di->lazyNew('Ushahidi_Repository_Post_ValueFactory')); @@ -512,6 +487,7 @@ public static function init() 'markdown' => $di->lazyGet('repository.post.markdown'), 'title' => $di->lazyGet('repository.post.title'), 'media' => $di->lazyGet('repository.post.media'), + 'tags' => $di->lazyGet('repository.post.tags'), ], ]; @@ -572,7 +548,8 @@ public static function init() 'user_repo' => $di->lazyGet('repository.user'), 'collection_repo' => $di->lazyGet('repository.set'), 'savedsearch_repo' => $di->lazyGet('repository.savedsearch'), - ];$di->params['Ushahidi_Validator_Webhook_Update'] = [ + ]; + $di->params['Ushahidi_Validator_Webhook_Update'] = [ 'user_repo' => $di->lazyGet('repository.user'), ]; $di->params['Ushahidi_Validator_SavedSearch_Create'] = [ @@ -649,6 +626,10 @@ public static function init() $di->params['Ushahidi_Validator_Post_Media'] = [ 'media_repo' => $di->lazyGet('repository.media') ]; + $di->set('validator.post.tags', $di->lazyNew('Ushahidi_Validator_Post_Tags')); + $di->params['Ushahidi_Validator_Post_Tags'] = [ + 'tags_repo' => $di->lazyGet('repository.tag') + ]; $di->set('validator.post.value_factory', $di->lazyNew('Ushahidi_Validator_Post_ValueFactory')); @@ -663,10 +644,11 @@ public static function init() 'point' => $di->lazyGet('validator.post.point'), 'relation' => $di->lazyGet('validator.post.relation'), 'varchar' => $di->lazyGet('validator.post.varchar'), - 'markdown' => $di->lazyGet('validator.post.markdown'), + 'markdown' => $di->lazyGet('validator.post.markdown'), 'title' => $di->lazyGet('validator.post.title'), 'media' => $di->lazyGet('validator.post.media'), 'video' => $di->lazyGet('validator.post.video'), + 'tags' => $di->lazyGet('validator.post.tags'), ], ]; @@ -680,12 +662,6 @@ public static function init() $di->setter['Ushahidi_Transformer_CSVPostTransformer']['setRepo'] = $di->lazyGet('repository.post'); - $di->set('filereader.csv', $di->lazyNew('Ushahidi_FileReader_CSV')); - $di->setter['Ushahidi_FileReader_CSV']['setReaderFactory'] = - $di->lazyGet('csv.reader_factory'); - - $di->set('csv.reader_factory', $di->lazyNew('Ushahidi_CSVReaderFactory')); - $di->set('tool.mailer', $di->lazyNew('Ushahidi_Mailer')); // Event listener for the Set repo @@ -711,69 +687,21 @@ public static function init() $di->setter['Ushahidi_Listener_PostListener']['setWebhookRepo'] = $di->lazyGet('repository.webhook'); - // Defined memcached - $di->set('memcached', $di->lazy(function () use ($di) { - $config = $di->get('ratelimiter.config'); - - $memcached = new Memcached(); - $memcached->addServer($config['memcached']['host'], $config['memcached']['port']); + // Add Intercom Listener to Config + $di->setter['Ushahidi_Repository_Config']['setEvent'] = 'ConfigUpdateEvent'; + $di->setter['Ushahidi_Repository_Config']['setListener'] = + $di->lazyNew('Ushahidi_Listener_IntercomListener'); - return $memcached; - })); + // Add Intercom Listener to Form + $di->setter['Ushahidi_Repository_Form']['setEvent'] = 'FormUpdateEvent'; + $di->setter['Ushahidi_Repository_Form']['setListener'] = + $di->lazyNew('Ushahidi_Listener_IntercomListener'); - // Set up login rate limiter - $di->set('ratelimiter.login.flap', $di->lazyNew('BehEh\Flaps\Flap')); - - $di->params['BehEh\Flaps\Flap'] = [ - 'storage' => $di->lazyNew('BehEh\Flaps\Storage\DoctrineCacheAdapter'), - 'name' => 'login' - ]; - - $di->set('ratelimiter.login.strategy', $di->lazyNew('BehEh\Flaps\Throttling\LeakyBucketStrategy')); - - // 3 requests every 1 minute by default - $di->params['BehEh\Flaps\Throttling\LeakyBucketStrategy'] = [ - 'requests' => 3, - 'timeSpan' => '1m' - ]; - - $di->set('ratelimiter.login', $di->lazyNew('Ushahidi_RateLimiter')); - - $di->params['Ushahidi_RateLimiter'] = [ - 'flap' => $di->lazyGet('ratelimiter.login.flap'), - 'throttlingStrategy' => $di->lazyGet('ratelimiter.login.strategy'), - ]; - - $di->params['BehEh\Flaps\Storage\DoctrineCacheAdapter'] = [ - 'cache' => $di->lazyGet('ratelimiter.cache') - ]; - - // Rate limit storage cache - $di->set('ratelimiter.cache', function() use ($di) { - $config = $di->get('ratelimiter.config'); - $cache = $config['cache']; - - if ($cache === 'memcached') { - $di->setter['Doctrine\Common\Cache\MemcachedCache']['setMemcached'] = - $di->lazyGet('memcached'); - - return $di->newInstance('Doctrine\Common\Cache\MemcachedCache'); - } - elseif ($cache === 'filesystem') { - $di->params['Doctrine\Common\Cache\FilesystemCache'] = [ - 'directory' => $config['filesystem']['directory'], - ]; - - return $di->newInstance('Doctrine\Common\Cache\FilesystemCache'); - } - - // Fall back to using in-memory cache if none is configured - return $di->newInstance('Doctrine\Common\Cache\ArrayCache'); - }); + // Add Intercom Listener to User + $di->setter['Ushahidi_Repository_User']['setEvent'] = 'UserGetAllEvent'; + $di->setter['Ushahidi_Repository_User']['setListener'] = + $di->lazyNew('Ushahidi_Listener_IntercomListener'); - // Rate limiter violation handler - $di->setter['BehEh\Flaps\Flap']['setViolationHandler'] = - $di->lazyNew('Ushahidi_ThrottlingViolationHandler'); /** * 1. Load the plugins diff --git a/application/classes/Ushahidi/Formatter/API.php b/application/classes/Ushahidi/Formatter/API.php index 693143ee82..ca99c823a5 100644 --- a/application/classes/Ushahidi/Formatter/API.php +++ b/application/classes/Ushahidi/Formatter/API.php @@ -107,7 +107,7 @@ protected function format_updated($value) protected function get_relation($resource, $id) { return !$id ? NULL : [ - 'id' => $id, + 'id' => intval($id), 'url' => URL::site(Ushahidi_Rest::url($resource, $id), Request::current()), ]; } diff --git a/application/classes/Ushahidi/Formatter/Form.php b/application/classes/Ushahidi/Formatter/Form.php index dc9d0e8866..893b7c8a01 100644 --- a/application/classes/Ushahidi/Formatter/Form.php +++ b/application/classes/Ushahidi/Formatter/Form.php @@ -26,4 +26,15 @@ protected function format_color($value) $value = ltrim($value, '#'); return $value ? '#' . $value : null; } + + protected function format_tags($tags) + { + $output = []; + foreach ($tags as $tagid) + { + $output[] = $this->get_relation('tags', $tagid); + } + + return $output; + } } diff --git a/application/classes/Ushahidi/Formatter/Post/CSV.php b/application/classes/Ushahidi/Formatter/Post/CSV.php index 899a5af7ac..fbcf155cc8 100644 --- a/application/classes/Ushahidi/Formatter/Post/CSV.php +++ b/application/classes/Ushahidi/Formatter/Post/CSV.php @@ -88,7 +88,6 @@ protected function generateCSVRecords($records) // Sort the keys so that they match with columns from the CSV heading ksort($record); - Kohana::$log->add(Log::ERROR, print_r($record, true)); fputcsv($fp, $record); } diff --git a/application/classes/Ushahidi/Formatter/Post/GeoJSONCollection.php b/application/classes/Ushahidi/Formatter/Post/GeoJSONCollection.php index 52efc6a17e..edc3d09dc5 100644 --- a/application/classes/Ushahidi/Formatter/Post/GeoJSONCollection.php +++ b/application/classes/Ushahidi/Formatter/Post/GeoJSONCollection.php @@ -28,7 +28,6 @@ public function __invoke($entities) 'type' => 'FeatureCollection', 'features' => [] ]; - $unmapped = 0; foreach ($entities as $entity) { @@ -48,7 +47,7 @@ public function __invoke($entities) { $color = ltrim($entity->color, '#'); $color = $color ? '#' . $color : null; - + $output['features'][] = [ 'type' => 'Feature', 'geometry' => [ @@ -68,12 +67,7 @@ public function __invoke($entities) ] ]; } - if(empty($geometries)) - { - $unmapped++; - } } - $output['unmapped'] = $unmapped; if ($this->search->bbox) { @@ -88,6 +82,11 @@ public function __invoke($entities) $output['bbox'] = $bbox; } + + // Note: Appending total output despite it not being in the geojson Spec + // this field is used by the client so that it can determine how many requests to make + // in order to retrieve all the posts + $output['total'] = $this->total; return $output; } diff --git a/application/classes/Ushahidi/Formatter/Post/Stats.php b/application/classes/Ushahidi/Formatter/Post/Stats.php index 7cab18990d..0a23f0bb9b 100644 --- a/application/classes/Ushahidi/Formatter/Post/Stats.php +++ b/application/classes/Ushahidi/Formatter/Post/Stats.php @@ -41,6 +41,10 @@ public function __invoke($records) } else { $data['totals'] = $this->formatTotals($records); } + + if (array_key_exists('unmapped', $records)) { + $data['unmapped'] = $records['unmapped']; + } } return $data; diff --git a/application/classes/Ushahidi/Formatter/Tag.php b/application/classes/Ushahidi/Formatter/Tag.php index c23d171618..e756272763 100644 --- a/application/classes/Ushahidi/Formatter/Tag.php +++ b/application/classes/Ushahidi/Formatter/Tag.php @@ -21,4 +21,19 @@ protected function format_color($value) $value = ltrim($value, '#'); return $value ? '#' . $value : null; } + + protected function format_children($tags) + { + $output = []; + + if (is_array($tags)) { + foreach ($tags as $tagid) + { + $output[] = $this->get_relation('tags', $tagid); + //$output[] = intval($tagid); + } + } + + return $output; + } } diff --git a/application/classes/Ushahidi/FormsTagsTrait.php b/application/classes/Ushahidi/FormsTagsTrait.php new file mode 100644 index 0000000000..3cdefb513b --- /dev/null +++ b/application/classes/Ushahidi/FormsTagsTrait.php @@ -0,0 +1,63 @@ + + * @package Ushahidi\Application\Controllers + * @copyright 2013 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) +*/ + +trait Ushahidi_FormsTagsTrait +{ + //returning tags for a specific Form-id + private function getTagsForForm($id) + { + $attributes = DB::select('form_attributes.options') + ->from('form_attributes') + ->join('form_stages')->on('form_stage_id', '=', 'form_stages.id') + ->join('forms')->on('form_id', '=', 'forms.id') + ->where('form_id', '=', $id) + ->where('form_attributes.type', '=', 'tags') + ->execute($this->db) + ->as_array(); + + $tags = []; + // Combine all tag ids into 1 array + foreach ($attributes as $attr) { + $options = json_decode($attr['options'], TRUE); + if (is_array($options)) { + $tags = array_merge($tags, $options); + } + } + + return $tags; + } + + private function removeTagFromAttributeOptions($id) + { + // Grab all tags attributes + $attr = DB::select('id', 'options') + ->from('form_attributes') + ->where('type', '=', 'tags') + ->execute($this->db) + ->as_array('id', 'options'); + + foreach ($attr as $attr_id => $options) { + $options = json_decode($options, TRUE); + if (is_array($options) && in_array($id, $options)) { + // Remove $id from options array + $index = array_search($id, $options); + array_splice($options, $index, 1); + $options = json_encode($options); + + // Save it + DB::update('form_attributes') + ->set(array('options' => $options)) + ->where('id', '=', $attr_id) + ->execute($this->db); + } + } + } +} diff --git a/application/classes/Ushahidi/Listener/IntercomListener.php b/application/classes/Ushahidi/Listener/IntercomListener.php new file mode 100644 index 0000000000..08a62acf1f --- /dev/null +++ b/application/classes/Ushahidi/Listener/IntercomListener.php @@ -0,0 +1,41 @@ + + * @package Ushahidi\Application + * @copyright 2014 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) + */ + +use League\Event\AbstractListener; +use League\Event\EventInterface; + +use Intercom\IntercomClient; + +use GuzzleHttp\Exception\ClientException; + +class Ushahidi_Listener_IntercomListener extends AbstractListener +{ + public function handle(EventInterface $event, $user_email = null, $data = null) + { + $intercomAppToken = service('site.intercomAppToken'); + + if ($user_email && $intercomAppToken) { + + $client = new IntercomClient($intercomAppToken, null); + try { + + $client->users->update([ + "email" => $user_email, + "custom_attributes" => $data + ]); + } catch(ClientException $e) { + Kohana::$log->add(Log::ERROR, print_r($e,true)); + } + } + } +} diff --git a/application/classes/Ushahidi/Repository.php b/application/classes/Ushahidi/Repository.php index 992a3a8830..04646d3fdc 100644 --- a/application/classes/Ushahidi/Repository.php +++ b/application/classes/Ushahidi/Repository.php @@ -128,6 +128,7 @@ public function getSearchTotal() { // Assume we can simply count the results to get a total $query = $this->getSearchQuery(true) + ->resetSelect() ->select([DB::expr('COUNT(*)'), 'total']); // Fetch the result and... @@ -170,7 +171,8 @@ protected function getSearchQuery($countable = false) if ($countable) { $query ->limit(null) - ->offset(null); + ->offset(null) + ->resetOrderBy(); } return $query; @@ -197,6 +199,7 @@ protected function selectOne(Array $where = []) protected function selectCount(Array $where = []) { $result = $this->selectQuery($where) + ->resetSelect() ->select([DB::expr('COUNT(*)'), 'total']) ->execute($this->db); return $result->get('total') ?: 0; diff --git a/application/classes/Ushahidi/Repository/Config.php b/application/classes/Ushahidi/Repository/Config.php index f68abff0f0..500998efb8 100644 --- a/application/classes/Ushahidi/Repository/Config.php +++ b/application/classes/Ushahidi/Repository/Config.php @@ -17,12 +17,18 @@ use Ushahidi\Core\Usecase\UpdateRepository; use Ushahidi\Core\Exception\NotFoundException; +use League\Event\ListenerInterface; +use Ushahidi\Core\Traits\Event; + class Ushahidi_Repository_Config implements ReadRepository, UpdateRepository, ConfigRepository { + // Use Event trait to trigger events + use Event; + // ReadRepository public function getEntity(Array $data = null) { @@ -43,27 +49,57 @@ public function get($group) // UpdateRepository public function update(Entity $entity) { + + $intercom_data = []; $group = $entity->getId(); $this->verifyGroup($group); $config = \Kohana::$config->load($group); + // Intercom count datasources + if ($group === 'data-provider') { + $intercom_data['num_data_sources'] = 0; + foreach ($entity->providers as $key => $value) { + $value ? $intercom_data['num_data_sources']++ : null; + } + } + $immutable = $entity->getImmutable(); - foreach ($entity->getChanged() as $key => $val) { - if (! in_array($key, $immutable)) { - + foreach ($entity->getChanged() as $key => $val) { + + // Emit Intercom Update events + if ($key === 'description') { + $intercom_data['has_description'] = true; + } + + if ($key === 'image_header') { + $intercom_data['has_logo'] = true; + } + + // New User - set their deployment created date + if ($key === 'first_login') { + $intercom_data['deployment_created_date'] = date("Y-m-d H:i:s"); + } + + if (! in_array($key, $immutable)) { + /* Below is to reset the twitter-since_id when the search-terms are updated. This should be revised when the data-source tech-debt is addressed*/ if($key === 'twitter' && isset($config['twitter']) && $val['twitter_search_terms'] !== $config['twitter']['twitter_search_terms']) - { + { $twitter_config = \Kohana::$config->load('twitter'); $twitter_config->set('since_id', 0); } - + $config->set($key, $val); } } + + if ($intercom_data) { + $user = service('session.user'); + $this->emit($this->event, $user->email, $intercom_data); + } } // ConfigRepository @@ -124,3 +160,4 @@ public function all(Array $groups = null) return $result; } } + diff --git a/application/classes/Ushahidi/Repository/Form.php b/application/classes/Ushahidi/Repository/Form.php index 61f14a66d4..66ad76fda0 100644 --- a/application/classes/Ushahidi/Repository/Form.php +++ b/application/classes/Ushahidi/Repository/Form.php @@ -14,9 +14,17 @@ use Ushahidi\Core\Entity\FormRepository; use Ushahidi\Core\SearchData; +use League\Event\ListenerInterface; +use Ushahidi\Core\Traits\Event; + class Ushahidi_Repository_Form extends Ushahidi_Repository implements FormRepository { + use Ushahidi_FormsTagsTrait; + + // Use Event trait to trigger events + use Event; + // Ushahidi_Repository protected function getTable() { @@ -27,12 +35,13 @@ protected function getTable() // ReadRepository public function getEntity(Array $data = null) { - if (isset($data["id"])) { + if (isset($data["id"])) { $can_create = $this->getRolesThatCanCreatePosts($data['id']); $data = $data + [ - 'can_create' => $can_create['roles'], + 'can_create' => $can_create['roles'], + 'tags' => $this->getTagsForForm($data['id']) ]; - } + } return new Form($data); } @@ -46,7 +55,6 @@ public function getSearchFields() protected function setSearchConditions(SearchData $search) { $query = $this->search_query; - if ($search->parent) { $query->where('parent_id', '=', $search->parent); } @@ -60,15 +68,29 @@ protected function setSearchConditions(SearchData $search) // CreateRepository public function create(Entity $entity) { + $id = parent::create($entity->setState(['created' => time()])); // todo ensure default group is created - - return parent::create($entity->setState(['created' => time()])); + return $id; } // UpdateRepository public function update(Entity $entity) { - return parent::update($entity->setState(['updated' => time()])); + // If orignal Form update Intercom if Name changed + if ($entity->id === 1) { + foreach ($entity->getChanged() as $key => $val) { + $user = service('session.user'); + $key === 'name' ? $this->emit($this->event, $user->email, ['primary_survey_name' => $val]) : null; + } + } + $form = $entity->getChanged(); + $form['updated'] = time(); + // removing tags from form before saving + unset($form['tags']); + // Finally save the form + $id = $this->executeUpdate(['id'=>$entity->id], $form); + + return $id; } /** @@ -81,6 +103,23 @@ public function getTotalCount(Array $where = []) return $this->selectCount($where); } + /** + * Get value of Form property hide_author + * if no form is found return false + * @param $form_id + * @return Boolean + */ + public function isAuthorHidden($form_id) + { + $query = DB::select('hide_author') + ->from('forms') + ->where('id', '=', $form_id); + + $results = $query->execute($this->db)->as_array(); + + return count($results) > 0 ? $results[0]['hide_author'] : false; + } + /** * Get `everyone_can_create` and list of roles that have access to post to the form * @param $form_id @@ -103,7 +142,7 @@ public function getRolesThatCanCreatePosts($form_id) $roles = []; - foreach($results as $role) { + foreach ($results as $role) { if (!is_null($role['name'])) { $roles[] = $role['name']; } @@ -113,7 +152,5 @@ public function getRolesThatCanCreatePosts($form_id) 'everyone_can_create' => $everyone_can_create, 'roles' => $roles, ]; - } - } diff --git a/application/classes/Ushahidi/Repository/Form/Attribute.php b/application/classes/Ushahidi/Repository/Form/Attribute.php index 27328d2745..ba15c0fa1e 100644 --- a/application/classes/Ushahidi/Repository/Form/Attribute.php +++ b/application/classes/Ushahidi/Repository/Form/Attribute.php @@ -13,6 +13,10 @@ use Ushahidi\Core\SearchData; use Ushahidi\Core\Entity\FormAttribute; use Ushahidi\Core\Entity\FormAttributeRepository; +use Ushahidi\Core\Entity\FormStageRepository; +use Ushahidi\Core\Entity\FormRepository; +use Ushahidi\Core\Traits\PostValueRestrictions; +use Ushahidi\Core\Traits\UserContext; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; @@ -20,8 +24,38 @@ class Ushahidi_Repository_Form_Attribute extends Ushahidi_Repository implements FormAttributeRepository { + use UserContext; + + use PostValueRestrictions; + + protected $form_stage_repo; + + protected $form_repo; + + protected $form_id; + // Use the JSON transcoder to encode properties use Ushahidi_JsonTranscodeRepository; + use Ushahidi_FormsTagsTrait; + + /** + * Construct + * @param Database $db + * @param FormStageRepository $form_stage_repo + * @param FormRepository $form_repo + */ + public function __construct( + Database $db, + FormStageRepository $form_stage_repo, + FormRepository $form_repo + ) + { + parent::__construct($db); + + $this->form_stage_repo = $form_stage_repo; + $this->form_repo = $form_repo; + + } // Ushahidi_JsonTranscodeRepository protected function getJsonProperties() @@ -29,6 +63,27 @@ protected function getJsonProperties() return ['options', 'config']; } + protected function getFormId($form_stage_id) + { + $form_id = $this->form_stage_repo->getFormByStageId($form_stage_id); + if ($form_id) { + return $form_id; + } + return null; + } + + // Override selectQuery to fetch attribute 'key' too + protected function selectQuery(Array $where = [], $form_id = null, $form_stage_id = null) + { + $query = parent::selectQuery($where); + + if (!$form_id && $form_stage_id) { + $form_id = $this->getFormId(); + } + + return $query; + } + // CreateRepository public function create(Entity $entity) { @@ -42,6 +97,37 @@ public function create(Entity $entity) } return $this->executeInsertAttribute($this->removeNullValues($record)); } + + // Override SearchRepository + public function setSearchParams(SearchData $search) + { + $form_id = null; + if ($search->form_id) { + $form_id = $search->form_id; + } + + $this->search_query = $this->selectQuery([], $form_id); + + $sorting = $search->getSorting(); + + if (!empty($sorting['orderby'])) { + $this->search_query->order_by( + $this->getTable() . '.' . $sorting['orderby'], + Arr::get($sorting, 'order') + ); + } + + if (!empty($sorting['offset'])) { + $this->search_query->offset($sorting['offset']); + } + + if (!empty($sorting['limit'])) { + $this->search_query->limit($sorting['limit']); + } + + // apply the unique conditions of the search + $this->setSearchConditions($search); + } // SearchRepository protected function setSearchConditions(SearchData $search) @@ -84,7 +170,8 @@ public function getSearchFields() // FormAttributeRepository public function getByKey($key, $form_id = null, $include_no_form = false) { - $query = $this->selectQuery() + + $query = $this->selectQuery([], $form_id) ->select('form_attributes.*') ->join('form_stages', 'LEFT') ->on('form_stages.id', '=', 'form_attributes.form_stage_id') @@ -122,7 +209,7 @@ public function getByForm($form_id) { $query = $this->selectQuery([ 'form_stages.form_id' => $form_id, - ]) + ], $form_id) ->select('form_attributes.*') ->join('form_stages', 'INNER') ->on('form_stages.id', '=', 'form_attributes.form_stage_id'); @@ -135,10 +222,12 @@ public function getByForm($form_id) // FormAttributeRepository public function getRequired($stage_id) { + $form_id = $this->getFormId($stage_id); + $query = $this->selectQuery([ 'form_attributes.form_stage_id' => $stage_id, 'form_attributes.required' => true - ]) + ], $form_id) ->select('form_attributes.*'); $results = $query->execute($this->db); diff --git a/application/classes/Ushahidi/Repository/Form/Stage.php b/application/classes/Ushahidi/Repository/Form/Stage.php index 7bdb52760b..86c0139032 100644 --- a/application/classes/Ushahidi/Repository/Form/Stage.php +++ b/application/classes/Ushahidi/Repository/Form/Stage.php @@ -13,16 +13,68 @@ use Ushahidi\Core\SearchData; use Ushahidi\Core\Entity\FormStage; use Ushahidi\Core\Entity\FormStageRepository; +use Ushahidi\Core\Entity\FormRepository; +use Ushahidi\Core\Traits\PostValueRestrictions; +use Ushahidi\Core\Traits\UserContext; + +use Ushahidi\Core\Traits\AdminAccess; +use Ushahidi\Core\Traits\PermissionAccess; +use Ushahidi\Core\Traits\Permissions\ManagePosts; class Ushahidi_Repository_Form_Stage extends Ushahidi_Repository implements FormStageRepository { + use UserContext; + + use PostValueRestrictions; + + // Checks if user is Admin + use AdminAccess; + + // Provides `hasPermission` + use PermissionAccess; + + // Provides `getPermission` + use ManagePosts; + + protected $form_id; + protected $form_repo; + + /** + * Construct + * @param Database $db + * @param FormRepository $form_repo + */ + public function __construct( + Database $db, + FormRepository $form_repo + ) + { + parent::__construct($db); + + $this->form_repo = $form_repo; + + } + // Ushahidi_Repository protected function getTable() { return 'form_stages'; } + // Override selectQuery to fetch attribute 'key' too + protected function selectQuery(Array $where = [], $form_id = null) + { + $query = parent::selectQuery($where); + + $user = $this->getUser(); + if (!$this->canUserEditForm($form_id, $user)) { + $query->where('show_when_published', '=', "1"); + } + + return $query; + } + // CreateRepository // ReadRepository public function getEntity(Array $data = null) @@ -36,6 +88,37 @@ public function getSearchFields() return ['form_id', 'label']; } + // Override SearchRepository + public function setSearchParams(SearchData $search) + { + $form_id = null; + if ($search->form_id) { + $form_id = $search->form_id; + } + + $this->search_query = $this->selectQuery([], $form_id); + + $sorting = $search->getSorting(); + + if (!empty($sorting['orderby'])) { + $this->search_query->order_by( + $this->getTable() . '.' . $sorting['orderby'], + Arr::get($sorting, 'order') + ); + } + + if (!empty($sorting['offset'])) { + $this->search_query->offset($sorting['offset']); + } + + if (!empty($sorting['limit'])) { + $this->search_query->limit($sorting['limit']); + } + + // apply the unique conditions of the search + $this->setSearchConditions($search); + } + // Ushahidi_Repository protected function setSearchConditions(SearchData $search) { @@ -51,15 +134,51 @@ protected function setSearchConditions(SearchData $search) } } + public function getFormByStageId($id) + { + $query = DB::select('form_id') + ->from('form_stages') + ->where('id', '=', $id); + + $results = $query->execute($this->db); + + return count($results) > 0 ? $results[0]['form_id'] : false; + } + // FormStageRepository public function getByForm($form_id) { - $query = $this->selectQuery(compact($form_id)); + $query = $this->selectQuery(compact($form_id), $form_id); $results = $query->execute($this->db); return $this->getCollection($results->as_array()); } + /** + * Retrieve Hidden Stage IDs for a given form + * if no form is found return false + * @param $form_id + * @return Array + */ + public function getHiddenStageIds($form_id) + { + $stages = []; + + $query = DB::select('id') + ->from('form_stages') + + ->where('form_id', '=', $form_id) + ->where('show_when_published', '=', 0); + + $results = $query->execute($this->db)->as_array(); + + foreach($results as $stage) { + array_push($stages, $stage['id']); + } + + return $stages; + } + // FormStageRepository public function existsInForm($id, $form_id) { @@ -72,7 +191,7 @@ public function getRequired($form_id) $query = $this->selectQuery([ 'form_stages.form_id' => $form_id, 'form_stages.required' => true - ]) + ], $form_id) ->select('form_stages.*'); $results = $query->execute($this->db); diff --git a/application/classes/Ushahidi/Repository/Post.php b/application/classes/Ushahidi/Repository/Post.php index 223b905bba..80cd563784 100644 --- a/application/classes/Ushahidi/Repository/Post.php +++ b/application/classes/Ushahidi/Repository/Post.php @@ -21,13 +21,13 @@ use Ushahidi\Core\SearchData; use Ushahidi\Core\Usecase\Post\StatsPostRepository; use Ushahidi\Core\Usecase\Post\UpdatePostRepository; -use Ushahidi\Core\Usecase\Post\UpdatePostTagRepository; use Ushahidi\Core\Usecase\Set\SetPostRepository; use Ushahidi\Core\Traits\UserContext; use Ushahidi\Core\Traits\Permissions\ManagePosts; use Ushahidi\Core\Traits\PermissionAccess; use Ushahidi\Core\Traits\AdminAccess; use Ushahidi\Core\Tool\Permissions\Permissionable; +use Ushahidi\Core\Traits\PostValueRestrictions; use Aura\DI\InstanceFactory; @@ -57,15 +57,21 @@ class Ushahidi_Repository_Post extends Ushahidi_Repository implements // Checks if user is Admin use AdminAccess; + // Check for value restrictions + // provides canUserReadPostsValues + use PostValueRestrictions; + protected $form_attribute_repo; protected $form_stage_repo; protected $form_repo; protected $post_value_factory; protected $bounding_box_factory; - protected $tag_repo; + // By default remove all private responses + protected $restricted = true; protected $include_value_types = []; protected $include_attributes = []; + protected $exclude_stages = []; protected $listener; @@ -83,8 +89,7 @@ public function __construct( FormStageRepository $form_stage_repo, FormRepository $form_repo, Ushahidi_Repository_Post_ValueFactory $post_value_factory, - InstanceFactory $bounding_box_factory, - UpdatePostTagRepository $tag_repo + InstanceFactory $bounding_box_factory ) { parent::__construct($db); @@ -94,7 +99,6 @@ public function __construct( $this->form_repo = $form_repo; $this->post_value_factory = $post_value_factory; $this->bounding_box_factory = $bounding_box_factory; - $this->tag_repo = $tag_repo; } // Ushahidi_Repository @@ -106,15 +110,45 @@ protected function getTable() // Ushahidi_Repository public function getEntity(Array $data = null) { + // Ensure we are dealing with a structured Post + + $user = $this->getUser(); + if ($data['form_id']) + { + + if ($this->canUserReadPostsValues(new Post($data), $user, $this->form_repo)) { + $this->restricted = false; + } + // Get Hidden Stage Ids to be excluded from results + $this->exclude_stages = $this->form_stage_repo->getHiddenStageIds($data['form_id']); + + } + if (!empty($data['id'])) { $data += [ 'values' => $this->getPostValues($data['id']), - 'tags' => $this->getTagsForPost($data['id']), + // Continued for legacy + 'tags' => $this->getTagsForPost($data['id'], $data['form_id']), 'sets' => $this->getSetsForPost($data['id']), 'completed_stages' => $this->getCompletedStagesForPost($data['id']), ]; } + // NOTE: This and the restriction above belong somewhere else, + // ideally in their own step + //Check if author information should be returned + if ($data['author_realname'] || $data['user_id'] || $data['author_email']) + { + + + if (!$this->canUserSeeAuthor(new Post($data), $this->form_repo, $user)) + { + unset($data['author_realname']); + unset($data['author_email']); + unset($data['user_id']); + } + } + return new Post($data); } @@ -142,12 +176,11 @@ protected function selectQuery(Array $where = []) protected function getPostValues($id) { + // Get all the values for the post. These are the EAV values. $values = $this->post_value_factory ->proxy($this->include_value_types) - ->getAllForPost($id, $this->include_attributes); - - + ->getAllForPost($id, $this->include_attributes, $this->exclude_stages, $this->restricted); $output = []; foreach ($values as $value) { @@ -163,11 +196,18 @@ protected function getPostValues($id) protected function getCompletedStagesForPost($id) { - $result = DB::select('form_stage_id', 'completed') + $query = DB::select('form_stage_id', 'completed') ->from('form_stages_posts') ->where('post_id', '=', $id) - ->where('completed', '=', 1) - ->execute($this->db); + ->where('completed', '=', 1); + + if ($this->restricted) { + if ($this->exclude_stages) { + $query->where('form_stage_id', 'NOT IN', $this->exclude_stages); + } + } + + $result = $query->execute($this->db); return $result->as_array(NULL, 'form_stage_id'); } @@ -181,10 +221,11 @@ public function getSearchFields() 'created_before', 'created_after', 'updated_before', 'updated_after', 'date_before', 'date_after', - 'bbox', 'tags', 'values', 'current_stage', + 'bbox', 'tags', 'values', 'center_point', 'within_km', 'published_to', 'include_types', 'include_attributes', // Specify values to include + 'include_unmapped', 'group_by', 'group_by_tags', 'group_by_attribute_key', // Group results 'timeline', 'timeline_interval', 'timeline_attribute', // Timeline params 'has_location' //contains a location or not @@ -220,7 +261,7 @@ protected function setSearchConditions(SearchData $search) $query = $this->search_query; $table = $this->getTable(); - + // Filter by status $status = $search->getFilter('status', ['published']); // @@ -324,7 +365,7 @@ protected function setSearchConditions(SearchData $search) // Convert to UTC (needed in case date came with a tz) $date_after->setTimezone(new DateTimeZone('UTC')); $query->where("$table.post_date", '>=', $date_after->format('Y-m-d H:i:s')); - } + } if ($search->date_before) { @@ -361,87 +402,19 @@ protected function setSearchConditions(SearchData $search) ; } + $raw_union = '(select post_geometry.post_id from post_geometry union select post_point.post_id from post_point)'; if($search->has_location === 'mapped') { - - $query - ->where("$table.id", 'IN', DB::select('post_id') - ->from('post_point')); + $query->where("$table.id", 'IN', + DB::query(Database::SELECT, $raw_union) + ); } else if($search->has_location === 'unmapped') { - $query - ->where("$table.id", 'NOT IN', DB::select('post_id') - ->from('post_point')); - } - - if ($search->current_stage) { - $stages = $search->current_stage; - if (!is_array($stages)) { - $stages = explode(',', $stages); - } - - /** - * Here be dragons - * The purpose of this query is to return the set of posts which - * have current stage X. In this case, current stage X is actually the - * the stage the post has NOT yet completed - which is the stage with. - * the lowest priority. - * For example: - * If I have 3 stages for a given Post Type, I am on stage 1 if - * I have completed no stages and I am on stage 3 if I have completed - * stages 1 and 2. - * If I have completed stages 1 and 3, I am on stage 2 as stages are considered - * to be sequential - */ - - /** - * This query is responsible for returning all the - * stages for a given post id, where the stage has been completed. - * This is used to check which stages the Post has not yet completed - */ - - $stages_posts = DB::select('form_stage_id') - ->from('form_stages_posts') - ->where('post_id', '=', DB::expr('posts.id')) - ->and_where('completed', '=', '1'); - - /** - * This query returns the IDs for the stages that we are filtering by - */ - $forms_sub = DB::select('form_stages.form_id') - ->from('form_stages') - ->where('form_stages.id', 'IN', $stages); - - /** - * This is the master query, it collects all the posts - * missing stages that we are filtering by. - */ - $sub = DB::select(array('posts.id','p_id'), array('form_stages.id', 'fs_id'), 'priority', 'posts.form_id', 'forms.id') - ->from('posts') - ->join('forms') - // Here we join to the forms table based on the set of stage ids we are filtering by - ->on('posts.form_id', '=', 'forms.id') - ->on('forms.id', 'IN', $forms_sub) - ->join('form_stages') - // Here we join to the form_stages table based on the form id - // and a check that the current post has not already completed this stage - ->on('form_stages.form_id', 'IN', $forms_sub) - ->on('form_stages.id', 'NOT IN', $stages_posts) - // We group the results by post id - ->group_by('p_id') - // We reduce the list to ensure that only results missing the stages to filter by are returned - ->having('form_stages.id', 'IN', $stages) - // Finally we order the results by priority to ensure that if, for example, - // a post is missing multiple stages we only consider the first uncompleted stage - ->order_by('priority'); - - //This step wraps the query and returns only the posts ids without the extra data such as form, stage or priority - $posts_sub = DB::select('p_id') - ->from(array($sub, 'sub')); - - $query - ->where('posts.id', 'IN', $posts_sub); + $query->where("$table.id", 'NOT IN', + DB::query(Database::SELECT, $raw_union) + ); } // Filter by tag + // @todo add filter by specific tag attribute? if (!empty($search->tags)) { if (isset($search->tags['any'])) @@ -528,7 +501,7 @@ protected function setSearchConditions(SearchData $search) ->where("$table.status", '=', 'published') ->or_where("$table.user_id", '=', $user->id) ->and_where_close(); - } + } } // SearchRepository @@ -536,13 +509,36 @@ public function getSearchTotal() { // Assume we can simply count the results to get a total $query = $this->getSearchQuery(true) + ->resetSelect() ->select([DB::expr('COUNT(DISTINCT posts.id)'), 'total']); // Fetch the result and... - $result = $query->execute($this->db); - + $results = $query->execute($this->db); // ... return the total. - return (int) $result->get('total', 0); + $total = 0; + + foreach ($results->as_array() as $result) { + $total += array_key_exists('total', $result) ? (int) $result['total'] : 0; + } + + return $total; + } + + public function getUnmappedTotal($total_posts) + { + + $mapped = 0; + $raw_sql = "select count(distinct post_id) as 'total' from (select post_geometry.post_id from post_geometry union select post_point.post_id from post_point) as sub;"; + if ($total_posts > 0) { + + $results = DB::query(Database::SELECT, $raw_sql)->execute($this->db); + + foreach($results->as_array() as $result) { + $mapped = array_key_exists('total', $result) ? (int) $result['total'] : 0; + } + } + + return $total_posts - $mapped; } // PostRepository @@ -609,6 +605,7 @@ public function getGroupedTotals(SearchData $search) 'time_label' ]) ->group_by('time_label'); + } // Group by attribute @@ -643,9 +640,10 @@ public function getGroupedTotals(SearchData $search) { $this->search_query ->join('forms', 'LEFT')->on('posts.form_id', '=', 'forms.id') - ->select(['forms.name', 'label']) + // This should really use ANY_VALUE(forms.name) but that only exists in mysql5.7 + ->select([DB::expr('MAX(forms.name)'), 'label']) ->select(['forms.id', 'id']) - ->group_by('posts.form_id'); + ->group_by('forms.id'); } // Group by tags elseif ($search->group_by === 'tags') @@ -671,7 +669,8 @@ public function getGroupedTotals(SearchData $search) ->join(['tags', 'parents']) // Slight hack to avoid kohana db forcing multiple ON clauses to use AND not OR. ->on(DB::expr("`parents`.`id` = `tags`.`parent_id` OR `parents`.`id` = `posts_tags`.`tag_id`"), '', DB::expr("")) - ->select(['parents.tag', 'label']) + // This should really use ANY_VALUE(forms.name) but that only exists in mysql5.7 + ->select([DB::expr('MAX(parents.tag)'), 'label']) ->select(['parents.id', 'id']) ->group_by('parents.id'); @@ -712,9 +711,13 @@ public function getGroupedTotals(SearchData $search) // Fetch the results and... $results = $this->search_query->execute($this->db); - + $results = $results->as_array(); + if ($search->include_unmapped) { + // Append unmapped totals to stats + $results['unmapped'] = $this->getUnmappedTotal($this->getSearchTotal()); + } // ... return them as an array - return $results->as_array(); + return $results; } // PostRepository @@ -797,10 +800,13 @@ private function getBoundingBoxSubquery(Util_BoundingBox $bounding_box) * @param int $id post id * @return array tag ids for post */ - private function getTagsForPost($id) + private function getTagsForPost($id, $form_id) { + list($attr_id, $attr_key) = $this->getFirstTagAttr($form_id); + $result = DB::select('tag_id')->from('posts_tags') ->where('post_id', '=', $id) + ->where('form_attribute_id', '=', $attr_id) ->execute($this->db); return $result->as_array(NULL, 'tag_id'); } @@ -870,16 +876,23 @@ public function create(Entity $entity) // Create the post $id = $this->executeInsert($this->removeNullValues($post)); + $values = $entity->values; + // Handle legacy post.tags attribute if ($entity->tags) { - // Update post-tags - $this->updatePostTags($id, $entity->tags); + // Find first tag attribute + list($attr_id, $attr_key) = $this->getFirstTagAttr($entity->form_id); + + // If we don't have tags in the values, use the post.tags value + if ($attr_key && !isset($values[$attr_key])) { + $values[$attr_key] = $entity->tags; + } } if ($entity->values) { // Update post-values - $this->updatePostValues($id, $entity->values); + $this->updatePostValues($id, $values); } if ($entity->completed_stages) @@ -912,16 +925,23 @@ public function update(Entity $entity) $count = $this->executeUpdate(['id' => $entity->id], $post); + $values = $entity->values; + // Handle legacy post.tags attribute if ($entity->hasChanged('tags')) { - // Update post-tags - $this->updatePostTags($entity->id, $entity->tags); + // Find first tag attribute + list($attr_id, $attr_key) = $this->getFirstTagAttr($entity->form_id); + + // If we don't have tags in the values, use the post.tags value + if ($attr_key && !isset($values[$attr_key])) { + $values[$attr_key] = $entity->tags; + } } if ($entity->hasChanged('values')) { // Update post-values - $this->updatePostValues($entity->id, $entity->values); + $this->updatePostValues($entity->id, $values); } if ($entity->hasChanged('completed_stages')) @@ -953,65 +973,18 @@ protected function updatePostValues($post_id, $attributes) } } - protected function updatePostTags($post_id, $tags) + public function getFirstTagAttr($form_id) { - // deletes all tags if $tags is empty - if (empty($tags)) - { - DB::delete('posts_tags') - ->where('post_id', '=', $post_id) - ->execute($this->db); - } - else - { - // Load existing tags - $existing = $this->getTagsForPost($post_id); - - $insert = DB::insert('posts_tags', ['post_id', 'tag_id']); - - $tag_ids = []; - $new_tags = FALSE; - - foreach ($tags as $tag) - { - if (is_array($tag)) { - $tag = $tag['id']; - } - - // Find the tag by id or name - // @todo this should happen before we even get here - $tag_entity = $this->tag_repo->getByTag($tag); - if (! $tag_entity->id) - { - $tag_entity = $this->tag_repo->get($tag); - } - - // Does the post already have this tag? - if (! in_array($tag_entity->id, $existing)) - { - // Add to insert query - $insert->values([$post_id, $tag_entity->id]); - $new_tags = TRUE; - } - - $tag_ids[] = $tag_entity->id; - } - - // Save - if ($new_tags) - { - $insert->execute($this->db); - } + $result = DB::select('form_attributes.id', 'form_attributes.key') + ->from('form_attributes') + ->join('form_stages', 'INNER')->on('form_stages.id', '=', 'form_attributes.form_stage_id') + ->where('form_stages.form_id', '=', $form_id) + ->where('form_attributes.type', '=', 'tags') + ->order_by('form_attributes.priority', 'ASC') + ->limit(1) + ->execute($this->db); - // Remove any other tags - if (! empty($tag_ids)) - { - DB::delete('posts_tags') - ->where('tag_id', 'NOT IN', $tag_ids) - ->and_where('post_id', '=', $post_id) - ->execute($this->db); - } - } + return [$result->get('id'), $result->get('key')]; } diff --git a/application/classes/Ushahidi/Repository/Post/Description.php b/application/classes/Ushahidi/Repository/Post/Description.php index 8e077c74c3..36d7633216 100644 --- a/application/classes/Ushahidi/Repository/Post/Description.php +++ b/application/classes/Ushahidi/Repository/Post/Description.php @@ -14,7 +14,7 @@ class Ushahidi_Repository_Post_Description extends Ushahidi_Repository_Post_Text { - public function getAllForPost($post_id, Array $include_attributes = []) + public function getAllForPost($post_id, Array $include_attributes = [], Array $exclude_stages = [], $restricted = false) { return []; } diff --git a/application/classes/Ushahidi/Repository/Post/Tags.php b/application/classes/Ushahidi/Repository/Post/Tags.php new file mode 100644 index 0000000000..3b5e3f3c7e --- /dev/null +++ b/application/classes/Ushahidi/Repository/Post/Tags.php @@ -0,0 +1,96 @@ + + * @package Ushahidi\Application + * @copyright 2014 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) + */ + +use Ushahidi\Core\Usecase\Post\UpdatePostTagRepository; + +class Ushahidi_Repository_Post_Tags extends Ushahidi_Repository_Post_Value +{ + protected $tag_repo; + + /** + * Construct + * @param Database $db + * @param TagRepo $tag_repo + */ + public function __construct( + Database $db, + UpdatePostTagRepository $tag_repo + ) + { + parent::__construct($db); + $this->tag_repo = $tag_repo; + } + + // Ushahidi_Repository + protected function getTable() + { + return 'posts_tags'; + } + + // Override selectQuery to fetch attribute 'key' too + protected function selectQuery(Array $where = []) + { + $query = parent::selectQuery($where); + + // Select 'tag_id' as value too + $query->select( + ['posts_tags.tag_id', 'value'] + ); + + return $query; + } + + // PostValueRepository + public function getValueQuery($form_attribute_id, $match) + { + return $this->selectQuery(compact('form_attribute_id')) + ->where('tag_id', 'LIKE', "%$match%"); + } + + // UpdatePostValueRepository + public function createValue($value, $form_attribute_id, $post_id) + { + $tag_id = $this->parseTag($value); + $input = compact('tag_id', 'form_attribute_id', 'post_id'); + $input['created'] = time(); + + return $this->executeInsert($input); + } + + // UpdatePostValueRepository + public function updateValue($id, $value) + { + $tag_id = $this->parseTag($value); + $update = compact($tag_id); + if ($id && $update) + { + $this->executeUpdate(compact('id'), $update); + } + } + + protected function parseTag($tag) + { + if (is_array($tag)) { + $tag = $tag['id']; + } + + // Find the tag by id or name + // @todo this should happen before we even get here + $tag_entity = $this->tag_repo->getByTag($tag); + if (! $tag_entity->id) + { + $tag_entity = $this->tag_repo->get($tag); + } + + return $tag_entity->id; + } + +} diff --git a/application/classes/Ushahidi/Repository/Post/Title.php b/application/classes/Ushahidi/Repository/Post/Title.php index 9e13a2fe34..e34c52a2af 100644 --- a/application/classes/Ushahidi/Repository/Post/Title.php +++ b/application/classes/Ushahidi/Repository/Post/Title.php @@ -14,7 +14,7 @@ class Ushahidi_Repository_Post_Title extends Ushahidi_Repository_Post_Varchar { - public function getAllForPost($post_id, Array $include_attributes = []) + public function getAllForPost($post_id, Array $include_attributes = [], Array $exclude_stages = [], $restricted = false) { return []; } diff --git a/application/classes/Ushahidi/Repository/Post/Value.php b/application/classes/Ushahidi/Repository/Post/Value.php index aac659efcc..b0e31bfacf 100644 --- a/application/classes/Ushahidi/Repository/Post/Value.php +++ b/application/classes/Ushahidi/Repository/Post/Value.php @@ -40,7 +40,9 @@ protected function selectQuery(Array $where = []) // Select 'key' too $query->select( $this->getTable().'.*', - 'form_attributes.key' + 'form_attributes.key', + 'form_attributes.form_stage_id', + 'form_attributes.response_private' ) ->join('form_attributes')->on('form_attribute_id', '=', 'form_attributes.id'); @@ -55,7 +57,7 @@ public function get($id, $post_id = null, $form_attribute_id = null) } // ValuesForPostRepository - public function getAllForPost($post_id, Array $include_attributes = []) + public function getAllForPost($post_id, Array $include_attributes = [], Array $exclude_stages = [], $restricted = false) { $query = $this->selectQuery(compact('post_id')); @@ -63,6 +65,13 @@ public function getAllForPost($post_id, Array $include_attributes = []) $query->where('form_attributes.key', 'IN', $include_attributes); } + if ($restricted) { + $query->where('form_attributes.response_private', '!=', '1'); + if ($exclude_stages) { + $query->where('form_attributes.form_stage_id', 'NOT IN', $exclude_stages); + } + } + $results = $query->execute($this->db); return $this->getCollection($results->as_array()); } diff --git a/application/classes/Ushahidi/Repository/Post/ValueProxy.php b/application/classes/Ushahidi/Repository/Post/ValueProxy.php index cafa242e95..b564a70ca6 100644 --- a/application/classes/Ushahidi/Repository/Post/ValueProxy.php +++ b/application/classes/Ushahidi/Repository/Post/ValueProxy.php @@ -23,12 +23,12 @@ public function __construct(Ushahidi_Repository_Post_ValueFactory $factory, Arra } // ValuesForPostRepository - public function getAllForPost($post_id, Array $include_attributes = []) + public function getAllForPost($post_id, Array $include_attributes = [], Array $exclude_stages = [], $restricted = false) { $results = []; - $this->factory->each(function ($repo) use ($post_id, $include_attributes, &$results) { - $results = array_merge($results, $repo->getAllForPost($post_id, $include_attributes)); + $this->factory->each(function ($repo) use ($post_id, $include_attributes, &$results, $exclude_stages, $restricted) { + $results = array_merge($results, $repo->getAllForPost($post_id, $include_attributes, $exclude_stages, $restricted)); }, $this->include_types); return $results; diff --git a/application/classes/Ushahidi/Repository/Tag.php b/application/classes/Ushahidi/Repository/Tag.php index bebf0ad70e..3c8a4593aa 100644 --- a/application/classes/Ushahidi/Repository/Tag.php +++ b/application/classes/Ushahidi/Repository/Tag.php @@ -12,6 +12,7 @@ use Ushahidi\Core\Entity; use Ushahidi\Core\SearchData; use Ushahidi\Core\Entity\Tag; +use Ushahidi\Core\Entity\TagRepository; use Ushahidi\Core\Usecase\Tag\UpdateTagRepository; use Ushahidi\Core\Usecase\Tag\DeleteTagRepository; use Ushahidi\Core\Usecase\Post\UpdatePostTagRepository; @@ -19,11 +20,13 @@ class Ushahidi_Repository_Tag extends Ushahidi_Repository implements UpdateTagRepository, DeleteTagRepository, - UpdatePostTagRepository + UpdatePostTagRepository, + TagRepository { // Use the JSON transcoder to encode properties use Ushahidi_JsonTranscodeRepository; - + // Use trait to for updating forms_tags-table + use Ushahidi_FormsTagsTrait; private $created_id; private $created_ts; @@ -39,6 +42,19 @@ protected function getTable() // ReadRepository public function getEntity(Array $data = null) { + if (!empty($data['id'])) + { + // If this is a top level category + if(empty($data['parent_id'])) { + // Load children + $data['children'] = DB::select('id') + ->from('tags') + ->where('parent_id','=',$data['id']) + ->execute($this->db) + ->as_array(null, 'id'); + } + } + return new Tag($data); } @@ -51,18 +67,17 @@ protected function getJsonProperties() // SearchRepository public function getSearchFields() { - return ['tag', 'type', 'parent_id', 'q', /* LIKE tag */]; + return ['tag', 'type', 'parent_id', 'q', 'level' /* LIKE tag */]; } // Ushahidi_Repository protected function setSearchConditions(SearchData $search) { $query = $this->search_query; - foreach (['tag', 'type', 'parent_id'] as $key) { if ($search->$key) { - $query->where($key, '=', $search->$key); + $query->where($key, '=', $search->$key); } } @@ -70,6 +85,21 @@ protected function setSearchConditions(SearchData $search) // Tag text searching $query->where('tag', 'LIKE', "%{$search->q}%"); } + + if($search->level) { + //searching for top-level-tags + if($search->level === 'parent') { + $query->where('parent_id', '=', null); + } + } + } + + // SearchRepository + public function getSearchResults() + { + $query = $this->getSearchQuery(); + $results = $query->distinct(TRUE)->execute($this->db); + return $this->getCollection($results->as_array()); } // CreateRepository @@ -77,9 +107,23 @@ public function create(Entity $entity) { $record = $entity->asArray(); $record['created'] = time(); - return $this->executeInsert($this->removeNullValues($record)); + + $id = $this->executeInsert($this->removeNullValues($record)); + + return $id; + } + + public function update(Entity $entity) + { + $tag = $entity->getChanged(); + // removing children before saving tag + unset($tag['children']); + $count = $this->executeUpdate(['id' => $entity->id], $tag); + + return $count; } + // UpdatePostTagRepository public function getByTag($tag) { @@ -90,6 +134,7 @@ public function getByTag($tag) public function doesTagExist($tag_or_id) { $query = $this->selectQuery() + ->resetSelect() ->select([DB::expr('COUNT(*)'), 'total']) ->where('id', '=', $tag_or_id) ->or_where('tag', '=', $tag_or_id) @@ -104,9 +149,22 @@ public function isSlugAvailable($slug) return $this->selectCount(compact('slug')) === 0; } + public function delete(Entity $entity) + { + // Remove tag from attribute options + $this->removeTagFromAttributeOptions($entity->id); + + return $this->executeDelete([ + 'id' => $entity->id + ]); + } + // DeleteTagRepository public function deleteTag($id) { + // Remove tag from attribute options + $this->removeTagFromAttributeOptions($entity->id); + return $this->delete(compact('id')); } } diff --git a/application/classes/Ushahidi/Repository/User.php b/application/classes/Ushahidi/Repository/User.php index 2469b7896a..a8e77c2e10 100644 --- a/application/classes/Ushahidi/Repository/User.php +++ b/application/classes/Ushahidi/Repository/User.php @@ -19,6 +19,9 @@ use Ushahidi\Core\Usecase\User\RegisterRepository; use Ushahidi\Core\Usecase\User\ResetPasswordRepository; +use League\Event\ListenerInterface; +use Ushahidi\Core\Traits\Event; + class Ushahidi_Repository_User extends Ushahidi_Repository implements UserRepository, RegisterRepository, @@ -29,6 +32,9 @@ class Ushahidi_Repository_User extends Ushahidi_Repository implements */ protected $hasher; + // Use Event trait to trigger events + use Event; + /** * @param Hasher $hasher * @return $this @@ -58,7 +64,6 @@ public function create(Entity $entity) 'created' => time(), 'password' => $this->hasher->hash($entity->password), ]; - return parent::create($entity->setState($state)); } @@ -133,6 +138,9 @@ public function isUniqueEmail($email) // RegisterRepository public function register(Entity $entity) { + + $this->updateIntercomUserCount(1); + return $this->executeInsert([ 'realname' => $entity->realname, 'email' => $entity->email, @@ -202,4 +210,25 @@ public function getTotalCount(Array $where = []) { return $this->selectCount($where); } + + // DeleteRepository + public function delete(Entity $entity) { + $this->updateIntercomUserCount(-1); + return parent::delete($entity); + } + + /** + * Pass User count to Intercom + * takes a postive/negative offset by which to increase/decrease count for create/delete + * @param Integer $offset + * @return void + */ + protected function updateIntercomUserCount($offset) + { + $data = [ + 'total_users' => $this->getTotalCount() + $offset + ]; + $user = service('session.user'); + $this->emit($this->event, $user->email, $data); + } } diff --git a/application/classes/Ushahidi/Signer/Signature.php b/application/classes/Ushahidi/Signer/Signature.php deleted file mode 100644 index 5936c8fc85..0000000000 --- a/application/classes/Ushahidi/Signer/Signature.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @package Ushahidi\Application - * @copyright 2014 Ushahidi - * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) - */ - -use Ushahidi\Core\Tool\Signer; - -class Ushahidi_Signer_Signature implements Signer -{ - protected $authToken; - - public function __construct($authToken) - { - $this->authToken = $authToken; - } - - public function sign($fullUrl, $data) - { - return computeSignature($fullUrl, $data); - } - - public function computeSignature($url, $data = array()) - { - // sort the array by keys - ksort($data); - // append them to the data string in order - // with no delimiters - foreach ($data as $key => $value) { - $url .= "$key$value"; - } - - // This function calculates the HMAC hash of the data with the key - // passed in - // Note: hash_hmac requires PHP 5 >= 5.1.2 or PECL hash:1.1-1.5 - // Or http://pear.php.net/package/Crypt_HMAC/ - return base64_encode(hash_hmac("sha256", $url, $this->authToken, true)); - } - - public function validate($expectedSignature, $url, $data = array()) - { - return self::compare( - $this->computeSignature($url, $data), - $expectedSignature - ); - } - /** - * Time insensitive compare, function's runtime is governed by the length - * of the first argument, not the difference between the arguments. - * @param $a string First part of the comparison pair - * @param $b string Second part of the comparison pair - * @return bool True if $a == $b, false otherwise. - */ - public static function compare($a, $b) - { - $result = true; - if (strlen($a) != strlen($b)) { - return false; - } - if (!$a && !$b) { - return true; - } - $limit = strlen($a); - for ($i = 0; $i < $limit; ++$i) { - if ($a[$i] != $b[$i]) { - $result = false; - } - } - return $result; - } -} diff --git a/application/classes/Ushahidi/Validator/Form/Attribute/Update.php b/application/classes/Ushahidi/Validator/Form/Attribute/Update.php index 8898612f6b..b5bc82c750 100644 --- a/application/classes/Ushahidi/Validator/Form/Attribute/Update.php +++ b/application/classes/Ushahidi/Validator/Form/Attribute/Update.php @@ -29,6 +29,8 @@ public function __construct(FormAttributeRepository $repo, FormStageRepository $ protected function getRules() { + $type = $this->validation_engine->getFullData('type'); + return [ 'key' => [ ['max_length', [':value', 150]], @@ -53,7 +55,8 @@ protected function getRules() 'relation', 'upload', 'video', - 'markdown' + 'markdown', + 'tags', ]]], ], 'type' => [ @@ -70,11 +73,12 @@ protected function getRules() 'relation', 'media', 'title', - 'description' + 'description', + 'tags', ]]], ], 'required' => [ - ['in_array', [':value', [true,false]]], + ['in_array', [':value', [true, false]]], ], 'priority' => [ ['digit'], @@ -90,10 +94,13 @@ protected function getRules() 'form_id' => [ ['digit'], ], + 'response_private' => [ + [[$this, 'canMakePrivate'], [':value', $type]] + ] ]; } - public function formStageBelongsToForm($value) + public function formStageBelongsToForm($value) { // don't check against nonexistant data if (!$value || !isset($this->valid['form_id'])) { @@ -103,4 +110,14 @@ public function formStageBelongsToForm($value) $group = $this->form_stage_repo->get($value); return ($group->form_id == $this->valid['form_id']); } + + public function canMakePrivate($value, $type) + { + // If input type is tags, then attribute cannot be private + if ($type === 'tags' && $value !== false) { + return false; + } + + return true; + } } diff --git a/application/classes/Ushahidi/Validator/Post/Create.php b/application/classes/Ushahidi/Validator/Post/Create.php index 82367d3ac8..de33b2d766 100644 --- a/application/classes/Ushahidi/Validator/Post/Create.php +++ b/application/classes/Ushahidi/Validator/Post/Create.php @@ -185,6 +185,10 @@ public function checkApprovalRequired (Validation $validation, $status, $fullDat return; } + if ($status === 'draft' && !isset($fullData['id'])) { + return; + } + $user = $this->getUser(); // Do we have permission to publish this post? $userCanChangeStatus = ($this->isUserAdmin($user) or $this->hasPermission($user)); diff --git a/application/classes/Ushahidi/Validator/Post/Markdown.php b/application/classes/Ushahidi/Validator/Post/Markdown.php index 20071cbbd8..68e91bbb00 100644 --- a/application/classes/Ushahidi/Validator/Post/Markdown.php +++ b/application/classes/Ushahidi/Validator/Post/Markdown.php @@ -16,8 +16,5 @@ protected function validate($value) if (!is_scalar($value)) { return 'scalar'; } - if (!Valid::max_length($value, 255)) { - return 'max_length'; - } } } diff --git a/application/classes/Ushahidi/Validator/Post/Tags.php b/application/classes/Ushahidi/Validator/Post/Tags.php new file mode 100644 index 0000000000..f83fc0ddbb --- /dev/null +++ b/application/classes/Ushahidi/Validator/Post/Tags.php @@ -0,0 +1,33 @@ + + * @package Ushahidi\Application + * @copyright 2014 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) + */ + +use Ushahidi\Core\Entity\TagRepository; + +class Ushahidi_Validator_Post_Tags extends Ushahidi_Validator_Post_ValueValidator +{ + protected $repo; + + public function __construct(TagRepository $tags_repo) + { + $this->repo = $tags_repo; + } + + protected function validate($value) + { + if (is_array($value)) { + $value = $value['id']; + } + + if (!$this->repo->doesTagExist($value)) { + return 'tagExists'; + } + } +} diff --git a/application/config/map.php b/application/config/map.php index aa04f40839..47b1a5f314 100644 --- a/application/config/map.php +++ b/application/config/map.php @@ -11,7 +11,7 @@ return array( // Enable marker clustering with leaflet.markercluster - 'clustering' => FALSE, + 'clustering' => TRUE, 'cluster_radius' => 50, // Map start location 'default_view' => array( diff --git a/application/config/site.php b/application/config/site.php index cd2e1cdfba..f4de51aa9a 100644 --- a/application/config/site.php +++ b/application/config/site.php @@ -1,4 +1,4 @@ -getHost()->toUnicode(); @@ -33,14 +36,15 @@ } return array( - 'name' => '', - 'description' => '', - 'email' => '', - 'timezone' => 'UTC', - 'language' => 'en-US', - 'date_format' => 'n/j/Y', - 'client_url' => $clientUrl ?: false, - 'first_login' => true, - 'tier' => 'free', - 'private' => false, + 'name' => '', + 'description' => '', + 'email' => '', + 'timezone' => 'UTC', + 'language' => 'en-US', + 'date_format' => 'n/j/Y', + 'client_url' => $clientUrl ?: false, + 'first_login' => true, + 'tier' => 'free', + 'private' => false, + 'intercomAppToken' => $intercomAppToken, ); diff --git a/application/kohana.php b/application/kohana.php index 920c4dc628..6818534d34 100644 --- a/application/kohana.php +++ b/application/kohana.php @@ -101,7 +101,11 @@ // Load dotenv if (is_file(APPPATH.'../.env')) { - Dotenv::load(APPPATH.'../'); + try { + (new Dotenv\Dotenv(APPPATH.'/../'))->load(); + } catch (Dotenv\Exception\InvalidPathException $e) { + // + } } // Bootstrap the application diff --git a/application/messages/post.php b/application/messages/post.php index 88428126b5..8a649ebd21 100644 --- a/application/messages/post.php +++ b/application/messages/post.php @@ -2,7 +2,7 @@ return [ 'publishedPostsLimitReached' => 'limit::posts', - 'tagDoesNotExist' => 'tag :value does not exist', + 'tagDoesNotExist' => 'category :value does not exist', 'attributeDoesNotExist' => 'attribute ":param1" does not exist', 'tooManyValues' => 'Too many values for :param1 (max: :param2)', 'valueDoesNotExist' => 'value id :param2 for field :param1 does not exist', @@ -27,6 +27,7 @@ 'digit' => 'The field :param1 must be a digit, Given: :param2', 'email' => 'The field :param1 must be an email address, Given: :param2', 'exists' => 'The field :param1 must be a valid post id, Post id: :param2', + 'tagExists' => 'The field :param1 must be a valid category id or name, Category: :param2', 'max_length' => 'The field :param1 must not exceed :param2 characters long, Given: :param2', 'invalidForm' => 'The field :param1 has the wrong post type, Post id: :param2', 'numeric' => 'The field :param1 must be numeric, Given: :param2', diff --git a/application/tests/features/bootstrap/FeatureContext.php b/application/tests/features/bootstrap/FeatureContext.php deleted file mode 100644 index 787b7400f6..0000000000 --- a/application/tests/features/bootstrap/FeatureContext.php +++ /dev/null @@ -1,163 +0,0 @@ - - * @package Ushahidi\Application\Tests - * @copyright 2013 Ushahidi - * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) - */ - -// Load bootstrap to hook into Kohana -require_once __DIR__.'/../../bootstrap.php'; - -use Behat\Behat\Context\ClosuredContextInterface, - Behat\Behat\Context\TranslatedContextInterface, - Behat\Behat\Context\BehatContext, - Behat\Behat\Exception\PendingException; -use Behat\Gherkin\Node\PyStringNode, - Behat\Gherkin\Node\TableNode; -use Behat\Behat\Event\FeatureEvent; - -/** - * Features context. - */ -class FeatureContext extends BehatContext -{ - /** - * Initializes context. - * Every scenario gets it's own context object. - * - * @param array $parameters context parameters (set them up through behat.yml) - */ - public function __construct(array $parameters) - { - // Initialize your context here - $this->useContext('RestContext', new RestContext($parameters)); - $this->useContext('PHPUnitFixtureContext', new PHPUnitFixtureContext($parameters)); - $this->useContext('MinkContext', $minkContext = new MinkExtendedContext); - } - - /** @BeforeFeature */ - public static function featureSetup(FeatureEvent $event) - { - $fixtureContext = new PHPUnitFixtureContext($event->getParameters()); - $fixtureContext->setUpDBTester('ushahidi/Base'); - - $pdo_connection = $fixtureContext->getConnection()->getConnection(); - self::insertGeometryFixtures($pdo_connection); - } - - /** @AfterFeature */ - public static function featureTearDown(FeatureEvent $event) - { - $fixtureContext = new PHPUnitFixtureContext($event->getParameters()); - $fixtureContext->tearDownDBTester('ushahidi/Base'); - } - - /** @BeforeScenario @resetFixture */ - public function scenarioSetup() - { - $this->getSubcontext('PHPUnitFixtureContext')->setUpDBTester('ushahidi/Base'); - - $pdo_connection = $this->getSubcontext('PHPUnitFixtureContext')->getConnection()->getConnection(); - self::insertGeometryFixtures($pdo_connection); - } - - /** @BeforeScenario @private */ - public function makePrivate() - { - $config = Kohana::$config->load('site'); - $config->set('private', true); - - $config = Kohana::$config->load('features'); - $config->set('private.enabled', true); - } - - /** @AfterScenario @private */ - public function makePublic() - { - $config = Kohana::$config->load('site'); - $config->set('private', false); - - $config = Kohana::$config->load('features'); - $config->set('private.enabled', false); - } - - /** @BeforeScenario @rolesEnabled */ - public function enableRoles() - { - $config = Kohana::$config->load('features'); - $config->set('roles.enabled', true); - } - - /** @AfterScenario @rolesEnabled */ - public function disableRoles() - { - $config = Kohana::$config->load('features'); - $config->set('roles.enabled', false); - } - - /** @BeforeScenario @webhooksEnabled */ - public function enableWebhooks() - { - $config = Kohana::$config->load('features'); - $config->set('webhooks.enabled', true); - } - - /** @AfterScenario @webhooksEnabled */ - public function disableWebhooks() - { - $config = Kohana::$config->load('features'); - $config->set('webhooks.enabled', false); - } - - /** @BeforeScenario @dataImportEnabled */ - public function enableDataImport() - { - $config = Kohana::$config->load('features'); - $config->set('data-import.enabled', true); - } - - /** @AfterScenario @dataImportEnabled */ - public function disableDataImport() - { - $config = Kohana::$config->load('features'); - $config->set('data-import.enabled', false); - } - - protected static function insertGeometryFixtures($pdo_connection) - { - $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) - VALUES (1, 1, 8, POINT(12.123, 21.213));"); - $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) - VALUES (7, 1, 8, POINT(12.223, 21.313));"); - $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) - VALUES (2, 99, 8, POINT(11.123, 24.213));"); - $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) - VALUES (3, 9999, 8, POINT(10.123, 26.213));"); - $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) - VALUES (4, 95, 8, POINT(1, 1));"); - $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) - VALUES (5, 95, 12, POINT(1.2, 0.5));"); - $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) - VALUES (6, 97, 8, POINT(1, 1));"); - - $pdo_connection->query("INSERT INTO `post_geometry` (`id`, `post_id`, `form_attribute_id`, `value`) - VALUES (1, 1, 9, - GeomFromText('MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), - ((20 35, 45 20, 30 5, 10 10, 10 30, 20 35), - (30 20, 20 25, 20 15, 30 20)))'));"); - } - - /** - * Automatically set bearer token so you can forget about it - * @BeforeScenario @oauth2Skip - */ - public function setDefaultBearerAuth() - { - $this->getSubcontext('RestContext')->thatTheRequestHeaderIs('Authorization', 'Bearer defaulttoken'); - } - -} diff --git a/application/tests/features/bootstrap/PHPUnitFixtureContext.php b/application/tests/features/bootstrap/PHPUnitFixtureContext.php deleted file mode 100644 index a37a791ae0..0000000000 --- a/application/tests/features/bootstrap/PHPUnitFixtureContext.php +++ /dev/null @@ -1,153 +0,0 @@ -load('database.'.$this->_database_connection); - - if($config['type'] !== 'pdo') - { - // Replace MySQLi with MySQL since MySQLi isn't valid for a DSN - $type = $config['type'] === 'MySQLi' ? 'MySQL' : $config['type']; - - $config['connection']['dsn'] = strtolower($type).':'. - 'host='.$config['connection']['hostname'].';'. - 'dbname='.$config['connection']['database']; - } - - $pdo = new PDO( - $config['connection']['dsn'], - $config['connection']['username'], - $config['connection']['password'] - ); - - return $this->createDefaultDBConnection($pdo, $config['connection']['database']); - } - - /** - * Returns the test dataset. - * - * @param string|array $dataset Dataset filename - * @return PHPUnit_Extensions_Database_DataSet_IDataSet - */ - protected function getDataSet($dataset) - { - $file = Kohana::find_file('tests/datasets', $dataset , 'yml'); - - return new PHPUnit_Extensions_Database_DataSet_YamlDataSet( - $file - ); - } - - - - /** Call this in a BeforeScenario hook */ - public function setUpDBTester($dataset) - { - $this->_databaseTester = NULL; - - $this->getDatabaseTester()->setSetUpOperation($this->getSetUpOperation()); - $this->getDatabaseTester()->setDataSet($this->getDataSet($dataset)); - $this->getDatabaseTester()->onSetUp(); - } - - /** Call this in an AfterScenario hook */ - public function tearDownDBTester($dataset) - { - $this->getDatabaseTester()->setTearDownOperation($this->getTearDownOperation()); - $this->getDatabaseTester()->setDataSet($this->getDataSet($dataset)); - $this->getDatabaseTester()->onTearDown(); - - /** - * Destroy the tester after the test is run to keep DB connections - * from piling up. - */ - $this->_databaseTester = NULL; - } - - /** - * Gets the IDatabaseTester for this testCase. If the IDatabaseTester is - * not set yet, this method calls newDatabaseTester() to obtain a new - * instance. - * - * @return PHPUnit_Extensions_Database_ITester - */ - protected function getDatabaseTester() - { - if (empty($this->_databaseTester)) - { - $this->_databaseTester = $this->newDatabaseTester(); - } - return $this->_databaseTester; - } - - /** - * Creates a IDatabaseTester for this testCase. - * - * @return PHPUnit_Extensions_Database_ITester - */ - protected function newDatabaseTester() - { - return new PHPUnit_Extensions_Database_DefaultTester($this->getConnection()); - } - - /** - * Returns the database operation executed in test setup. - * Overriding to fix Mysql 5.5 truncate errors - * - * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation - */ - protected function getSetUpOperation() - { - //return PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT(); - $cascadeTruncates = TRUE; - return new PHPUnit_Extensions_Database_Operation_Composite(array( - new Unittest_Database_Operation_MySQL55Truncate($cascadeTruncates), - PHPUnit_Extensions_Database_Operation_Factory::INSERT() - )); - } - - /** - * Returns the database operation executed in test cleanup. - * - * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation - */ - protected function getTearDownOperation() - { - return PHPUnit_Extensions_Database_Operation_Factory::NONE(); - } - - /** - * Creates a new DefaultDatabaseConnection using the given PDO connection - * and database schema name. - * - * @param PDO $connection - * @param string $schema - * @return PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection - */ - protected function createDefaultDBConnection(PDO $connection, $schema = '') - { - return new PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection($connection, $schema); - } - -} diff --git a/application/tests/features/bootstrap/RestContext.php b/application/tests/features/bootstrap/RestContext.php deleted file mode 100644 index 753a9f9664..0000000000 --- a/application/tests/features/bootstrap/RestContext.php +++ /dev/null @@ -1,638 +0,0 @@ - - * @package Ushahidi\Application\Tests - * @copyright 2013 Ushahidi - * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) - */ - -use Behat\Behat\Context\BehatContext; -use Symfony\Component\Yaml\Yaml; - -/** - * Rest context. - */ -class RestContext extends BehatContext -{ - - private $_restObject = null; - private $_restObjectType = null; - private $_restObjectMethod = 'get'; - private $_client = null; - private $_response = null; - private $_requestUrl = null; - private $_apiUrl = 'api/v3'; - - private $_parameters = array(); - private $_headers = array(); - private $_postFields = array(); - private $_postFiles = array(); - - /** - * Initializes context. - * Every scenario gets it's own context object. - */ - public function __construct(array $parameters) - { - $this->_restObject = new stdClass(); - $this->_parameters = $parameters; - - $base_url = $this->getParameter('base_url'); - $proxy_url = $this->getParameter('proxy_url'); - - $options = array(); - if($proxy_url) - { - $options['curl.options'] = array(CURLOPT_PROXY => $proxy_url); - } - - $this->_client = new Guzzle\Service\Client($base_url, $options); - } - - public function getParameter($name) - { - if (count($this->_parameters) === 0) { - - - throw new \Exception('Parameters not loaded!'); - } else { - - $parameters = $this->_parameters; - return (isset($parameters[$name])) ? $parameters[$name] : null; - } - } - - /** - * @Given /^that I want to make a new "([^"]*)"$/ - */ - public function thatIWantToMakeANew($objectType) - { - // Reset _restObject - $this->_restObject = new stdClass(); - - $this->_restObjectType = ucwords(strtolower($objectType)); - $this->_restObjectMethod = 'post'; - } - - /** - * @Given /^that I want to import a "([^"]*)"$/ - */ - public function thatIWantToImportA($objectType) - { - // Reset _restObject - $this->_restObject = new stdClass(); - - $this->_restObjectType = ucwords(strtolower($objectType)); - $this->_restObjectMethod = 'post'; - } - - - /** - * @Given /^that I want to submit a new "([^"]*)"$/ - */ - public function thatIWantToSubmitANew($objectType) - { - // Reset _restObject - $this->_restObject = new stdClass(); - - $this->_restObjectType = ucwords(strtolower($objectType)); - $this->_restObjectMethod = 'post'; - } - - /** - * @Given /^that I want to update a "([^"]*)"$/ - * @Given /^that I want to update an "([^"]*)"$/ - */ - public function thatIWantToUpdateA($objectType) - { - // Reset _restObject - $this->_restObject = new stdClass(); - - $this->_restObjectType = ucwords(strtolower($objectType)); - $this->_restObjectMethod = 'put'; - } - - /** - * @Given /^that I want to find a "([^"]*)"$/ - * @Given /^that I want to find an "([^"]*)"$/ - */ - public function thatIWantToFindA($objectType) - { - // Reset _restObject - $this->_restObject = new stdClass(); - - $this->_restObjectType = ucwords(strtolower($objectType)); - $this->_restObjectMethod = 'get'; - } - - /** - * @Given /^that I want to get all "([^"]*)"$/ - */ - public function thatIWantToGetAll($objectType) - { - // Reset _restObject - $this->_restObject = new stdClass(); - - $this->_restObjectType = ucwords(strtolower($objectType)); - $this->_restObjectMethod = 'get'; - } - - /** - * @Given /^that I want to delete a "([^"]*)"$/ - * @Given /^that I want to delete an "([^"]*)"$/ - */ - public function thatIWantToDeleteA($objectType) - { - // Reset _restObject - $this->_restObject = new stdClass(); - - $this->_restObjectType = ucwords(strtolower($objectType)); - $this->_restObjectMethod = 'delete'; - } - - /** - * @Given /^that the request "([^"]*)" is:$/ - * @Given /^that the request "([^"]*)" is "([^"]*)"$/ - * @Given /^that its "([^"]*)" is "([^"]*)"$/ - */ - public function thatTheRequestPropertyIs($propertyName, $propertyValue) - { - $this->_restObject->$propertyName = $propertyValue; - } - - /** - * @Given /^that the request "([^"]*)" header is:$/ - * @Given /^that the request "([^"]*)" header is "([^"]*)"$/ - */ - public function thatTheRequestHeaderIs($headerName, $headerValue) - { - $this->_headers[$headerName] = $headerValue; - } - - /** - * @Given /^that the response "([^"]*)" header is "([^"]*)"$/ - */ - public function thatTheResponseHeaderIs($headerName, $headerValue) - { - $this->_headers[$headerName] = $headerValue; - } - - /** - * @Given /^that the post field "([^"]*)" is:$/ - * @Given /^that the post field "([^"]*)" is "([^"]*)"$/ - */ - public function thatThePostFieldIs($fieldName, $fieldValue) - { - $this->_postFields[$fieldName] = $fieldValue; - } - - /** - * @Given /^that the post file "([^"]*)" is:$/ - * @Given /^that the post file "([^"]*)" is "([^"]*)"$/ - */ - public function thatThePostFileIs($fieldName, $fieldValue) - { - $this->_postFiles[$fieldName] = $fieldValue; - } - - /** - * @When /^I request "([^"]*)"$/ - */ - public function iRequest($pageUrl) - { - $this->_requestUrl = $this->_apiUrl.$pageUrl; - - switch (strtoupper($this->_restObjectMethod)) { - case 'GET': - $request = (array)$this->_restObject; - $id = ( isset($request['id']) ) ? $request['id'] : ''; - $http_request = $this->_client - ->get($this->_requestUrl.'/'.$id); - - if (isset($request['query string'])) - { - $url = $http_request->getUrl(TRUE); - $url->setQuery((string) trim($request['query string'])); - $http_request->setUrl($url); - } - break; - case 'POST': - $request = (array)$this->_restObject; - // If post fields or files are set assume this is a 'normal' POST request - if ($this->_postFields OR $this->_postFiles) - { - $http_request = $this->_client - ->post($this->_requestUrl) - ->addPostFields($this->_postFields) - ->addPostFiles($this->_preparePostFileData($this->_postFiles)); - } - // Otherwise assume we have JSON - else - { - $http_request = $this->_client - ->post($this->_requestUrl) - ->setBody($request['data']); - } - break; - case 'PUT': - $request = (array)$this->_restObject; - $id = ( isset($request['id']) ) ? $request['id'] : ''; - $http_request = $this->_client - ->put($this->_requestUrl.'/'.$id) - ->setBody($request['data']); - break; - case 'DELETE': - $request = (array)$this->_restObject; - $id = ( isset($request['id']) ) ? $request['id'] : ''; - $http_request = $this->_client - ->delete($this->_requestUrl.'/'.$id); - break; - } - - try { - $http_request - ->addHeaders($this->_headers) - ->send(); - } catch (Guzzle\Http\Exception\BadResponseException $e) { - // Don't care. - // 4xx and 5xx statuses are valid error responses - } - - // Get response object - $this->_response = $http_request->getResponse(); - - // Create fake response object if Guzzle doesn't give us one - if (! $this->_response instanceof Guzzle\Http\Message\Response) - { - $this->_response = new Guzzle\Http\Message\Response(null, null, null); - } - } - - /** - * @Then /^the response is JSON$/ - */ - public function theResponseIsJson() - { - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - // Check for NULL not empty - since [] and {} will be empty but valid - if ($data === NULL) { - - // Get further error info - switch (json_last_error()) { - case JSON_ERROR_NONE: - $error = 'No errors'; - break; - case JSON_ERROR_DEPTH: - $error = 'Maximum stack depth exceeded'; - break; - case JSON_ERROR_STATE_MISMATCH: - $error = 'Underflow or the modes mismatch'; - break; - case JSON_ERROR_CTRL_CHAR: - $error = 'Unexpected control character found'; - break; - case JSON_ERROR_SYNTAX: - $error = 'Syntax error, malformed JSON'; - break; - case JSON_ERROR_UTF8: - $error = 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; - default: - $error = 'Unknown error'; - break; - } - - throw new Exception("Response was not JSON\nBody:" . $this->_response->getBody(TRUE) . "\nError: " . $error ); - } - } - - /** - * @Then /^the response is JSONP$/ - */ - public function theResponseIsJsonp() - { - $result = preg_match('/^.+\(({.+})\)$/', $this->_response->getBody(TRUE), $matches); - - if ($result != 1 OR empty($matches[1])) - { - throw new Exception("Response was not JSONP\nBody:" . $this->_response->getBody(TRUE)); - } - - $data = json_decode($matches[1]); - - // Check for NULL not empty - since [] and {} will be empty but valid - if ($data === NULL) { - // Get further error info - switch (json_last_error()) { - case JSON_ERROR_NONE: - $error = 'No errors'; - break; - case JSON_ERROR_DEPTH: - $error = 'Maximum stack depth exceeded'; - break; - case JSON_ERROR_STATE_MISMATCH: - $error = 'Underflow or the modes mismatch'; - break; - case JSON_ERROR_CTRL_CHAR: - $error = 'Unexpected control character found'; - break; - case JSON_ERROR_SYNTAX: - $error = 'Syntax error, malformed JSON'; - break; - case JSON_ERROR_UTF8: - $error = 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; - default: - $error = 'Unknown error'; - break; - } - - throw new Exception("Response was not JSONP\nBody:" . $this->_response->getBody(TRUE) . "\nError: " . $error ); - } - } - - /** - * @Given /^the response has a "([^"]*)" property$/ - * @Given /^the response has an "([^"]*)" property$/ - */ - public function theResponseHasAProperty($propertyName) - { - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - if (Arr::path($data, $propertyName) === NULL) { - throw new Exception("Property '".$propertyName."' is not set!\n"); - } - } - - /** - * @Given /^the response does not have a "([^"]*)" property$/ - * @Given /^the response does not have an "([^"]*)" property$/ - */ - public function theResponseDoesNotHaveAProperty($propertyName) - { - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - if (Arr::path($data, $propertyName) !== NULL) { - throw new Exception("Property '".$propertyName."' is set but should not be!\n"); - } - } - - /** - * @Then /^the "([^"]*)" property equals "([^"]*)"$/ - */ - public function thePropertyEquals($propertyName, $propertyValue) - { - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - $actualPropertyValue = Arr::path($data, $propertyName); - - if ($actualPropertyValue === NULL) { - throw new Exception("Property '".$propertyName."' is not set!\n"); - } - // Check the value - note this has to use != since $propertValue is always a string so strict comparison would fail. - if ($actualPropertyValue != $propertyValue) { - throw new \Exception('Property value mismatch on \''.$propertyName.'\'! (given: '.$propertyValue.', match: '.$actualPropertyValue.')'); - } - } - - /** - * @Then /^the "([^"]*)" property is true$/ - */ - public function thePropertyIsTrue($propertyName) - { - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - $actualPropertyValue = Arr::path($data, $propertyName); - - if ($actualPropertyValue === NULL) { - throw new Exception("Property '".$propertyName."' is not set!\n"); - } - if ($actualPropertyValue !== TRUE) { - throw new \Exception('Property \''.$propertyName.'\' is not true! (match: '.$actualPropertyValue.')'); - } - } - - /** - * @Then /^the "([^"]*)" property is false$/ - */ - public function thePropertyIsFalse($propertyName) - { - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - $actualPropertyValue = Arr::path($data, $propertyName); - - if ($actualPropertyValue === NULL) { - throw new Exception("Property '".$propertyName."' is not set!\n"); - } - if ($actualPropertyValue !== FALSE) { - throw new \Exception('Property \''.$propertyName.'\' is not false! (match: '.$actualPropertyValue.')'); - } - } - - /** - * @Given /^the "([^"]*)" property contains "([^"]*)"$/ - */ - public function thePropertyContains($propertyName, $propertyContainsValue) - { - - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - $actualPropertyValue = Arr::path($data, $propertyName); - - if ($actualPropertyValue === NULL) { - throw new Exception("Property '".$propertyName."' is not set!\n"); - } - - if (is_array($actualPropertyValue) AND ! in_array($propertyContainsValue, $actualPropertyValue)) { - throw new \Exception('Property \''.$propertyName.'\' does not contain value! (given: '.$propertyContainsValue.', match: '.json_encode($actualPropertyValue).')'); - } - elseif (is_string($actualPropertyValue) AND strpos($actualPropertyValue, $propertyContainsValue) === FALSE) - { - throw new \Exception('Property \''.$propertyName.'\' does not contain value! (given: '.$propertyContainsValue.', match: '.$actualPropertyValue.')'); - } - elseif (!is_array($actualPropertyValue) AND !is_string($actualPropertyValue)) - { - throw new \Exception("Property '".$propertyName."' could not be compared. Must be string or array.\n"); - } - } - - /** - * @Given /^the "([^"]*)" property count is "([^"]*)"$/ - */ - public function thePropertyCountIs($propertyName, $propertyCountValue) - { - - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - $actualPropertyValue = Arr::path($data, $propertyName); - - if ($actualPropertyValue === NULL) { - throw new Exception("Property '".$propertyName."' is not set!\n"); - } - - if (is_array($actualPropertyValue) AND count($actualPropertyValue) != $propertyCountValue) { - throw new \Exception('Property \''.$propertyName.'\' count does not match! (given: '.$propertyCountValue.', match: '.count($actualPropertyValue).')'); - } - elseif (!is_array($actualPropertyValue)) - { - throw new \Exception("Property '".$propertyName."' could not be compared. Must be an array.\n"); - } - } - - /** - * @Given /^the type of the "([^"]*)" property is "([^"]*)"$/ - */ - public function theTypeOfThePropertyIs($propertyName, $typeString) - { - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - $actualPropertyValue = Arr::path($data, $propertyName); - - if ($actualPropertyValue === NULL) { - throw new Exception("Property '".$propertyName."' is not set!\n"); - } - // check our type - switch (strtolower($typeString)) { - case 'numeric': - if (!is_numeric($actualPropertyValue)) { - throw new Exception("Property '".$propertyName."' is not of the correct type: ".$typeString."!\n"); - } - break; - } - } - - /** - * @Then /^the "([^"]*)" property is empty$/ - */ - public function thePropertyIsEmpty($propertyName) - { - $data = json_decode($this->_response->getBody(TRUE), TRUE); - - $this->theResponseIsJson(); - - $actualPropertyValue = Arr::path($data, $propertyName); - - if (!empty($actualPropertyValue)) { - throw new Exception("Property '{$propertyName}' is not empty!\n"); - } - } - - /** - * @Then /^the guzzle status code should be (\d+)$/ - */ - public function theRestResponseStatusCodeShouldBe($httpStatus) - { - if ((string)$this->_response->getStatusCode() !== $httpStatus) { - throw new \Exception('HTTP code does not match '.$httpStatus. - ' (actual: '.$this->_response->getStatusCode().')'); - } - } - - /** - * @Then /^the "([^"]*)" header should exist$/ - */ - public function theRestHeaderShouldExist($header) - { - if (!$this->_response->hasHeader($header)) { - throw new \Exception('HTTP header does not exist '.$header ); - } - } - - /** - * @Then /^the the ([^"]*)" header should be "([^"]*)"$/ - */ - public function theRestHeaderShouldExistBe($header, $contents) - { - if ((string)$this->_response->getHeader($header) !== $contents) { - throw new \Exception('HTTP header ' . $header . ' does not match '.$contents. - ' (actual: '.$this->_response->getHeader($header).')'); - } - } - - - /** - * @Then /^echo last response$/ - */ - public function echoLastResponse() - { - $this->printDebug( - $this->_requestUrl."\n\n". - $this->_response - ); - } - - /** - * @Given /^that the api_url is "([^"]*)"$/ - */ - public function thatTheApiUrlIs($api_url) - { - $this->_apiUrl = $api_url; - } - - /** - * @AfterScenario - */ - public function afterScenarioCheckError(Behat\Behat\Event\ScenarioEvent $event) - { - // If scenario failed, dump response - if ($event->getResult() == 4 AND $this->_response) - { - $this->echoLastResponse(); - } - } - - private function _preparePostFileData($postFiles) - { - //Check if post files is not empty - if ( count($postFiles) > 0) - { - array_walk_recursive($postFiles, array($this, '_prefix_app_path')); - return $postFiles; - } - return $postFiles; - } - - /** - * Make the path to upload files to, relative to the application directory - * - * @param string $item the path to the file to be uploaded - * @return string path to application folder - */ - private function _prefix_app_path(&$item) - { - $item = APPPATH.$item; - } - - /** - * @Given /^that I want to count all "([^"]*)"$/ - */ - public function thatIWantToCountAll($objectType) - { - // Reset _restObject - $this->_restObject = new stdClass(); - - $this->_restObjectType = ucwords(strtolower($objectType)); - $this->_restObjectMethod = 'get'; - } - -} diff --git a/behat.yml.dist b/behat.yml.dist index 768aa19e68..4c118246e2 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -2,25 +2,34 @@ ## Replace base_url values with the url of your dev site ## default: - paths: - features: application/tests/features - bootstrap: application/tests/features/bootstrap - formatter: - name: progress - filters: - tags: "~@dataproviders" - context: - parameters: - base_url: http://localhost:8000 -# proxy_url: localhost:8888 - extensions: - Behat\MinkExtension\Extension: - base_url: http://localhost:8000 - goutte: - guzzle_parameters: - curl.options: - 3 : 8000 #CURLOPT_PORT=3 -# 10004: localhost:8888 #CURLOPT_PROXY=10004 + formatters: + progress: true + suites: + default: + paths: + - %paths.base%/tests/integration + contexts: + - Tests\Integration\Bootstrap\KohanaContext + - Tests\Integration\Bootstrap\FeatureContext + - Tests\Integration\Bootstrap\RestContext: + baseUrl: http://localhost:8000 + # proxyUrl: localhost:8888 + - Tests\Integration\Bootstrap\PHPUnitFixtureContext + - Tests\Integration\Bootstrap\MinkExtendedContext + filters: + tags: ~@dataproviders + extensions: + Behat\MinkExtension: + base_url: http://localhost:8000 + sessions: + default: + goutte: ~ + goutte: + guzzle_parameters: + curl.options: + 3 : 8000 #CURLOPT_PORT=3 + # 10004: localhost:8888 #CURLOPT_PROXY=10004 ci: - filters: - tags: + suites: + default: + filters: ~ diff --git a/bin/tests b/bin/tests deleted file mode 100755 index bec1be5063..0000000000 --- a/bin/tests +++ /dev/null @@ -1,297 +0,0 @@ -#!/usr/bin/env php - 'testing', - 'DB_TYPE' => 'MySQLi', - 'DB_HOST' => '127.0.0.1', - 'DB_NAME' => 'platform_test', - 'DB_PASS' => '', - 'DB_USER' => 'root' - ]; - - public function __construct() - { - parent::__construct(); - $this->dir = realpath(__DIR__ . '/../'); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $this->input = $input; - $this->output = $output; - $this->addOutputFormatting(); - } - - protected function install() - { - // change permissions - foreach ([ - "{$this->dir}/application/cache", - "{$this->dir}/application/logs", - ] as $file) { - chmod($file, 0777); - } - - // configure mysql, set up testing databases - $this->output->writeln("Configuring databases"); - $this->mysqlCommand('SET GLOBAL sql_mode = "STRICT_ALL_TABLES"'); - $this->mysqlCommand('DROP DATABASE IF EXISTS platform_test'); - $this->mysqlCommand('CREATE DATABASE platform_test'); - $this->mysqlCommand('DROP DATABASE IF EXISTS zombie2x'); - $this->mysqlCommand('CREATE DATABASE zombie2x'); - - // apply database migrations - $this->output->writeln("Migrating databases..."); - $this->execEnv("{$this->dir}/bin/phinx migrate -c {$this->dir}/application/phinx.php"); - - // if zombie2x.sql does not exist, download it - $zombie_sql_file = '/tmp/ushahidi-zombie2x.sql'; - if (!file_exists($zombie_sql_file)) - { - $this->downloadFile($this->test_database_sql_url, $zombie_sql_file); - } - - // import the zombies - $this->output->writeln("Importing test data"); - shell_exec("mysql -u root zombie2x < $zombie_sql_file"); - } - - protected function downloadFile($remote_file, $local_file) - { - $this->output->writeln("Downloading $remote_file"); - - $outfile = fopen($local_file, 'wb'); - - $progress = new ProgressBar($this->output, 100); - $progress->setFormat('[%bar%] %percent:3s%% (%elapsed% / %estimated:-6s%)'); - - $ch = curl_init(); - - curl_setopt($ch, CURLOPT_FILE, $outfile); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_URL, $remote_file); - curl_setopt($ch, CURLOPT_NOPROGRESS, false); - curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function() use ($progress) { - // curl versions 7.32 and below do not pass the - // $ch handler as the first argument to this function - $args = func_get_args(); - if (count($args) >= 5) { array_shift($args); } - - $total_down = $args[0]; - $current_down = $args[1]; - - if ($total_down === 0) { return; } - $progress->setCurrent(intval(($current_down / $total_down) * 100)); - }); - - curl_exec($ch); - $progress->finish(); - $this->output->writeln(''); - curl_close($ch); - fclose($outfile); - } - - protected function testServer($state, $coverage = FALSE) - { - if ($state === 'up' && !$this->test_server_pid) - { - $index = $coverage ? 'coverage' : 'index'; - $command = "php -S localhost:8000 -t {$this->dir}/httpdocs" - . " {$this->dir}/httpdocs/{$index}.php" - . " > /dev/null 2>&1 & echo $!;" - ; - - $this->test_server_pid = $this->execEnv($command); - $this->output->writeln("PHP server started (pid: {$this->test_server_pid})"); - sleep(3); - } - else if ($state === 'down' && $this->test_server_pid) - { - $this->output->writeln("Terminating PHP Server (pid: {$this->test_server_pid})"); - // Hack: hard coded fallback signal because OSX php is weird and doesn't have SIGTERM - $sigterm = defined('SIGTERM') ? SIGTERM : 15; - posix_kill($this->test_server_pid, $sigterm); - $this->test_server_pid = null; - } - } - - protected function execEnv($command, $return_exit_code = false, $env_vars = array()) - { - $env_vars = $env_vars ?: $this->env_variables; - array_walk($env_vars, function(&$value, $key) { - $value = "export $key=$value"; - }); - - $command = implode(';', $env_vars) . ";$command"; - - if ($return_exit_code) - { - passthru($command, $exit_code); - return $exit_code; - } - else - { - return exec($command); - } - } - - protected function mysqlCommand($command) - { - $command = escapeshellarg($command); - shell_exec("mysql -u root -e $command;"); - } - - protected function addOutputFormatting() - { - foreach ([ // custom output formatting - 'pass' => new OutputFormatterStyle('white', 'green', ['bold']), - 'fail' => new OutputFormatterStyle('white', 'red', ['bold']), - 'info' => new OutputFormatterStyle('white', 'blue', ['bold']), - ] as $tag => $style) { - $this->output->getFormatter()->setStyle($tag, $style); - } - } -} - -class UshahidiTestsRunCommand extends UshahidiTestsCommand -{ - protected function configure() - { - $this - ->setName('run') - ->setDescription('Runs all the tests and returns a single pass/fail result & exit code (default command)') - ->addOption( - 'no-install', - null, - InputOption::VALUE_NONE, - 'Don\'t install the prerequisites' - )->addOption( - 'coverage', - null, - InputOption::VALUE_NONE, - 'Enable code coverage' - ) - - ; - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - parent::execute($input, $output); - - $this->output->writeln( - "\n Ushahidi Platform Tests \n" - ); - - $no_install = $input->getOption('no-install'); - if (!$no_install) { $this->install(); } - - $coverage = $input->getOption('coverage'); - if ($coverage) { - $coverage_dir = $this->dir . 'coverage'; - system('rm -rf ' . escapeshellarg($coverage_dir) . '/*'); // clear coverage - } - - // start the local test server - $this->testServer('up', $coverage); - - // we're optimistic - $tests_pass = true; - $test_start_time = time(); - - // run phpspec - chdir($this->dir); // phpspec won't find tests otherwise - $output->writeln("\n - Running Phpspec tests - "); - $phpspec_command = "{$this->dir}/bin/phpspec run --no-code-generation" - . ($coverage ? " -c phpspec.yml.dist" : " -c phpspec.yml.coverage"); - $tests_pass = ($this->execEnv($phpspec_command, true) === 0) && $tests_pass; - - // run behat - $output->writeln("\n - Running Behat tests - \n"); - $behat_cache = '/tmp/behat.cache'; - $behat_command = "{$this->dir}/bin/behat" - . " --config {$this->dir}/behat.yml.dist" - . " --cache $behat_cache" - . " --format progress" - . " --profile ci" - . " --strict" - ; - $tests_pass = ($this->execEnv($behat_command, true) === 0) && $tests_pass; - system('rm -rf ' . escapeshellarg($behat_cache)); // clear cache - - // run phpunit - $output->writeln("\n - Running PHPUnit tests - \n"); - $phpunit_command = "{$this->dir}/bin/phpunit" - . " -c {$this->dir}/phpunit.xml.dist" - . ($coverage ? "" : " --no-coverage") - ; - $tests_pass = ($this->execEnv($phpunit_command, true) === 0) && $tests_pass; - - // bring down the test server - $this->testServer('down'); - - $elapsed_time = time() - $test_start_time; - - // output a single pass/fail message - if ($tests_pass) - { - $output->writeln( - "\n All tests ran successfully! ($elapsed_time seconds)\n" - ); - } - else - { - $output->writeln( - "\n Some tests failed! \n" - ); - } - - // return a single exit code from the tests above - exit($tests_pass ? 0 : 1); - } -} - -class UshahidiTestsInstallCommand extends UshahidiTestsCommand -{ - protected function configure() - { - $this - ->setName('install') - ->setDescription('Install necessary prerequisites for running tests') - ; - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - parent::execute($input, $output); - $this->install(); - } -} - -$test_runner = new Application(); -$test_runner->add(new UshahidiTestsRunCommand); -$test_runner->add(new UshahidiTestsInstallCommand); -$test_runner->setDefaultCommand('run'); -$test_runner->run(); diff --git a/composer.json b/composer.json index 7f91d34a20..3e40bd4609 100644 --- a/composer.json +++ b/composer.json @@ -7,29 +7,30 @@ "repositories": [ { "type": "vcs", - "url": "https://github.com/ushahidi/Aura.Di" + "url": "https://github.com/ushahidi/ohanzee-db" } ], "require": { - "php": ">=5.4", - "aura/di": "dev-develop-2", + "php": ">=5.6.4", + "aura/di": "2.2", "bodom78/kohana-imagefly": "dev-master", "league/oauth2-server": "~3.2.4", - "league/flysystem-aws-s3-v3": "1.0.4", - "league/flysystem-rackspace": "1.0.1", - "league/flysystem": "1.1.*", + "league/flysystem-aws-s3-v3": "~1.0", + "league/flysystem-rackspace": "~1.0", + "league/flysystem": "~1.0", "ircmaxell/password-compat": "^1.0.4", + "intercom/intercom-php": "^v3.1.2", "abraham/twitteroauth": "^0.5.3", "kohana/core" : "3.3.3.1@dev", "kohana/cache" : "3.3.*@dev", "kohana/image" : "3.3.*@dev", "kohana/minion" : "3.3.*@dev", - "ohanzee/database": "~0.1.2", - "robmorgan/phinx": "~0.4.1", + "ohanzee/database": "dev-master", + "robmorgan/phinx": "~0.8.0", "ushahidi/shadowhand-email": "dev-master", "symm/gisconverter": "~1.0.5", "twilio/sdk": "3.12.*", - "vlucas/phpdotenv": "~1.0@dev", + "vlucas/phpdotenv": "~2.2", "zeelot/kohana-media": "1.3.*@dev", "ext-curl": "*", "ext-gd": "*", @@ -44,26 +45,24 @@ "league/url": "~3.0", "beheh/flaps": "dev-master", "doctrine/cache": "^1.5@dev", - "satooshi/php-coveralls": "^2.0@dev", - "henrikbjorn/phpspec-code-coverage": "~2.0", "ramsey/uuid": "^3.4.1", "sentry/sentry": "~1.5" }, "require-dev": { - "behat/behat": "~2.5.2", - "behat/mink-extension": "~1.3", - "behat/mink-goutte-driver": "~1.0", - "fabpot/goutte": "~1.0", + "fzaninotto/faker": "~1.4", "guzzle/guzzle": "~3.9.1", - "kohana/unittest": "3.3.*@dev", - "phpunit/phpunit": "~4.8", + "phpunit/phpunit": "^5.7", "phpunit/dbunit": "~1.4", - "phpspec/phpspec": "~2.4", - "symfony/console": "2.6.*", - "squizlabs/php_codesniffer": "1.5.*", - "heroku/heroku-buildpack-php": "dev-master" + "phpspec/phpspec": "~3.0", + "heroku/heroku-buildpack-php": "dev-master", + "behat/behat": "^3.3", + "behat/mink-extension": "^2.2", + "behat/mink-goutte-driver": "^1.2", + "satooshi/php-coveralls": "^2.0@dev", + "leanphp/phpspec-code-coverage": "~3.1", + "laravel/homestead": "^5.2", + "squizlabs/php_codesniffer": "~3.0" }, - "minimum-stability": "dev", "config": { "bin-dir": "bin/", "github-protocols": [ @@ -78,26 +77,36 @@ "Ushahidi\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "Tests\\Unit\\": "tests/unit", + "Tests\\Integration\\Bootstrap\\": "tests/integration/bootstrap" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, "scripts": { "compile" : [ - "phinx migrate -c application/phinx.php" + "@migrate" ], "lint" : [ - "phpcs --ignore=vendor/*,application/*,modules/*,plugins/*,httpdocs/*,spec/*,migrations/*,bin/* --standard=PSR2 --tab-width=4 ./", - "phpcs --standard=spec/ruleset.xml --tab-width=4 ./spec/", + "phpcs --ignore=vendor/*,application/*,modules/*,plugins/*,httpdocs/*,tests/spec/*,migrations/*,bin/* --standard=src/ruleset.xml --tab-width=4 ./", + "phpcs --standard=tests/spec/ruleset.xml --tab-width=4 ./tests/spec/", "phpcs --standard=migrations/ruleset.xml --tab-width=4 ./migrations/" ], "pre-coverage" : [ - "rm -rf coverage/", - "php -S localhost:8000 -t httpdocs httpdocs/coverage.php; echo $! > /tmp/platform.pid" + "rm -rf coverage/" ], "coverage" : [ "phpunit", "phpspec run --no-code-generation", "behat --strict --profile ci" ], + "migrate" : [ + "bin/phinx migrate -c application/phinx.php" + ], "pre-test" : [ - "php -S localhost:8000 -t httpdocs httpdocs/index.php &" + "@migrate" ], "test" : [ "phpunit --no-coverage", diff --git a/composer.lock b/composer.lock index 9851498716..ddadf34031 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "80f5f2a629f10179d208c5f39defbb63", - "content-hash": "e9a0d55e5c7248704ae10e2ea6c99774", + "hash": "930a9dfe59bde37d71c7443dfcdcb79e", + "content-hash": "75c4f2753a6b406fefe9b4bf17ba51ea", "packages": [ { "name": "abraham/twitteroauth", @@ -63,16 +63,16 @@ }, { "name": "aura/di", - "version": "dev-develop-2", + "version": "2.2.0", "source": { "type": "git", - "url": "https://github.com/ushahidi/Aura.Di.git", - "reference": "1ce70099c1f1460d57a38611d20d2b6a9a4e0356" + "url": "https://github.com/auraphp/Aura.Di.git", + "reference": "8e167c9faca11a8fde3594e2e6e4a967aaad9bd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ushahidi/Aura.Di/zipball/1ce70099c1f1460d57a38611d20d2b6a9a4e0356", - "reference": "1ce70099c1f1460d57a38611d20d2b6a9a4e0356", + "url": "https://api.github.com/repos/auraphp/Aura.Di/zipball/8e167c9faca11a8fde3594e2e6e4a967aaad9bd1", + "reference": "8e167c9faca11a8fde3594e2e6e4a967aaad9bd1", "shasum": "" }, "require": { @@ -92,6 +92,7 @@ "Aura\\Di\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-2-Clause" ], @@ -110,29 +111,26 @@ "di", "di container" ], - "support": { - "source": "https://github.com/ushahidi/Aura.Di/tree/develop-2" - }, - "time": "2014-11-30 17:41:20" + "time": "2015-03-16 00:22:17" }, { "name": "aws/aws-sdk-php", - "version": "3.18.20", + "version": "3.26.5", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "e5a901dd3a42d0c46a90ee37a174938cd0ce55bf" + "reference": "5fd52d91aa168134f13a57df7fbf7d1f7b7a85ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e5a901dd3a42d0c46a90ee37a174938cd0ce55bf", - "reference": "e5a901dd3a42d0c46a90ee37a174938cd0ce55bf", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5fd52d91aa168134f13a57df7fbf7d1f7b7a85ca", + "reference": "5fd52d91aa168134f13a57df7fbf7d1f7b7a85ca", "shasum": "" }, "require": { - "guzzlehttp/guzzle": "~5.3|~6.0.1|~6.1", + "guzzlehttp/guzzle": "^5.3.1|^6.2.1", "guzzlehttp/promises": "~1.0", - "guzzlehttp/psr7": "~1.0", + "guzzlehttp/psr7": "^1.4.1", "mtdowling/jmespath.php": "~2.2", "php": ">=5.5" }, @@ -148,7 +146,7 @@ "ext-simplexml": "*", "ext-spl": "*", "nette/neon": "^2.3", - "phpunit/phpunit": "~4.0|~5.0", + "phpunit/phpunit": "^4.8.35|^5.4.0", "psr/cache": "^1.0" }, "suggest": { @@ -193,7 +191,7 @@ "s3", "sdk" ], - "time": "2016-06-23 23:17:52" + "time": "2017-04-28 23:15:22" }, { "name": "beheh/flaps", @@ -201,12 +199,12 @@ "source": { "type": "git", "url": "https://github.com/beheh/flaps.git", - "reference": "9a7089d1d46e8450c1bea92474d9b512077e61af" + "reference": "f9b86524ed1c9bf12f5cb99da2d77f62a22f4d01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beheh/flaps/zipball/9a7089d1d46e8450c1bea92474d9b512077e61af", - "reference": "9a7089d1d46e8450c1bea92474d9b512077e61af", + "url": "https://api.github.com/repos/beheh/flaps/zipball/f9b86524ed1c9bf12f5cb99da2d77f62a22f4d01", + "reference": "f9b86524ed1c9bf12f5cb99da2d77f62a22f4d01", "shasum": "" }, "require": { @@ -246,7 +244,7 @@ "rate limit", "throttle" ], - "time": "2015-06-11 09:37:09" + "time": "2017-02-01 11:01:27" }, { "name": "bodom78/kohana-imagefly", @@ -291,16 +289,16 @@ }, { "name": "composer/installers", - "version": "dev-master", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "3c90d491bafa3d0a1bd57a7d001da839a08d2f88" + "reference": "79ad876c7498c0bbfe7eed065b8651c93bfd6045" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/3c90d491bafa3d0a1bd57a7d001da839a08d2f88", - "reference": "3c90d491bafa3d0a1bd57a7d001da839a08d2f88", + "url": "https://api.github.com/repos/composer/installers/zipball/79ad876c7498c0bbfe7eed065b8651c93bfd6045", + "reference": "79ad876c7498c0bbfe7eed065b8651c93bfd6045", "shasum": "" }, "require": { @@ -342,11 +340,16 @@ "keywords": [ "Craft", "Dolibarr", + "Eliasis", "Hurad", "ImageCMS", + "Kanboard", "MODX Evo", "Mautic", + "Maya", "OXID", + "Plentymarkets", + "Porto", "RadPHP", "SMF", "Thelia", @@ -354,9 +357,11 @@ "agl", "aimeos", "annotatecms", + "attogram", "bitrix", "cakephp", "chef", + "cockpit", "codeigniter", "concrete5", "croogo", @@ -367,9 +372,11 @@ "fuelphp", "grav", "installer", + "itop", "joomla", "kohana", "laravel", + "lavalite", "lithium", "magento", "mako", @@ -380,16 +387,19 @@ "piwik", "ppi", "puppet", + "reindex", "roundcube", "shopware", "silverstripe", + "sydes", "symfony", "typo3", "wordpress", + "yawik", "zend", "zikula" ], - "time": "2016-06-24 07:03:15" + "time": "2017-04-24 06:37:16" }, { "name": "ddeboer/data-import", @@ -397,12 +407,12 @@ "source": { "type": "git", "url": "https://github.com/ddeboer/data-import.git", - "reference": "8fe7e731bb52df0298707eb8fb8b9b8098395437" + "reference": "2107895beae45cffb19a5084b9d117f79d288d73" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ddeboer/data-import/zipball/8fe7e731bb52df0298707eb8fb8b9b8098395437", - "reference": "8fe7e731bb52df0298707eb8fb8b9b8098395437", + "url": "https://api.github.com/repos/ddeboer/data-import/zipball/2107895beae45cffb19a5084b9d117f79d288d73", + "reference": "2107895beae45cffb19a5084b9d117f79d288d73", "shasum": "" }, "require": { @@ -461,20 +471,20 @@ "export", "import" ], - "time": "2016-06-23 06:26:02" + "time": "2017-01-22 10:07:40" }, { "name": "doctrine/cache", - "version": "dev-master", + "version": "v1.6.1", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "ce7c366e335378e8a11ef602820a8e12626f12d7" + "reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/ce7c366e335378e8a11ef602820a8e12626f12d7", - "reference": "ce7c366e335378e8a11ef602820a8e12626f12d7", + "url": "https://api.github.com/repos/doctrine/cache/zipball/b6f544a20f4807e81f7044d31e679ccbb1866dc3", + "reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3", "shasum": "" }, "require": { @@ -485,12 +495,13 @@ }, "require-dev": { "phpunit/phpunit": "~4.8|~5.0", - "predis/predis": "~1.0" + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -530,74 +541,20 @@ "cache", "caching" ], - "time": "2016-06-21 12:14:15" - }, - { - "name": "doctrine/instantiator", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "416fb8ad1d095a87f1d21bc40711843cd122fd4a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/416fb8ad1d095a87f1d21bc40711843cd122fd4a", - "reference": "416fb8ad1d095a87f1d21bc40711843cd122fd4a", - "shasum": "" - }, - "require": { - "php": ">=5.3,<8.0-DEV" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.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": "2016-03-31 10:24:22" + "time": "2016-10-29 11:16:17" }, { "name": "guzzle/guzzle", - "version": "dev-master", + "version": "v3.9.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle3.git", - "reference": "b3f5050cb6270c7a728a0b74ac2de50a262b3e02" + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/b3f5050cb6270c7a728a0b74ac2de50a262b3e02", - "reference": "b3f5050cb6270c7a728a0b74ac2de50a262b3e02", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", "shasum": "" }, "require": { @@ -680,31 +637,31 @@ "web service" ], "abandoned": "guzzlehttp/guzzle", - "time": "2015-04-29 17:06:53" + "time": "2015-03-18 18:23:50" }, { "name": "guzzlehttp/guzzle", - "version": "dev-master", + "version": "6.2.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "79c6fbef131eed51ab82bf813e9694419931bc8b" + "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/79c6fbef131eed51ab82bf813e9694419931bc8b", - "reference": "79c6fbef131eed51ab82bf813e9694419931bc8b", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/8d6c6cc55186db87b7dc5009827429ba4e9dc006", + "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006", "shasum": "" }, "require": { - "guzzlehttp/promises": "~1.0", - "guzzlehttp/psr7": "~1.1", - "php": ">=5.5.0" + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" }, "require-dev": { "ext-curl": "*", - "phpunit/phpunit": "~4.0", - "psr/log": "~1.0" + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" }, "type": "library", "extra": { @@ -742,32 +699,32 @@ "rest", "web service" ], - "time": "2016-06-20 07:37:14" + "time": "2017-02-28 22:50:30" }, { "name": "guzzlehttp/promises", - "version": "1.2.0", + "version": "v1.3.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579" + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579", - "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", "shasum": "" }, "require": { "php": ">=5.5.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "^4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -793,20 +750,20 @@ "keywords": [ "promise" ], - "time": "2016-05-18 16:56:05" + "time": "2016-12-20 10:07:11" }, { "name": "guzzlehttp/psr7", - "version": "dev-master", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b" + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", - "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", "shasum": "" }, "require": { @@ -842,72 +799,84 @@ "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", + "description": "PSR-7 message implementation that also provides common utility methods", "keywords": [ "http", "message", + "request", + "response", "stream", - "uri" + "uri", + "url" ], - "time": "2016-06-24 23:00:38" + "time": "2017-03-20 17:10:46" }, { - "name": "henrikbjorn/phpspec-code-coverage", - "version": "2.1.0", + "name": "intercom/intercom-php", + "version": "v3.1.2", "source": { "type": "git", - "url": "https://github.com/henrikbjorn/PhpSpecCodeCoverageExtension.git", - "reference": "528a0c69a524f8acba5f66bc59ae8dc9bc409045" + "url": "https://github.com/intercom/intercom-php.git", + "reference": "9ebffdf46cf42e59cac03e8382e3420ba9df7953" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/henrikbjorn/PhpSpecCodeCoverageExtension/zipball/528a0c69a524f8acba5f66bc59ae8dc9bc409045", - "reference": "528a0c69a524f8acba5f66bc59ae8dc9bc409045", + "url": "https://api.github.com/repos/intercom/intercom-php/zipball/9ebffdf46cf42e59cac03e8382e3420ba9df7953", + "reference": "9ebffdf46cf42e59cac03e8382e3420ba9df7953", "shasum": "" }, "require": { - "php": "^5.3.3|^5.4|^5.5|^5.6|^7.0", - "phpspec/phpspec": "^2.0", - "phpunit/php-code-coverage": "^2.2.4|^3" + "guzzlehttp/guzzle": "~6.0", + "php": ">= 5.6" }, "require-dev": { - "bossa/phpspec2-expect": "^1.0" - }, - "suggest": { - "ext-xdebug": "To allow coverage generation when not using a recent version of phpdbg" + "phpunit/phpunit": "4.0.*" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "psr-4": { - "PhpSpec\\Extension\\": "src/" + "Intercom\\": [ + "src" + ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache Version 2" + ], + "authors": [ + { + "name": "Intercom Platform Team", + "homepage": "http://intercom.io" + } + ], + "description": "Intercom API client built on top of Guzzle 6", + "keywords": [ + "Guzzle", + "api", + "intercom", + "intercom.io" ], - "description": "Integrates CodeCoverage with PhpSpec", - "time": "2016-05-05 18:25:12" + "time": "2017-04-04 13:33:25" }, { "name": "ircmaxell/password-compat", - "version": "1.0.x-dev", + "version": "v1.0.4", "source": { "type": "git", "url": "https://github.com/ircmaxell/password_compat.git", - "reference": "9b99377557a33a4129c9194e60a97a685fab21e0" + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/9b99377557a33a4129c9194e60a97a685fab21e0", - "reference": "9b99377557a33a4129c9194e60a97a685fab21e0", + "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", "shasum": "" }, "require-dev": { @@ -936,11 +905,11 @@ "hashing", "password" ], - "time": "2014-11-20 19:18:42" + "time": "2014-11-20 16:49:30" }, { "name": "kohana/cache", - "version": "dev-3.3/develop", + "version": "v3.3.6", "source": { "type": "git", "url": "https://github.com/kohana/cache.git", @@ -1055,7 +1024,7 @@ }, { "name": "kohana/image", - "version": "dev-3.3/develop", + "version": "v3.3.6", "source": { "type": "git", "url": "https://github.com/kohana/image.git", @@ -1115,7 +1084,7 @@ }, { "name": "kohana/minion", - "version": "dev-3.3/develop", + "version": "v3.3.6", "source": { "type": "git", "url": "https://github.com/kohana/minion.git", @@ -1233,12 +1202,12 @@ "source": { "type": "git", "url": "https://github.com/thephpleague/event.git", - "reference": "ebc612ba587ab9411ffefa276d72398c57517c50" + "reference": "0bfa3954c93a7b596168b4fd32d0e6631fd175e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/event/zipball/ebc612ba587ab9411ffefa276d72398c57517c50", - "reference": "ebc612ba587ab9411ffefa276d72398c57517c50", + "url": "https://api.github.com/repos/thephpleague/event/zipball/0bfa3954c93a7b596168b4fd32d0e6631fd175e2", + "reference": "0bfa3954c93a7b596168b4fd32d0e6631fd175e2", "shasum": "" }, "require": { @@ -1275,24 +1244,24 @@ "event", "listener" ], - "time": "2016-03-21 09:16:39" + "time": "2016-07-23 09:33:29" }, { "name": "league/flysystem", - "version": "dev-master", + "version": "1.0.40", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "b75910a746d1f3ae4b347bd95e86553b4d2e81cc" + "reference": "3828f0b24e2c1918bb362d57a53205d6dc8fde61" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/b75910a746d1f3ae4b347bd95e86553b4d2e81cc", - "reference": "b75910a746d1f3ae4b347bd95e86553b4d2e81cc", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3828f0b24e2c1918bb362d57a53205d6dc8fde61", + "reference": "3828f0b24e2c1918bb362d57a53205d6dc8fde61", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=5.5.9" }, "conflict": { "league/flysystem-sftp": "<1.0.6" @@ -1310,12 +1279,12 @@ "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", "league/flysystem-copy": "Allows you to use Copy.com storage", - "league/flysystem-dropbox": "Allows you to use Dropbox storage", "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", "league/flysystem-webdav": "Allows you to use WebDAV storage", - "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter" + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage" }, "type": "library", "extra": { @@ -1358,25 +1327,25 @@ "sftp", "storage" ], - "time": "2016-06-09 08:23:13" + "time": "2017-04-28 10:15:08" }, { "name": "league/flysystem-aws-s3-v3", - "version": "1.0.4", + "version": "1.0.15", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "e8e27d07bba47d29ca064b5f9dd06273fbaf7f62" + "reference": "c947f36f977b495a57e857ae1630df0da35ec456" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/e8e27d07bba47d29ca064b5f9dd06273fbaf7f62", - "reference": "e8e27d07bba47d29ca064b5f9dd06273fbaf7f62", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/c947f36f977b495a57e857ae1630df0da35ec456", + "reference": "c947f36f977b495a57e857ae1630df0da35ec456", "shasum": "" }, "require": { "aws/aws-sdk-php": "^3.0.0", - "league/flysystem": "~1.0", + "league/flysystem": "^1.0.40", "php": ">=5.5.0" }, "require-dev": { @@ -1405,26 +1374,26 @@ } ], "description": "Flysystem adapter for the AWS S3 SDK v3.x", - "time": "2015-07-07 20:11:47" + "time": "2017-04-28 10:21:54" }, { "name": "league/flysystem-rackspace", - "version": "1.0.1", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-rackspace.git", - "reference": "c44e4072cf93c9e1b6ee9a125ad84c827e13adca" + "reference": "ba877e837f5dce60e78a0555de37eb9bfc7dd6b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-rackspace/zipball/c44e4072cf93c9e1b6ee9a125ad84c827e13adca", - "reference": "c44e4072cf93c9e1b6ee9a125ad84c827e13adca", + "url": "https://api.github.com/repos/thephpleague/flysystem-rackspace/zipball/ba877e837f5dce60e78a0555de37eb9bfc7dd6b9", + "reference": "ba877e837f5dce60e78a0555de37eb9bfc7dd6b9", "shasum": "" }, "require": { "league/flysystem": "~1.0", "php": ">=5.4.0", - "rackspace/php-opencloud": "~1.12" + "rackspace/php-opencloud": "~1.16" }, "require-dev": { "mockery/mockery": "0.9.*", @@ -1452,7 +1421,7 @@ } ], "description": "Flysystem adapter for Rackspace", - "time": "2015-04-02 07:47:54" + "time": "2016-03-11 12:13:42" }, { "name": "league/oauth2-server", @@ -1518,16 +1487,16 @@ }, { "name": "league/url", - "version": "3.x-dev", + "version": "3.3.5", "source": { "type": "git", "url": "https://github.com/thephpleague/url.git", - "reference": "45f5529ea879ffc166cc4e4ffa478a212c183628" + "reference": "1ae2c3ce29a7c5438339ff6388225844e6479da8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/url/zipball/45f5529ea879ffc166cc4e4ffa478a212c183628", - "reference": "45f5529ea879ffc166cc4e4ffa478a212c183628", + "url": "https://api.github.com/repos/thephpleague/url/zipball/1ae2c3ce29a7c5438339ff6388225844e6479da8", + "reference": "1ae2c3ce29a7c5438339ff6388225844e6479da8", "shasum": "" }, "require": { @@ -1569,7 +1538,7 @@ "url" ], "abandoned": "league/uri", - "time": "2015-09-24 10:19:47" + "time": "2015-07-15 08:24:12" }, { "name": "mikemccabe/json-patch-php", @@ -1598,96 +1567,18 @@ "description": "Produce and apply json-patch objects", "time": "2015-01-05 21:19:54" }, - { - "name": "monolog/monolog", - "version": "1.x-dev", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "55841909e2bcde01b5318c35f2b74f8ecc86e037" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/55841909e2bcde01b5318c35f2b74f8ecc86e037", - "reference": "55841909e2bcde01b5318c35f2b74f8ecc86e037", - "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", - "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" - }, - "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": "2016-07-02 14:02:10" - }, { "name": "mtdowling/jmespath.php", - "version": "2.3.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "192f93e43c2c97acde7694993ab171b3de284093" + "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/192f93e43c2c97acde7694993ab171b3de284093", - "reference": "192f93e43c2c97acde7694993ab171b3de284093", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/adcc9531682cf87dfda21e1fd5d0e7a41d292fac", + "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac", "shasum": "" }, "require": { @@ -1729,25 +1620,25 @@ "json", "jsonpath" ], - "time": "2016-01-05 18:25:05" + "time": "2016-12-03 22:08:25" }, { "name": "ohanzee/database", - "version": "0.1.2", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/kohana/ohanzee-db.git", - "reference": "26dc07ed3041551258a6d5d70a01bf454d28ab32" + "url": "https://github.com/ushahidi/ohanzee-db.git", + "reference": "279a566fee8724214b37ba66a5270cfa4dc2751b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kohana/ohanzee-db/zipball/26dc07ed3041551258a6d5d70a01bf454d28ab32", - "reference": "26dc07ed3041551258a6d5d70a01bf454d28ab32", + "url": "https://api.github.com/repos/ushahidi/ohanzee-db/zipball/279a566fee8724214b37ba66a5270cfa4dc2751b", + "reference": "279a566fee8724214b37ba66a5270cfa4dc2751b", "shasum": "" }, "require": { "kohana/core": ">=3.3", - "php": ">=5.3.6" + "php": ">=5.4" }, "replace": { "kohana/database": ">=3.3" @@ -1762,7 +1653,6 @@ "": "src/" } }, - "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -1779,7 +1669,7 @@ "role": "developer" } ], - "description": "Official Ohanzee component for database SQL queries", + "description": "Ohanzee component for database SQL queries and query building", "homepage": "http://ohanzee.org/", "keywords": [ "component", @@ -1790,20 +1680,26 @@ "query builder", "sql" ], - "time": "2014-08-21 16:41:35" + "support": { + "source": "http://github.com/kohana/ohanzee-db", + "issues": "http://github.com/kohana/ohanzee-db/issues", + "forum": "http://discourse.kohanaframework.org/category/ohanzee-components", + "irc": "irc://irc.freenode.net/kohana" + }, + "time": "2017-04-28 00:10:09" }, { "name": "paragonie/random_compat", - "version": "v2.0.2", + "version": "v2.0.10", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf" + "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf", - "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d", + "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d", "shasum": "" }, "require": { @@ -1838,27 +1734,24 @@ "pseudorandom", "random" ], - "time": "2016-04-03 06:00:07" + "time": "2017-03-13 16:27:32" }, { - "name": "phpdocumentor/reflection-common", - "version": "dev-master", + "name": "psr/http-message", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", "shasum": "" }, "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" + "php": ">=5.3.0" }, "type": "library", "extra": { @@ -1868,9 +1761,7 @@ }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1879,51 +1770,48 @@ ], "authors": [ { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" ], - "time": "2015-12-27 11:43:31" + "time": "2016-08-06 14:39:51" }, { - "name": "phpdocumentor/reflection-docblock", - "version": "3.1.0", + "name": "psr/log", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "shasum": "" }, "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" + "php": ">=5.3.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1932,146 +1820,188 @@ ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-06-10 09:48:41" + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10 12:19:37" }, { - "name": "phpdocumentor/type-resolver", - "version": "0.2", + "name": "rackspace/php-opencloud", + "version": "v1.16.0", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + "url": "https://github.com/rackspace/php-opencloud.git", + "reference": "d6b71feed7f9e7a4b52e0240a79f06473ba69c8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "url": "https://api.github.com/repos/rackspace/php-opencloud/zipball/d6b71feed7f9e7a4b52e0240a79f06473ba69c8c", + "reference": "d6b71feed7f9e7a4b52e0240a79f06473ba69c8c", "shasum": "" }, "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0" + "guzzle/guzzle": "~3.8", + "mikemccabe/json-patch-php": "~0.1", + "php": ">=5.4", + "psr/log": "~1.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "apigen/apigen": "~4.0", + "fabpot/php-cs-fixer": "1.0.*@dev", + "jakub-onderka/php-parallel-lint": "0.*", + "phpspec/prophecy": "~1.4", + "phpunit/phpunit": "4.3.*", + "satooshi/php-coveralls": "0.6.*@dev" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" + "psr-0": { + "OpenCloud": [ + "lib/" ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache-2.0" ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "name": "Jamie Hannaford", + "email": "jamie.hannaford@rackspace.com", + "homepage": "https://github.com/jamiehannaford" } ], - "time": "2016-06-10 07:14:17" - }, - { - "name": "phpspec/php-diff", - "version": "dev-master", - "source": { + "description": "PHP SDK for Rackspace/OpenStack APIs", + "keywords": [ + "Openstack", + "nova", + "opencloud", + "rackspace", + "swift" + ], + "time": "2016-01-29 10:34:57" + }, + { + "name": "ramsey/uuid", + "version": "3.6.1", + "source": { "type": "git", - "url": "https://github.com/phpspec/php-diff.git", - "reference": "0464787bfa7cd13576c5a1e318709768798bec6a" + "url": "https://github.com/ramsey/uuid.git", + "reference": "4ae32dd9ab8860a4bbd750ad269cba7f06f7934e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/php-diff/zipball/0464787bfa7cd13576c5a1e318709768798bec6a", - "reference": "0464787bfa7cd13576c5a1e318709768798bec6a", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/4ae32dd9ab8860a4bbd750ad269cba7f06f7934e", + "reference": "4ae32dd9ab8860a4bbd750ad269cba7f06f7934e", "shasum": "" }, + "require": { + "paragonie/random_compat": "^1.0|^2.0", + "php": "^5.4 || ^7.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "apigen/apigen": "^4.1", + "codeception/aspect-mock": "^1.0 | ^2.0", + "doctrine/annotations": "~1.2.0", + "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1", + "ircmaxell/random-lib": "^1.1", + "jakub-onderka/php-parallel-lint": "^0.9.0", + "mockery/mockery": "^0.9.4", + "moontoast/math": "^1.1", + "php-mock/php-mock-phpunit": "^0.3|^1.1", + "phpunit/phpunit": "^4.7|>=5.0 <5.4", + "satooshi/php-coveralls": "^0.6.1", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { - "psr-0": { - "Diff": "lib/" + "psr-4": { + "Ramsey\\Uuid\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Chris Boulton", - "homepage": "http://github.com/chrisboulton" + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + }, + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" } ], - "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", - "time": "2016-04-07 12:29:16" + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "time": "2017-03-26 20:37:53" }, { - "name": "phpspec/phpspec", - "version": "2.5.x-dev", + "name": "robmorgan/phinx", + "version": "v0.8.0", "source": { "type": "git", - "url": "https://github.com/phpspec/phpspec.git", - "reference": "65ba3eaa0e96c36a4a6c47950b10859ddc179ab5" + "url": "https://github.com/robmorgan/phinx.git", + "reference": "15e43d10dd99ac818c8d65735c50191bcbeafdbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/phpspec/zipball/65ba3eaa0e96c36a4a6c47950b10859ddc179ab5", - "reference": "65ba3eaa0e96c36a4a6c47950b10859ddc179ab5", + "url": "https://api.github.com/repos/robmorgan/phinx/zipball/15e43d10dd99ac818c8d65735c50191bcbeafdbc", + "reference": "15e43d10dd99ac818c8d65735c50191bcbeafdbc", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.1", - "ext-tokenizer": "*", - "php": ">=5.3.3", - "phpspec/php-diff": "~1.0.0", - "phpspec/prophecy": "~1.4", - "sebastian/exporter": "~1.0", - "symfony/console": "~2.3|~3.0", - "symfony/event-dispatcher": "~2.1|~3.0", - "symfony/finder": "~2.1|~3.0", - "symfony/process": "^2.6|~3.0", - "symfony/yaml": "~2.1|~3.0" + "php": ">=5.4", + "symfony/config": "~2.8|~3.0", + "symfony/console": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" }, "require-dev": { - "behat/behat": "^3.0.11", - "ciaranmcnulty/versionbasedtestskipper": "^0.2.1", - "phpunit/phpunit": "~4.4", - "symfony/filesystem": "~2.1|~3.0" - }, - "suggest": { - "phpspec/nyan-formatters": "~1.0 – Adds Nyan formatters" + "phpunit/phpunit": "^4.8.26|^5.0" }, "bin": [ - "bin/phpspec" + "bin/phinx" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5.x-dev" - } - }, "autoload": { - "psr-0": { - "PhpSpec": "src/" + "psr-4": { + "Phinx\\": "src/Phinx" } }, "notification-url": "https://packagist.org/downloads/", @@ -2080,52 +2010,66 @@ ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com", + "homepage": "http://shadowhand.me", + "role": "Developer" }, { - "name": "Marcello Duarte", - "homepage": "http://marcelloduarte.net/" + "name": "Rob Morgan", + "email": "robbym@gmail.com", + "homepage": "https://robmorgan.id.au", + "role": "Lead Developer" + }, + { + "name": "Richard Quadling", + "email": "rquadling@gmail.com", + "role": "Developer" } ], - "description": "Specification-oriented BDD framework for PHP 5.3+", - "homepage": "http://phpspec.net/", + "description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.", + "homepage": "https://phinx.org", "keywords": [ - "BDD", - "SpecBDD", - "TDD", - "spec", - "specification", - "testing", - "tests" + "database", + "database migrations", + "db", + "migrations", + "phinx" ], - "time": "2016-06-07 20:44:43" + "time": "2017-02-28 18:34:31" }, { - "name": "phpspec/prophecy", - "version": "dev-master", + "name": "sentry/sentry", + "version": "1.6.2", "source": { "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + "url": "https://github.com/getsentry/sentry-php.git", + "reference": "5bee26136ab3fc166334cd972892bf71bd361558" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/5bee26136ab3fc166334cd972892bf71bd361558", + "reference": "5bee26136ab3fc166334cd972892bf71bd361558", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0" + "ext-curl": "*", + "php": ">=5.2.4" + }, + "conflict": { + "raven/raven": "*" }, "require-dev": { - "phpspec/phpspec": "^2.0" + "friendsofphp/php-cs-fixer": "^1.8.0", + "monolog/monolog": "*", + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "suggest": { + "monolog/monolog": "Automatically capture Monolog events as breadcrumbs" }, + "bin": [ + "bin/sentry" + ], "type": "library", "extra": { "branch-alias": { @@ -2134,262 +2078,295 @@ }, "autoload": { "psr-0": { - "Prophecy\\": "src/" + "Raven_": "lib/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" + "name": "David Cramer", + "email": "dcramer@gmail.com" } ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", + "description": "A PHP client for Sentry (http://getsentry.com)", + "homepage": "http://getsentry.com", "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" + "log", + "logging" ], - "time": "2016-06-07 08:13:47" + "time": "2017-02-03 07:32:53" }, { - "name": "phpunit/php-code-coverage", - "version": "2.2.x-dev", + "name": "swiftmailer/swiftmailer", + "version": "v4.3.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "ae540bed1079c07aa12e9e62d9d8d4fc49bbdff2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/ae540bed1079c07aa12e9e62d9d8d4fc49bbdff2", + "reference": "ae540bed1079c07aa12e9e62d9d8d4fc49bbdff2", "shasum": "" }, "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" + "php": ">=5.2.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2.x-dev" + "dev-master": "4.3-dev" } }, "autoload": { - "classmap": [ - "src/" + "files": [ + "lib/swift_required.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "LGPL" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Chris Corbyn" } ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", "keywords": [ - "coverage", - "testing", - "xunit" + "mail", + "mailer" ], - "time": "2015-10-06 15:47:00" + "time": "2013-04-11 10:22:09" }, { - "name": "phpunit/php-file-iterator", - "version": "dev-master", + "name": "symfony/config", + "version": "v3.2.8", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + "url": "https://github.com/symfony/config.git", + "reference": "e5533fcc0b3dd377626153b2852707878f363728" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "url": "https://api.github.com/repos/symfony/config/zipball/e5533fcc0b3dd377626153b2852707878f363728", + "reference": "e5533fcc0b3dd377626153b2852707878f363728", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.5.9", + "symfony/filesystem": "~2.8|~3.0" + }, + "require-dev": { + "symfony/yaml": "~3.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "3.2-dev" } }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2015-06-21 13:08:43" + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2017-04-12 14:13:17" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "symfony/console", + "version": "v3.2.8", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/symfony/console.git", + "reference": "a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/symfony/console/zipball/a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38", + "reference": "a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.5.9", + "symfony/debug": "~2.8|~3.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/filesystem": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/filesystem": "", + "symfony/process": "" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21 13:50:34" + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2017-04-26 01:39:17" }, { - "name": "phpunit/php-token-stream", - "version": "dev-master", + "name": "symfony/debug", + "version": "v3.2.8", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "cab6c6fefee93d7b7c3a01292a0fe0884ea66644" + "url": "https://github.com/symfony/debug.git", + "reference": "fd6eeee656a5a7b384d56f1072243fe1c0e81686" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/cab6c6fefee93d7b7c3a01292a0fe0884ea66644", - "reference": "cab6c6fefee93d7b7c3a01292a0fe0884ea66644", + "url": "https://api.github.com/repos/symfony/debug/zipball/fd6eeee656a5a7b384d56f1072243fe1c0e81686", + "reference": "fd6eeee656a5a7b384d56f1072243fe1c0e81686", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" + "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": { - "phpunit/phpunit": "~4.2" + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "3.2-dev" } }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2015-09-23 14:46:55" + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2017-04-19 20:17:50" }, { - "name": "psr/http-message", - "version": "dev-master", + "name": "symfony/event-dispatcher", + "version": "v2.8.20", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "7fc8e2b4118ff316550596357325dfd92a51f531" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7fc8e2b4118ff316550596357325dfd92a51f531", + "reference": "7fc8e2b4118ff316550596357325dfd92a51f531", "shasum": "" }, "require": { - "php": ">=5.3.0" + "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": "1.0.x-dev" + "dev-master": "2.8-dev" } }, "autoload": { "psr-4": { - "Psr\\Http\\Message\\": "src/" - } + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2397,48 +2374,48 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Common interface for HTTP messages", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "time": "2015-05-04 20:22:00" + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2017-04-26 16:56:54" }, { - "name": "psr/log", - "version": "dev-master", + "name": "symfony/filesystem", + "version": "v3.2.8", "source": { "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "d8e60a5619fff77f9669da8997697443ef1a1d7e" + "url": "https://github.com/symfony/filesystem.git", + "reference": "040651db13cf061827a460cc10f6e36a445c45b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d8e60a5619fff77f9669da8997697443ef1a1d7e", - "reference": "d8e60a5619fff77f9669da8997697443ef1a1d7e", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/040651db13cf061827a460cc10f6e36a445c45b4", + "reference": "040651db13cf061827a460cc10f6e36a445c45b4", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=5.5.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.2-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2446,132 +2423,107 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2016-01-06 21:40:42" + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2017-04-12 14:13:17" }, { - "name": "rackspace/php-opencloud", - "version": "dev-working", + "name": "symfony/polyfill-mbstring", + "version": "v1.3.0", "source": { "type": "git", - "url": "https://github.com/rackspace/php-opencloud.git", - "reference": "3ffee7b90884a3c556578db8ff9ab2b20b65f18c" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rackspace/php-opencloud/zipball/3ffee7b90884a3c556578db8ff9ab2b20b65f18c", - "reference": "3ffee7b90884a3c556578db8ff9ab2b20b65f18c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", "shasum": "" }, "require": { - "guzzle/guzzle": "~3.8", - "mikemccabe/json-patch-php": "~0.1", - "php": ">=5.4", - "psr/log": "~1.0" + "php": ">=5.3.3" }, - "require-dev": { - "apigen/apigen": "~4.0", - "fabpot/php-cs-fixer": "1.0.*@dev", - "jakub-onderka/php-parallel-lint": "0.*", - "phpspec/prophecy": "~1.4", - "phpunit/phpunit": "4.3.*", - "satooshi/php-coveralls": "0.6.*@dev" + "suggest": { + "ext-mbstring": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-working": "1.16-dev" + "dev-master": "1.3-dev" } }, "autoload": { - "psr-0": { - "OpenCloud": [ - "lib/" - ] - } + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "MIT" ], "authors": [ { - "name": "Jamie Hannaford", - "email": "jamie.hannaford@rackspace.com", - "homepage": "https://github.com/jamiehannaford" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "PHP SDK for Rackspace/OpenStack APIs", + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", "keywords": [ - "Openstack", - "nova", - "opencloud", - "rackspace", - "swift" + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" ], - "time": "2016-06-13 07:37:06" + "time": "2016-11-14 01:06:16" }, { - "name": "ramsey/uuid", - "version": "dev-master", + "name": "symfony/property-access", + "version": "v2.8.20", "source": { "type": "git", - "url": "https://github.com/ramsey/uuid.git", - "reference": "be0a40fec15740eba2e6ade85786cd7348def382" + "url": "https://github.com/symfony/property-access.git", + "reference": "28a9b519a9cd1131b486362bfc6a00cdb9779a42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/be0a40fec15740eba2e6ade85786cd7348def382", - "reference": "be0a40fec15740eba2e6ade85786cd7348def382", + "url": "https://api.github.com/repos/symfony/property-access/zipball/28a9b519a9cd1131b486362bfc6a00cdb9779a42", + "reference": "28a9b519a9cd1131b486362bfc6a00cdb9779a42", "shasum": "" }, "require": { - "paragonie/random_compat": "^1.0|^2.0", - "php": ">=5.4" - }, - "replace": { - "rhumsaa/uuid": "self.version" - }, - "require-dev": { - "apigen/apigen": "^4.1", - "codeception/aspect-mock": "1.0.0", - "goaop/framework": "1.0.0-alpha.2", - "ircmaxell/random-lib": "^1.1", - "jakub-onderka/php-parallel-lint": "^0.9.0", - "mockery/mockery": "^0.9.4", - "moontoast/math": "^1.1", - "phpunit/phpunit": "^4.7|>=5.0 <5.4", - "satooshi/php-coveralls": "^0.6.1", - "squizlabs/php_codesniffer": "^2.3" - }, - "suggest": { - "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", - "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", - "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", - "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", - "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", - "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + "php": ">=5.3.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "2.8-dev" } }, "autoload": { "psr-4": { - "Ramsey\\Uuid\\": "src/" - } + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2579,59 +2531,148 @@ ], "authors": [ { - "name": "Marijn Huizendveld", - "email": "marijn.huizendveld@gmail.com" - }, - { - "name": "Thibaud Fabre", - "email": "thibaud@aztech.io" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", - "homepage": "https://github.com/ramsey/uuid", + "description": "Symfony PropertyAccess Component", + "homepage": "https://symfony.com", "keywords": [ - "guid", - "identifier", - "uuid" + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" ], - "time": "2016-06-24 22:24:42" + "time": "2017-04-12 14:07:15" }, { - "name": "robmorgan/phinx", - "version": "v0.4.3", + "name": "symfony/yaml", + "version": "v3.2.8", "source": { "type": "git", - "url": "https://github.com/robmorgan/phinx.git", - "reference": "0d1f9cb9939f65f506a8a3f5fee356764c310fd4" + "url": "https://github.com/symfony/yaml.git", + "reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/robmorgan/phinx/zipball/0d1f9cb9939f65f506a8a3f5fee356764c310fd4", - "reference": "0d1f9cb9939f65f506a8a3f5fee356764c310fd4", + "url": "https://api.github.com/repos/symfony/yaml/zipball/acec26fcf7f3031e094e910b94b002fa53d4e4d6", + "reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6", "shasum": "" }, "require": { - "php": ">=5.3.2", - "symfony/config": "~2.6.0", - "symfony/console": "~2.6.0", - "symfony/yaml": "~2.6.0" + "php": ">=5.5.9" }, "require-dev": { - "phpunit/phpunit": "3.7.*", - "squizlabs/php_codesniffer": "dev-phpcs-fixer" + "symfony/console": "~2.8|~3.0" }, - "bin": [ - "bin/phinx" + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "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 Yaml Component", + "homepage": "https://symfony.com", + "time": "2017-05-01 14:55:58" + }, + { + "name": "symm/gisconverter", + "version": "v1.0.5", + "source": { + "type": "git", + "url": "https://github.com/symm/gisconverter.git", + "reference": "21ab697b7692b891dac37c64d10c9d83d4433f80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symm/gisconverter/zipball/21ab697b7692b891dac37c64d10c9d83d4433f80", + "reference": "21ab697b7692b891dac37c64d10c9d83d4433f80", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Symm\\Gisconverter": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" ], + "description": "A php library to convert vector geometries between different formats", + "time": "2014-08-07 13:50:52" + }, + { + "name": "true/punycode", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/true/php-punycode.git", + "reference": "a4d0c11a36dd7f4e7cd7096076cab6d3378a071e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/true/php-punycode/zipball/a4d0c11a36dd7f4e7cd7096076cab6d3378a071e", + "reference": "a4d0c11a36dd7f4e7cd7096076cab6d3378a071e", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.7", + "squizlabs/php_codesniffer": "~2.0" + }, "type": "library", "autoload": { "psr-4": { - "Phinx\\": "src/Phinx" + "TrueBV\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2640,69 +2681,347 @@ ], "authors": [ { - "name": "Rob Morgan", - "email": "robbym@gmail.com", - "homepage": "http://robmorgan.id.au", - "role": "Lead Developer" + "name": "Renan Gonçalves", + "email": "renan.saddam@gmail.com" + } + ], + "description": "A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)", + "homepage": "https://github.com/true/php-punycode", + "keywords": [ + "idna", + "punycode" + ], + "time": "2016-11-16 10:37:54" + }, + { + "name": "twilio/sdk", + "version": "3.12.8", + "source": { + "type": "git", + "url": "https://github.com/twilio/twilio-php.git", + "reference": "9d8bb7dad58dc52fc4cbc1f0e905950ad839ca73" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twilio/twilio-php/zipball/9d8bb7dad58dc52fc4cbc1f0e905950ad839ca73", + "reference": "9d8bb7dad58dc52fc4cbc1f0e905950ad839ca73", + "shasum": "" + }, + "require": { + "php": ">=5.2.1" + }, + "require-dev": { + "mockery/mockery": ">=0.7.2", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "Services_Twilio": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Burke", + "email": "kevin@twilio.com" }, { - "name": "Woody Gilk", - "email": "woody.gilk@gmail.com", - "homepage": "http://shadowhand.me", - "role": "Developer" + "name": "Kyle Conroy", + "email": "kyle+pear@twilio.com" } ], - "description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.", - "homepage": "https://phinx.org", + "description": "A PHP wrapper for Twilio's API", + "homepage": "http://github.com/twilio/twilio-php", "keywords": [ - "database", - "database migrations", - "db", - "migrations", - "phinx" + "api", + "sms", + "twilio" ], - "time": "2015-02-23 16:38:12" + "time": "2014-12-04 19:17:59" }, { - "name": "satooshi/php-coveralls", + "name": "ushahidi/shadowhand-email", "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/satooshi/php-coveralls.git", - "reference": "50c60bb64054974f8ed7540ae6e75fd7981a5fd3" + "url": "https://github.com/ushahidi/shadowhand-email.git", + "reference": "51274cdd899d0c619368c9580146bd05b461a03f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/50c60bb64054974f8ed7540ae6e75fd7981a5fd3", - "reference": "50c60bb64054974f8ed7540ae6e75fd7981a5fd3", + "url": "https://api.github.com/repos/ushahidi/shadowhand-email/zipball/51274cdd899d0c619368c9580146bd05b461a03f", + "reference": "51274cdd899d0c619368c9580146bd05b461a03f", "shasum": "" }, "require": { - "ext-json": "*", - "ext-simplexml": "*", - "guzzlehttp/guzzle": "^6.0", - "php": ">=5.5", - "psr/log": "^1.0", - "symfony/config": "^2.1|^3.0", - "symfony/console": "^2.1|^3.0", - "symfony/stopwatch": "^2.0|^3.0", - "symfony/yaml": "^2.0|^3.0" + "kohana/core": "3.3.*", + "php": ">=5.3.0", + "swiftmailer/swiftmailer": "~4.3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Shadowhand\\": "src/" + }, + "files": [ + "init.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kohana Team", + "email": "team@kohanaframework.org", + "role": "creator" + }, + { + "name": "Robbie Mackay", + "email": "robbie@ushahidi.com", + "role": "maintainer" + } + ], + "description": "Email helper class, uses Swiftmailer", + "homepage": "http://github.com/ushahidi/shadowhand-email", + "keywords": [ + "email", + "helper", + "kohana", + "library", + "module", + "ohanzee", + "swiftmailer" + ], + "time": "2017-03-22 00:35:17" + }, + { + "name": "vlucas/phpdotenv", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause-Attribution" + ], + "authors": [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "time": "2016-09-01 10:05:43" + }, + { + "name": "zeelot/kohana-media", + "version": "dev-1.3/develop", + "source": { + "type": "git", + "url": "https://github.com/Zeelot/kohana-media.git", + "reference": "2f657c028d6c875017fd37d6b8d1fa3d2e3fe35e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Zeelot/kohana-media/zipball/2f657c028d6c875017fd37d6b8d1fa3d2e3fe35e", + "reference": "2f657c028d6c875017fd37d6b8d1fa3d2e3fe35e", + "shasum": "" + }, + "require": { + "kohana/core": ">=3.3", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.3/develop": "1.3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Lorenzo Pisani", + "email": "zeelot3k@gmail.com", + "homepage": "http://zeelot3k.com", + "role": "developer" + }, + { + "name": "Contributors", + "homepage": "https://github.com/Zeelot/kohana-media/graphs/contributors", + "role": "contributor" + } + ], + "description": "Using the Kohana cascading file system to serve media assets", + "homepage": "https://github.com/Zeelot/kohana-media", + "keywords": [ + "assets", + "caching", + "cfs", + "files", + "framework", + "kohana", + "media" + ], + "time": "2014-04-26 16:15:53" + } + ], + "packages-dev": [ + { + "name": "behat/behat", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/Behat/Behat.git", + "reference": "15a3a1857457eaa29cdf41564a5e421effb09526" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Behat/zipball/15a3a1857457eaa29cdf41564a5e421effb09526", + "reference": "15a3a1857457eaa29cdf41564a5e421effb09526", + "shasum": "" + }, + "require": { + "behat/gherkin": "^4.4.4", + "behat/transliterator": "~1.0", + "container-interop/container-interop": "^1.1", + "ext-mbstring": "*", + "php": ">=5.3.3", + "symfony/class-loader": "~2.1||~3.0", + "symfony/config": "~2.3||~3.0", + "symfony/console": "~2.5||~3.0", + "symfony/dependency-injection": "~2.1||~3.0", + "symfony/event-dispatcher": "~2.1||~3.0", + "symfony/translation": "~2.3||~3.0", + "symfony/yaml": "~2.1||~3.0" + }, + "require-dev": { + "herrera-io/box": "~1.6.1", + "phpunit/phpunit": "~4.5", + "symfony/process": "~2.5|~3.0" + }, + "suggest": { + "behat/mink-extension": "for integration with Mink testing framework", + "behat/symfony2-extension": "for integration with Symfony2 web framework", + "behat/yii-extension": "for integration with Yii web framework" + }, + "bin": [ + "bin/behat" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Behat": "src/", + "Behat\\Testwork": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Scenario-oriented BDD framework for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "Agile", + "BDD", + "ScenarioBDD", + "Scrum", + "StoryBDD", + "User story", + "business", + "development", + "documentation", + "examples", + "symfony", + "testing" + ], + "time": "2016-12-25 13:43:52" + }, + { + "name": "behat/gherkin", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", + "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.5|~5", + "symfony/phpunit-bridge": "~2.7|~3", + "symfony/yaml": "~2.3|~3" }, "suggest": { - "symfony/http-kernel": "Allows Symfony integration" + "symfony/yaml": "If you want to parse features, represented in YAML files" }, - "bin": [ - "bin/coveralls" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { - "psr-4": { - "Satooshi\\": "src/Satooshi/" + "psr-0": { + "Behat\\Gherkin": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2711,482 +3030,458 @@ ], "authors": [ { - "name": "Kitamura Satoshi", - "email": "with.no.parachute@gmail.com", - "homepage": "https://www.facebook.com/satooshi.jp" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" } ], - "description": "PHP client library for Coveralls API", - "homepage": "https://github.com/satooshi/php-coveralls", + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", "keywords": [ - "ci", - "coverage", - "github", - "test" + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" ], - "time": "2016-01-20 17:44:41" + "time": "2016-10-30 11:50:56" }, { - "name": "sebastian/comparator", - "version": "dev-master", + "name": "behat/mink", + "version": "v1.7.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + "url": "https://github.com/minkphp/Mink.git", + "reference": "e6930b9c74693dff7f4e58577e1b1743399f3ff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "url": "https://api.github.com/repos/minkphp/Mink/zipball/e6930b9c74693dff7f4e58577e1b1743399f3ff9", + "reference": "e6930b9c74693dff7f4e58577e1b1743399f3ff9", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2" + "php": ">=5.3.1", + "symfony/css-selector": "~2.1|~3.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "symfony/phpunit-bridge": "~2.7|~3.0" + }, + "suggest": { + "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)", + "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation", + "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)", + "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Behat\\Mink\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "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": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", + "description": "Browser controller/emulator abstraction for PHP", + "homepage": "http://mink.behat.org/", "keywords": [ - "comparator", - "compare", - "equality" + "browser", + "testing", + "web" ], - "time": "2015-07-26 15:48:44" + "time": "2016-03-05 08:26:18" }, { - "name": "sebastian/diff", - "version": "dev-master", + "name": "behat/mink-browserkit-driver", + "version": "v1.3.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + "url": "https://github.com/minkphp/MinkBrowserKitDriver.git", + "reference": "10e67fb4a295efcd62ea0bf16025a85ea19534fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/10e67fb4a295efcd62ea0bf16025a85ea19534fb", + "reference": "10e67fb4a295efcd62ea0bf16025a85ea19534fb", "shasum": "" }, "require": { - "php": ">=5.3.3" + "behat/mink": "^1.7.1@dev", + "php": ">=5.3.6", + "symfony/browser-kit": "~2.3|~3.0", + "symfony/dom-crawler": "~2.3|~3.0" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "silex/silex": "~1.2", + "symfony/phpunit-bridge": "~2.7|~3.0" }, - "type": "library", + "type": "mink-driver", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Behat\\Mink\\Driver\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" } ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", + "description": "Symfony2 BrowserKit driver for Mink framework", + "homepage": "http://mink.behat.org/", "keywords": [ - "diff" + "Mink", + "Symfony2", + "browser", + "testing" ], - "time": "2015-12-08 07:14:41" + "time": "2016-03-05 08:59:47" }, { - "name": "sebastian/environment", - "version": "dev-master", + "name": "behat/mink-extension", + "version": "v2.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "6e7133793a8e5a5714a551a8324337374be209df" + "url": "https://github.com/Behat/MinkExtension.git", + "reference": "5b4bda64ff456104564317e212c823e45cad9d59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e7133793a8e5a5714a551a8324337374be209df", - "reference": "6e7133793a8e5a5714a551a8324337374be209df", + "url": "https://api.github.com/repos/Behat/MinkExtension/zipball/5b4bda64ff456104564317e212c823e45cad9d59", + "reference": "5b4bda64ff456104564317e212c823e45cad9d59", "shasum": "" }, "require": { - "php": ">=5.3.3" + "behat/behat": "~3.0,>=3.0.5", + "behat/mink": "~1.5", + "php": ">=5.3.2", + "symfony/config": "~2.2|~3.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "behat/mink-goutte-driver": "~1.1", + "phpspec/phpspec": "~2.0" }, - "type": "library", + "type": "behat-extension", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "2.1.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-0": { + "Behat\\MinkExtension": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Christophe Coevoet", + "email": "stof@notk.org" + }, + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "description": "Mink extension for Behat", + "homepage": "http://extensions.behat.org/mink", "keywords": [ - "Xdebug", - "environment", - "hhvm" + "browser", + "gui", + "test", + "web" ], - "time": "2015-12-02 08:37:27" + "time": "2016-02-15 07:55:18" }, { - "name": "sebastian/exporter", - "version": "dev-master", + "name": "behat/mink-goutte-driver", + "version": "v1.2.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + "url": "https://github.com/minkphp/MinkGoutteDriver.git", + "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "url": "https://api.github.com/repos/minkphp/MinkGoutteDriver/zipball/8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", + "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" + "behat/mink": "~1.6@dev", + "behat/mink-browserkit-driver": "~1.2@dev", + "fabpot/goutte": "~1.0.4|~2.0|~3.1", + "php": ">=5.3.1" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" + "symfony/phpunit-bridge": "~2.7|~3.0" }, - "type": "library", + "type": "mink-driver", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Behat\\Mink\\Driver\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "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" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "description": "Goutte driver for Mink framework", + "homepage": "http://mink.behat.org/", "keywords": [ - "export", - "exporter" + "browser", + "goutte", + "headless", + "testing" ], - "time": "2016-06-17 09:04:28" + "time": "2016-03-05 09:04:22" }, { - "name": "sebastian/recursion-context", - "version": "dev-master", + "name": "behat/transliterator", + "version": "v1.2.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "7ff5b1b3dcc55b8ab8ae61ef99d4730940856ee7" + "url": "https://github.com/Behat/Transliterator.git", + "reference": "826ce7e9c2a6664c0d1f381cbb38b1fb80a7ee2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/7ff5b1b3dcc55b8ab8ae61ef99d4730940856ee7", - "reference": "7ff5b1b3dcc55b8ab8ae61ef99d4730940856ee7", + "url": "https://api.github.com/repos/Behat/Transliterator/zipball/826ce7e9c2a6664c0d1f381cbb38b1fb80a7ee2c", + "reference": "826ce7e9c2a6664c0d1f381cbb38b1fb80a7ee2c", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "chuyskywalker/rolling-curl": "^3.1", + "php-yaoi/php-yaoi": "^1.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": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Transliterator": "src/" } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Artistic-1.0" ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-01-28 05:39:29" + "description": "String transliterator", + "keywords": [ + "i18n", + "slug", + "transliterator" + ], + "time": "2017-04-04 11:38:05" }, { - "name": "sebastian/version", - "version": "1.0.6", + "name": "container-interop/container-interop", + "version": "1.2.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + "url": "https://github.com/container-interop/container-interop.git", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", "shasum": "" }, + "require": { + "psr/container": "^1.0" + }, "type": "library", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } + "MIT" ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21 13:59:46" + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "homepage": "https://github.com/container-interop/container-interop", + "time": "2017-02-14 19:40:03" }, { - "name": "sentry/sentry", - "version": "dev-master", + "name": "doctrine/instantiator", + "version": "1.0.5", "source": { "type": "git", - "url": "https://github.com/getsentry/sentry-php.git", - "reference": "2a92076ffc6c3f193f2736c9ce75d26705bb48b7" + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/2a92076ffc6c3f193f2736c9ce75d26705bb48b7", - "reference": "2a92076ffc6c3f193f2736c9ce75d26705bb48b7", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", "shasum": "" }, "require": { - "ext-curl": "*", - "monolog/monolog": "*", - "php": ">=5.2.4" - }, - "conflict": { - "raven/raven": "*" + "php": ">=5.3,<8.0-DEV" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^1.8.0", - "phpunit/phpunit": "^4.8 || ^5.0" + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" }, - "bin": [ - "bin/sentry" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "psr-0": { - "Raven_": "lib/" + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "David Cramer", - "email": "dcramer@gmail.com" + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" } ], - "description": "A PHP client for Sentry (http://getsentry.com)", - "homepage": "http://getsentry.com", + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", "keywords": [ - "log", - "logging" + "constructor", + "instantiate" ], - "time": "2016-11-01 18:46:47" + "time": "2015-06-14 21:17:01" }, { - "name": "swiftmailer/swiftmailer", - "version": "v4.3.1", + "name": "fabpot/goutte", + "version": "v3.2.1", "source": { "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "ae540bed1079c07aa12e9e62d9d8d4fc49bbdff2" + "url": "https://github.com/FriendsOfPHP/Goutte.git", + "reference": "db5c28f4a010b4161d507d5304e28a7ebf211638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/ae540bed1079c07aa12e9e62d9d8d4fc49bbdff2", - "reference": "ae540bed1079c07aa12e9e62d9d8d4fc49bbdff2", + "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/db5c28f4a010b4161d507d5304e28a7ebf211638", + "reference": "db5c28f4a010b4161d507d5304e28a7ebf211638", "shasum": "" }, "require": { - "php": ">=5.2.4" + "guzzlehttp/guzzle": "^6.0", + "php": ">=5.5.0", + "symfony/browser-kit": "~2.1|~3.0", + "symfony/css-selector": "~2.1|~3.0", + "symfony/dom-crawler": "~2.1|~3.0" }, - "type": "library", + "type": "application", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.2-dev" } }, "autoload": { - "files": [ - "lib/swift_required.php" - ] + "psr-4": { + "Goutte\\": "Goutte" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL" + "MIT" ], "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Chris Corbyn" + "email": "fabien@symfony.com" } ], - "description": "Swiftmailer, free feature-rich PHP mailer", - "homepage": "http://swiftmailer.org", + "description": "A simple PHP Web Scraper", + "homepage": "https://github.com/FriendsOfPHP/Goutte", "keywords": [ - "mail", - "mailer" + "scraper" ], - "time": "2013-04-11 10:22:09" + "time": "2017-01-03 13:21:43" }, { - "name": "symfony/config", - "version": "2.6.x-dev", - "target-dir": "Symfony/Component/Config", + "name": "fzaninotto/faker", + "version": "v1.6.0", "source": { "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "0ca496cbe208fc37c4cf3415ebb3056e0963115b" + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/0ca496cbe208fc37c4cf3415ebb3056e0963115b", - "reference": "0ca496cbe208fc37c4cf3415ebb3056e0963115b", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/filesystem": "~2.3" + "php": "^5.3.3|^7.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7" + "ext-intl": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } + "branch-alias": [] }, "autoload": { - "psr-0": { - "Symfony\\Component\\Config\\": "" + "psr-4": { + "Faker\\": "src/Faker/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3195,56 +3490,96 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2016-04-29 12:21:54" + }, + { + "name": "heroku/heroku-buildpack-php", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/heroku/heroku-buildpack-php.git", + "reference": "727aa850a02a7af94c9225237464be8e8c8ff6db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/heroku/heroku-buildpack-php/zipball/727aa850a02a7af94c9225237464be8e8c8ff6db", + "reference": "727aa850a02a7af94c9225237464be8e8c8ff6db", + "shasum": "" + }, + "bin": [ + "bin/heroku-hhvm-apache2", + "bin/heroku-hhvm-nginx", + "bin/heroku-php-apache2", + "bin/heroku-php-nginx" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "David Zuelke", + "email": "dz@heroku.com" } ], - "description": "Symfony Config Component", - "homepage": "https://symfony.com", - "time": "2015-07-08 05:59:48" + "description": "Toolkit for starting a PHP application locally, with or without foreman, using the same config for PHP/HHVM and Apache2/Nginx as on Heroku", + "homepage": "https://github.com/heroku/heroku-buildpack-php", + "keywords": [ + "apache", + "apache2", + "foreman", + "heroku", + "hhvm", + "nginx", + "php" + ], + "time": "2017-03-27 23:33:27" }, { - "name": "symfony/console", - "version": "2.6.x-dev", - "target-dir": "Symfony/Component/Console", + "name": "laravel/homestead", + "version": "v5.2.4", "source": { "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "0e5e18ae09d3f5c06367759be940e9ed3f568359" + "url": "https://github.com/laravel/homestead.git", + "reference": "77f1f01f6ec504c7f3adcb220d73c831a8dcc2bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0e5e18ae09d3f5c06367759be940e9ed3f568359", - "reference": "0e5e18ae09d3f5c06367759be940e9ed3f568359", + "url": "https://api.github.com/repos/laravel/homestead/zipball/77f1f01f6ec504c7f3adcb220d73c831a8dcc2bb", + "reference": "77f1f01f6ec504c7f3adcb220d73c831a8dcc2bb", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.6 || ^7.0", + "symfony/console": "~2.3|~3.0", + "symfony/process": "~2.3|~3.0", + "symfony/yaml": "~2.3|~3.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1", - "symfony/phpunit-bridge": "~2.7", - "symfony/process": "~2.1" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/process": "" + "phpunit/phpunit": "^5.7 || ^6.0" }, + "bin": [ + "bin/homestead" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "4.0-dev" } }, "autoload": { - "psr-0": { - "Symfony\\Component\\Console\\": "" + "psr-4": { + "Laravel\\Homestead\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3253,59 +3588,43 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" } ], - "description": "Symfony Console Component", - "homepage": "https://symfony.com", - "time": "2015-07-26 09:08:40" + "description": "A virtual machine for web artisans.", + "time": "2017-04-26 15:43:12" }, { - "name": "symfony/event-dispatcher", - "version": "2.8.x-dev", + "name": "leanphp/phpspec-code-coverage", + "version": "v3.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "2a6b8713f8bdb582058cfda463527f195b066110" + "url": "https://github.com/leanphp/phpspec-code-coverage.git", + "reference": "2f66eb6fbca15761e6029ded9dbe3e277c7093d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2a6b8713f8bdb582058cfda463527f195b066110", - "reference": "2a6b8713f8bdb582058cfda463527f195b066110", + "url": "https://api.github.com/repos/leanphp/phpspec-code-coverage/zipball/2f66eb6fbca15761e6029ded9dbe3e277c7093d6", + "reference": "2f66eb6fbca15761e6029ded9dbe3e277c7093d6", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": "~5.6||~7.0", + "phpspec/phpspec": "~3.0", + "phpunit/php-code-coverage": "~4.0||~5.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.0,>=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" + "bossa/phpspec2-expect": "~2.0" }, "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "ext-xdebug": "Install Xdebug to generate phpspec code coverage if you are not using phpdbg" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "LeanPHP\\PhpSpec\\CodeCoverage\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3313,97 +3632,107 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "ek9", + "email": "dev@ek9.co", + "homepage": "https://ek9.co" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Henrik Bjornskov" } ], - "description": "Symfony EventDispatcher Component", - "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "description": "Generate Code Coverage reports for PhpSpec tests", + "homepage": "https://github.com/leanphp/phpspec-code-coverage", + "keywords": [ + "build", + "clover", + "code", + "code-coverage", + "coverage", + "generate", + "generation", + "phpspec", + "report", + "reports", + "spec", + "test", + "tests" + ], + "time": "2017-02-21 02:54:14" }, { - "name": "symfony/filesystem", - "version": "2.8.x-dev", + "name": "myclabs/deep-copy", + "version": "1.6.1", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "dee379131dceed90a429e951546b33edfe7dccbb" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb", - "reference": "dee379131dceed90a429e951546b33edfe7dccbb", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102", + "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.4.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" }, + "type": "library", "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" + "DeepCopy\\": "src/DeepCopy/" } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], - "description": "Symfony Filesystem Component", - "homepage": "https://symfony.com", - "time": "2016-04-12 18:01:21" + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-04-12 18:52:22" }, { - "name": "symfony/finder", - "version": "2.8.x-dev", + "name": "phpdocumentor/reflection-common", + "version": "1.0", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "cad8e7020cb8d1756cced64b1b48d7b176c9f366" + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/cad8e7020cb8d1756cced64b1b48d7b176c9f366", - "reference": "cad8e7020cb8d1756cced64b1b48d7b176c9f366", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "phpDocumentor\\Reflection\\": [ + "src" + ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3411,48 +3740,52 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" } ], - "description": "Symfony Finder Component", - "homepage": "https://symfony.com", - "time": "2016-06-21 05:36:02" + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27 11:43:31" }, { - "name": "symfony/process", - "version": "2.8.x-dev", + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.1", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "b3f638531fa1890f8db3010a2b98a33f1a6528b9" + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/b3f638531fa1890f8db3010a2b98a33f1a6528b9", - "reference": "b3f638531fa1890f8db3010a2b98a33f1a6528b9", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" }, + "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3460,48 +3793,47 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Mike van Riel", + "email": "me@mikevanriel.com" } ], - "description": "Symfony Process Component", - "homepage": "https://symfony.com", - "time": "2016-06-21 05:36:02" + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-09-30 07:12:33" }, { - "name": "symfony/property-access", - "version": "2.8.x-dev", + "name": "phpdocumentor/type-resolver", + "version": "0.2.1", "source": { "type": "git", - "url": "https://github.com/symfony/property-access.git", - "reference": "c1a556ab664b5f96a7d604d1d6337068f16d6a25" + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/c1a556ab664b5f96a7d604d1d6337068f16d6a25", - "reference": "c1a556ab664b5f96a7d604d1d6337068f16d6a25", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\PropertyAccess\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3509,108 +3841,98 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Mike van Riel", + "email": "me@mikevanriel.com" } ], - "description": "Symfony PropertyAccess Component", - "homepage": "https://symfony.com", - "keywords": [ - "access", - "array", - "extraction", - "index", - "injection", - "object", - "property", - "property path", - "reflection" - ], - "time": "2016-06-16 05:02:45" + "time": "2016-11-25 06:54:22" }, { - "name": "symfony/stopwatch", - "version": "dev-master", + "name": "phpspec/php-diff", + "version": "v1.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "4d61f33aeb537eba5b2ec8ae1a49ac617ee896d8" + "url": "https://github.com/phpspec/php-diff.git", + "reference": "0464787bfa7cd13576c5a1e318709768798bec6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/4d61f33aeb537eba5b2ec8ae1a49ac617ee896d8", - "reference": "4d61f33aeb537eba5b2ec8ae1a49ac617ee896d8", + "url": "https://api.github.com/repos/phpspec/php-diff/zipball/0464787bfa7cd13576c5a1e318709768798bec6a", + "reference": "0464787bfa7cd13576c5a1e318709768798bec6a", "shasum": "" }, - "require": { - "php": ">=5.5.9" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "psr-0": { + "Diff": "lib/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Chris Boulton", + "homepage": "http://github.com/chrisboulton" } ], - "description": "Symfony Stopwatch Component", - "homepage": "https://symfony.com", - "time": "2016-06-06 11:53:30" + "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", + "time": "2016-04-07 12:29:16" }, { - "name": "symfony/yaml", - "version": "2.6.x-dev", - "target-dir": "Symfony/Component/Yaml", + "name": "phpspec/phpspec", + "version": "3.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/Yaml.git", - "reference": "c044d1744b8e91aaaa0d9bac683ab87ec7cbf359" + "url": "https://github.com/phpspec/phpspec.git", + "reference": "1c77d11878c4bd475bc66f0eaa2686df0fcfa30f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/c044d1744b8e91aaaa0d9bac683ab87ec7cbf359", - "reference": "c044d1744b8e91aaaa0d9bac683ab87ec7cbf359", + "url": "https://api.github.com/repos/phpspec/phpspec/zipball/1c77d11878c4bd475bc66f0eaa2686df0fcfa30f", + "reference": "1c77d11878c4bd475bc66f0eaa2686df0fcfa30f", "shasum": "" }, "require": { - "php": ">=5.3.3" + "doctrine/instantiator": "^1.0.1", + "ext-tokenizer": "*", + "php": "^5.6 || ^7.0", + "phpspec/php-diff": "^1.0.0", + "phpspec/prophecy": "^1.5", + "sebastian/exporter": "^1.0 || ^2.0 || ^3.0", + "symfony/console": "^2.7 || ^3.0", + "symfony/event-dispatcher": "^2.7 || ^3.0", + "symfony/finder": "^2.7 || ^3.0", + "symfony/process": "^2.7 || ^3.0", + "symfony/yaml": "^2.7 || ^3.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7" + "behat/behat": "^3.3", + "ciaranmcnulty/versionbasedtestskipper": "^0.2.1", + "phpunit/phpunit": "^5.5|^6.0", + "symfony/filesystem": "^3.0" }, + "suggest": { + "phpspec/nyan-formatters": "Adds Nyan formatters" + }, + "bin": [ + "bin/phpspec" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { "psr-0": { - "Symfony\\Component\\Yaml\\": "" + "PhpSpec": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3619,178 +3941,243 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Marcello Duarte", + "homepage": "http://marcelloduarte.net/" + }, + { + "name": "Ciaran McNulty", + "homepage": "https://ciaranmcnulty.com/" } ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2015-07-26 08:59:42" + "description": "Specification-oriented BDD framework for PHP 5.6+", + "homepage": "http://phpspec.net/", + "keywords": [ + "BDD", + "SpecBDD", + "TDD", + "spec", + "specification", + "testing", + "tests" + ], + "time": "2017-04-27 12:40:39" }, { - "name": "symm/gisconverter", - "version": "dev-master", + "name": "phpspec/prophecy", + "version": "v1.7.0", "source": { "type": "git", - "url": "https://github.com/symm/gisconverter.git", - "reference": "b5c82ef2373bca0ecb92e6bb61f2222b883d1afa" + "url": "https://github.com/phpspec/prophecy.git", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symm/gisconverter/zipball/b5c82ef2373bca0ecb92e6bb61f2222b883d1afa", - "reference": "b5c82ef2373bca0ecb92e6bb61f2222b883d1afa", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", "shasum": "" }, "require": { - "php": ">=5.3.0" + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1|^2.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { - "phpunit/phpunit": "3.7.*" + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8 || ^5.6.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { "psr-0": { - "Symm\\Gisconverter": "src/" + "Prophecy\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "MIT" ], - "description": "A php library to convert vector geometries between different formats", - "time": "2014-08-07 14:02:42" + "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": "2017-03-02 20:05:34" }, { - "name": "true/punycode", - "version": "v2.0.3", + "name": "phpunit/dbunit", + "version": "1.4.1", "source": { "type": "git", - "url": "https://github.com/true/php-punycode.git", - "reference": "6853ce218b6115ec749607e14ac51338920c9d81" + "url": "https://github.com/sebastianbergmann/dbunit.git", + "reference": "9aaee6447663ff1b0cd50c23637e04af74c5e2ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/true/php-punycode/zipball/6853ce218b6115ec749607e14ac51338920c9d81", - "reference": "6853ce218b6115ec749607e14ac51338920c9d81", + "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/9aaee6447663ff1b0cd50c23637e04af74c5e2ae", + "reference": "9aaee6447663ff1b0cd50c23637e04af74c5e2ae", "shasum": "" }, - "require": { - "ext-mbstring": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.7", - "squizlabs/php_codesniffer": "~2.0" - }, + "require": { + "ext-pdo": "*", + "ext-simplexml": "*", + "php": ">=5.3.3", + "phpunit/phpunit": "~4|~5", + "symfony/yaml": "~2.1|~3.0" + }, + "bin": [ + "composer/bin/dbunit" + ], "type": "library", - "autoload": { - "psr-4": { - "TrueBV\\": "src/" + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" } }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Renan Gonçalves", - "email": "renan.saddam@gmail.com" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)", - "homepage": "https://github.com/true/php-punycode", + "description": "DbUnit port for PHP/PHPUnit to support database interaction testing.", + "homepage": "https://github.com/sebastianbergmann/dbunit/", "keywords": [ - "idna", - "punycode" + "database", + "testing", + "xunit" ], - "time": "2016-05-23 08:20:50" + "time": "2015-08-07 04:57:38" }, { - "name": "twilio/sdk", - "version": "3.12.8", + "name": "phpunit/php-code-coverage", + "version": "4.0.8", "source": { "type": "git", - "url": "https://github.com/twilio/twilio-php.git", - "reference": "9d8bb7dad58dc52fc4cbc1f0e905950ad839ca73" + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twilio/twilio-php/zipball/9d8bb7dad58dc52fc4cbc1f0e905950ad839ca73", - "reference": "9d8bb7dad58dc52fc4cbc1f0e905950ad839ca73", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", "shasum": "" }, "require": { - "php": ">=5.2.1" + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "^1.3", + "phpunit/php-text-template": "^1.2", + "phpunit/php-token-stream": "^1.4.2 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "^1.0 || ^2.0" }, "require-dev": { - "mockery/mockery": ">=0.7.2", - "phpunit/phpunit": "3.7.*" + "ext-xdebug": "^2.1.4", + "phpunit/phpunit": "^5.7" + }, + "suggest": { + "ext-xdebug": "^2.5.1" }, "type": "library", - "autoload": { - "psr-0": { - "Services_Twilio": "" + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Kevin Burke", - "email": "kevin@twilio.com" - }, - { - "name": "Kyle Conroy", - "email": "kyle+pear@twilio.com" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "A PHP wrapper for Twilio's API", - "homepage": "http://github.com/twilio/twilio-php", + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", "keywords": [ - "api", - "sms", - "twilio" + "coverage", + "testing", + "xunit" ], - "time": "2014-12-04 19:17:59" + "time": "2017-04-02 07:44:40" }, { - "name": "ushahidi/shadowhand-email", - "version": "dev-master", + "name": "phpunit/php-file-iterator", + "version": "1.4.2", "source": { "type": "git", - "url": "https://github.com/ushahidi/shadowhand-email.git", - "reference": "51274cdd899d0c619368c9580146bd05b461a03f" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ushahidi/shadowhand-email/zipball/51274cdd899d0c619368c9580146bd05b461a03f", - "reference": "51274cdd899d0c619368c9580146bd05b461a03f", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", "shasum": "" }, "require": { - "kohana/core": "3.3.*", - "php": ">=5.3.0", - "swiftmailer/swiftmailer": "~4.3.1" + "php": ">=5.3.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, "autoload": { - "psr-4": { - "Shadowhand\\": "src/" - }, - "files": [ - "init.php" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3799,345 +4186,325 @@ ], "authors": [ { - "name": "Kohana Team", - "email": "team@kohanaframework.org", - "role": "creator" - }, - { - "name": "Robbie Mackay", - "email": "robbie@ushahidi.com", - "role": "maintainer" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "Email helper class, uses Swiftmailer", - "homepage": "http://github.com/ushahidi/shadowhand-email", + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ - "email", - "helper", - "kohana", - "library", - "module", - "ohanzee", - "swiftmailer" + "filesystem", + "iterator" ], - "time": "2017-03-22 00:35:17" + "time": "2016-10-03 07:40:28" }, { - "name": "vlucas/phpdotenv", - "version": "dev-master", + "name": "phpunit/php-text-template", + "version": "1.2.1", "source": { "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "ae388efe53a2c352ddd270f4d316bad58952b8e3" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/ae388efe53a2c352ddd270f4d316bad58952b8e3", - "reference": "ae388efe53a2c352ddd270f4d316bad58952b8e3", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "shasum": "" }, "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" + "php": ">=5.3.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, "autoload": { - "psr-0": { - "Dotenv": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "BSD-3-Clause" ], "authors": [ { - "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "http://www.vancelucas.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", - "homepage": "http://github.com/vlucas/phpdotenv", + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ - "dotenv", - "env", - "environment" + "template" ], - "time": "2015-02-19 20:37:05" + "time": "2015-06-21 13:50:34" }, { - "name": "webmozart/assert", - "version": "dev-master", + "name": "phpunit/php-timer", + "version": "1.0.9", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "3a8e045064f294992a13966b6c892fb9d64853a3" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/3a8e045064f294992a13966b6c892fb9d64853a3", - "reference": "3a8e045064f294992a13966b6c892fb9d64853a3", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", "shasum": "" }, "require": { - "php": "^5.3.3|^7.0" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.0-dev" } }, "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "Assertions to validate method input/output with nice error messages.", + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ - "assert", - "check", - "validate" + "timer" ], - "time": "2016-03-04 13:27:44" + "time": "2017-02-26 11:10:40" }, { - "name": "zeelot/kohana-media", - "version": "dev-1.3/develop", + "name": "phpunit/php-token-stream", + "version": "1.4.11", "source": { "type": "git", - "url": "https://github.com/Zeelot/kohana-media.git", - "reference": "2f657c028d6c875017fd37d6b8d1fa3d2e3fe35e" + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Zeelot/kohana-media/zipball/2f657c028d6c875017fd37d6b8d1fa3d2e3fe35e", - "reference": "2f657c028d6c875017fd37d6b8d1fa3d2e3fe35e", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", "shasum": "" }, "require": { - "kohana/core": ">=3.3", + "ext-tokenizer": "*", "php": ">=5.3.3" }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, "type": "library", "extra": { "branch-alias": { - "dev-1.3/develop": "1.3.x-dev" + "dev-master": "1.4-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { - "name": "Lorenzo Pisani", - "email": "zeelot3k@gmail.com", - "homepage": "http://zeelot3k.com", - "role": "developer" - }, - { - "name": "Contributors", - "homepage": "https://github.com/Zeelot/kohana-media/graphs/contributors", - "role": "contributor" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Using the Kohana cascading file system to serve media assets", - "homepage": "https://github.com/Zeelot/kohana-media", + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", "keywords": [ - "assets", - "caching", - "cfs", - "files", - "framework", - "kohana", - "media" + "tokenizer" ], - "time": "2014-04-26 16:15:53" - } - ], - "packages-dev": [ + "time": "2017-02-27 10:12:30" + }, { - "name": "behat/behat", - "version": "2.5.x-dev", + "name": "phpunit/phpunit", + "version": "5.7.19", "source": { "type": "git", - "url": "https://github.com/Behat/Behat.git", - "reference": "ca8e6cf7b20585765801aa80dd11be4acbf5bfa7" + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Behat/zipball/ca8e6cf7b20585765801aa80dd11be4acbf5bfa7", - "reference": "ca8e6cf7b20585765801aa80dd11be4acbf5bfa7", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/69c4f49ff376af2692bad9cebd883d17ebaa98a1", + "reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1", "shasum": "" }, "require": { - "behat/gherkin": "~2.3.0", - "php": ">=5.3.1", - "symfony/config": "~2.3", - "symfony/console": "~2.0", - "symfony/dependency-injection": "~2.0", - "symfony/event-dispatcher": "~2.0", - "symfony/finder": "~2.0", - "symfony/translation": "~2.3", - "symfony/yaml": "~2.0" + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.6.2", + "phpunit/php-code-coverage": "^4.0.4", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "^1.2.4", + "sebastian/diff": "~1.2", + "sebastian/environment": "^1.3.4 || ^2.0", + "sebastian/exporter": "~2.0", + "sebastian/global-state": "^1.1", + "sebastian/object-enumerator": "~2.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "~1.0.3|~2.0", + "symfony/yaml": "~2.1|~3.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" }, "require-dev": { - "phpunit/phpunit": "~3.7.19" + "ext-pdo": "*" }, "suggest": { - "behat/mink-extension": "for integration with Mink testing framework", - "behat/symfony2-extension": "for integration with Symfony2 web framework", - "behat/yii-extension": "for integration with Yii web framework" + "ext-xdebug": "*", + "phpunit/php-invoker": "~1.1" }, "bin": [ - "bin/behat" + "phpunit" ], "type": "library", - "autoload": { - "psr-0": { - "Behat\\Behat": "src/" + "extra": { + "branch-alias": { + "dev-master": "5.7.x-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Scenario-oriented BDD framework for PHP 5.3", - "homepage": "http://behat.org/", + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", "keywords": [ - "BDD", - "Behat", - "Symfony2" + "phpunit", + "testing", + "xunit" ], - "time": "2015-12-30 11:55:42" + "time": "2017-04-03 02:22:27" }, { - "name": "behat/gherkin", - "version": "2.3.x-dev", + "name": "phpunit/phpunit-mock-objects", + "version": "3.4.3", "source": { "type": "git", - "url": "https://github.com/Behat/Gherkin.git", - "reference": "c32e15d92e1a2ce399a1a1c5be7afd965176e86c" + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/c32e15d92e1a2ce399a1a1c5be7afd965176e86c", - "reference": "c32e15d92e1a2ce399a1a1c5be7afd965176e86c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", + "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", "shasum": "" }, "require": { - "php": ">=5.3.1", - "symfony/finder": "~2.0" + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2 || ^2.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" }, "require-dev": { - "symfony/config": "~2.0", - "symfony/translation": "~2.0", - "symfony/yaml": "~2.0" + "phpunit/phpunit": "^5.4" }, "suggest": { - "symfony/config": "If you want to use Config component to manage resources", - "symfony/translation": "If you want to use Symfony2 translations adapter", - "symfony/yaml": "If you want to parse features, represented in YAML files" + "ext-soap": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-develop": "2.2-dev" + "dev-master": "3.2.x-dev" } }, "autoload": { - "psr-0": { - "Behat\\Gherkin": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "Gherkin DSL parser for PHP 5.3", - "homepage": "http://behat.org/", + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", "keywords": [ - "BDD", - "Behat", - "DSL", - "Symfony2", - "parser" + "mock", + "xunit" ], - "time": "2014-06-06 00:48:18" + "time": "2016-12-08 20:27:08" }, { - "name": "behat/mink", - "version": "dev-master", + "name": "psr/container", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/minkphp/Mink.git", - "reference": "a88582ed857ea9792519e723b73d40a399e2a221" + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/minkphp/Mink/zipball/a88582ed857ea9792519e723b73d40a399e2a221", - "reference": "a88582ed857ea9792519e723b73d40a399e2a221", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", "shasum": "" }, "require": { - "php": ">=5.3.1", - "symfony/css-selector": "~2.1|~3.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "~2.7|~3.0" - }, - "suggest": { - "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)", - "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation", - "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)", - "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)" + "php": ">=5.3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Behat\\Mink\\": "src/" + "Psr\\Container\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4146,53 +4513,61 @@ ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Browser controller/emulator abstraction for PHP", - "homepage": "http://mink.behat.org/", + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", "keywords": [ - "browser", - "testing", - "web" + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" ], - "time": "2016-03-21 10:12:43" + "time": "2017-02-14 16:28:37" }, { - "name": "behat/mink-browserkit-driver", + "name": "satooshi/php-coveralls", "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/minkphp/MinkBrowserKitDriver.git", - "reference": "81ff645ec09b95d4daf1193542b3dd2e5984af2e" + "url": "https://github.com/satooshi/php-coveralls.git", + "reference": "d7285decc88dff59c5ff02c4b1052ab424ba7fa5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/81ff645ec09b95d4daf1193542b3dd2e5984af2e", - "reference": "81ff645ec09b95d4daf1193542b3dd2e5984af2e", + "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/d7285decc88dff59c5ff02c4b1052ab424ba7fa5", + "reference": "d7285decc88dff59c5ff02c4b1052ab424ba7fa5", "shasum": "" }, "require": { - "behat/mink": "^1.7.1@dev", - "php": ">=5.3.6", - "symfony/browser-kit": "~2.3|~3.0", - "symfony/dom-crawler": "~2.3|~3.0" + "ext-json": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^6.0", + "php": "^5.5 || ^7.0", + "psr/log": "^1.0", + "symfony/config": "^2.1 || ^3.0", + "symfony/console": "^2.1 || ^3.0", + "symfony/stopwatch": "^2.0 || ^3.0", + "symfony/yaml": "^2.0 || ^3.0" }, - "require-dev": { - "silex/silex": "~1.2", - "symfony/phpunit-bridge": "~2.7|~3.0" + "suggest": { + "symfony/http-kernel": "Allows Symfony integration" }, - "type": "mink-driver", + "bin": [ + "bin/coveralls" + ], + "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { "psr-4": { - "Behat\\Mink\\Driver\\": "src/" + "Satooshi\\": "src/Satooshi/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4201,362 +4576,377 @@ ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "name": "Kitamura Satoshi", + "email": "with.no.parachute@gmail.com", + "homepage": "https://www.facebook.com/satooshi.jp" } ], - "description": "Symfony2 BrowserKit driver for Mink framework", - "homepage": "http://mink.behat.org/", + "description": "PHP client library for Coveralls API", + "homepage": "https://github.com/satooshi/php-coveralls", "keywords": [ - "Mink", - "Symfony2", - "browser", - "testing" + "ci", + "coverage", + "github", + "test" ], - "time": "2016-04-11 09:16:06" + "time": "2017-03-31 10:12:47" }, { - "name": "behat/mink-extension", - "version": "1.3.x-dev", + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/Behat/MinkExtension.git", - "reference": "dddddf73ec965ec9deb631b97a25b1004a14ddf6" + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/MinkExtension/zipball/dddddf73ec965ec9deb631b97a25b1004a14ddf6", - "reference": "dddddf73ec965ec9deb631b97a25b1004a14ddf6", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", "shasum": "" }, "require": { - "behat/behat": "~2.5.0", - "behat/mink": "~1.5", - "php": ">=5.3.2", - "symfony/config": "~2.2" + "php": "^5.6 || ^7.0" }, "require-dev": { - "behat/mink-goutte-driver": "~1.0", - "fabpot/goutte": "~1.0" + "phpunit/phpunit": "^5.7 || ^6.0" }, - "type": "behat-extension", - "autoload": { - "psr-0": { - "Behat\\MinkExtension": "src/" + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Mink extension for Behat", - "homepage": "http://mink.behat.org", - "keywords": [ - "browser", - "gui", - "test", - "web" - ], - "time": "2015-03-02 10:45:50" + "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-04 06:30:41" }, { - "name": "behat/mink-goutte-driver", - "version": "dev-master", + "name": "sebastian/comparator", + "version": "1.2.4", "source": { "type": "git", - "url": "https://github.com/minkphp/MinkGoutteDriver.git", - "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca" + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkGoutteDriver/zipball/8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", - "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", "shasum": "" }, "require": { - "behat/mink": "~1.6@dev", - "behat/mink-browserkit-driver": "~1.2@dev", - "fabpot/goutte": "~1.0.4|~2.0|~3.1", - "php": ">=5.3.1" + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7|~3.0" + "phpunit/phpunit": "~4.4" }, - "type": "mink-driver", + "type": "library", "extra": { "branch-alias": { "dev-master": "1.2.x-dev" } }, "autoload": { - "psr-4": { - "Behat\\Mink\\Driver\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "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": "Goutte driver for Mink framework", - "homepage": "http://mink.behat.org/", + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", "keywords": [ - "browser", - "goutte", - "headless", - "testing" + "comparator", + "compare", + "equality" ], - "time": "2016-03-05 09:04:22" + "time": "2017-01-29 09:50:25" }, { - "name": "fabpot/goutte", - "version": "1.0.x-dev", + "name": "sebastian/diff", + "version": "1.4.1", "source": { "type": "git", - "url": "https://github.com/FriendsOfPHP/Goutte.git", - "reference": "794b196e76bdd37b5155cdecbad311f0a3b07625" + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/794b196e76bdd37b5155cdecbad311f0a3b07625", - "reference": "794b196e76bdd37b5155cdecbad311f0a3b07625", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", "shasum": "" }, "require": { - "ext-curl": "*", - "guzzle/http": "~3.1", - "php": ">=5.3.0", - "symfony/browser-kit": "~2.1", - "symfony/css-selector": "~2.1", - "symfony/dom-crawler": "~2.1", - "symfony/finder": "~2.1", - "symfony/process": "~2.1" + "php": ">=5.3.3" }, "require-dev": { - "guzzle/plugin-history": "~3.1", - "guzzle/plugin-mock": "~3.1" + "phpunit/phpunit": "~4.8" }, - "type": "application", + "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.4-dev" } }, "autoload": { - "psr-0": { - "Goutte": "." - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "A simple PHP Web Scraper", - "homepage": "https://github.com/fabpot/Goutte", + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "scraper" + "diff" ], - "time": "2014-10-09 15:52:51" + "time": "2015-12-08 07:14:41" }, { - "name": "heroku/heroku-buildpack-php", - "version": "dev-master", + "name": "sebastian/environment", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/heroku/heroku-buildpack-php.git", - "reference": "118cfbb3e6940bd6c1a953b0c482f458582162a6" + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/heroku/heroku-buildpack-php/zipball/118cfbb3e6940bd6c1a953b0c482f458582162a6", - "reference": "118cfbb3e6940bd6c1a953b0c482f458582162a6", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", "shasum": "" }, - "bin": [ - "bin/heroku-hhvm-apache2", - "bin/heroku-hhvm-nginx", - "bin/heroku-php-apache2", - "bin/heroku-php-nginx" - ], + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "David Zuelke", - "email": "dz@heroku.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Toolkit for starting a PHP application locally, with or without foreman, using the same config for PHP/HHVM and Apache2/Nginx as on Heroku", - "homepage": "https://github.com/heroku/heroku-buildpack-php", + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", "keywords": [ - "apache", - "apache2", - "foreman", - "heroku", - "hhvm", - "nginx", - "php" + "Xdebug", + "environment", + "hhvm" ], - "time": "2016-06-17 22:36:40" + "time": "2016-11-26 07:53:53" }, { - "name": "kohana/unittest", - "version": "dev-3.3/develop", + "name": "sebastian/exporter", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/kohana/unittest.git", - "reference": "d7cf45cd5570cb6f5bb2f3788862f999382c4d5a" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kohana/unittest/zipball/d7cf45cd5570cb6f5bb2f3788862f999382c4d5a", - "reference": "d7cf45cd5570cb6f5bb2f3788862f999382c4d5a", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", "shasum": "" }, "require": { - "composer/installers": "~1.0", - "kohana/core": ">=3.3", "php": ">=5.3.3", - "phpunit/phpunit": "3.7.24 - 4" + "sebastian/recursion-context": "~2.0" }, "require-dev": { - "kohana/core": "3.3.*@dev", - "kohana/koharness": "*@dev" + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" }, - "type": "kohana-module", + "type": "library", "extra": { "branch-alias": { - "dev-3.3/develop": "3.3.x-dev", - "dev-3.4/develop": "3.4.x-dev" - }, - "installer-paths": { - "vendor/{$vendor}/{$name}": [ - "type:kohana-module" - ] + "dev-master": "2.0.x-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { - "name": "Kohana Team", - "email": "team@kohanaframework.org", - "homepage": "http://kohanaframework.org/team", - "role": "developer" + "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": "PHPUnit integration for running unit tests on the Kohana framework", - "homepage": "http://kohanaframework.org", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", "keywords": [ - "framework", - "kohana" + "export", + "exporter" ], - "time": "2016-03-23 17:13:51" + "time": "2016-11-19 08:54:04" }, { - "name": "phpunit/dbunit", - "version": "1.4.x-dev", + "name": "sebastian/global-state", + "version": "1.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/dbunit.git", - "reference": "5d65dc3fd9463a57d4660179dadc5a3a1b604811" + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/5d65dc3fd9463a57d4660179dadc5a3a1b604811", - "reference": "5d65dc3fd9463a57d4660179dadc5a3a1b604811", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", "shasum": "" }, "require": { - "ext-pdo": "*", - "ext-simplexml": "*", - "php": ">=5.3.3", - "phpunit/phpunit": "~4|~5", - "symfony/yaml": "~2.1|~3.0" + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" }, - "bin": [ - "composer/bin/dbunit" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "1.0-dev" } }, "autoload": { "classmap": [ - "PHPUnit/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "", - "../../symfony/yaml/" - ], "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "DbUnit port for PHP/PHPUnit to support database interaction testing.", - "homepage": "https://github.com/sebastianbergmann/dbunit/", + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ - "database", - "testing", - "xunit" + "global state" ], - "time": "2015-08-07 17:26:36" + "time": "2015-10-12 03:26:01" }, { - "name": "phpunit/php-timer", - "version": "1.0.8", + "name": "sebastian/object-enumerator", + "version": "2.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.6", + "sebastian/recursion-context": "~2.0" }, "require-dev": { - "phpunit/phpunit": "~4|~5" + "phpunit/phpunit": "~5" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -4569,62 +4959,37 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2016-05-12 18:03:57" + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-02-18 15:18:39" }, { - "name": "phpunit/phpunit", - "version": "4.8.x-dev", + "name": "sebastian/recursion-context", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b9cf8c5ff8bc658bebf8e9a5473fc513c38473de" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b9cf8c5ff8bc658bebf8e9a5473fc513c38473de", - "reference": "b9cf8c5ff8bc658bebf8e9a5473fc513c38473de", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.1", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" + "php": ">=5.3.3" }, - "suggest": { - "phpunit/php-invoker": "~1.1" + "require-dev": { + "phpunit/phpunit": "~4.4" }, - "bin": [ - "phpunit" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.8.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -4637,51 +5002,44 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2016-06-17 15:17:43" + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-11-19 07:33:16" }, { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.x-dev", + "name": "sebastian/resource-operations", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "suggest": { - "ext-soap": "*" + "php": ">=5.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -4696,45 +5054,34 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2015-10-02 06:51:40" + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28 20:34:47" }, { - "name": "sebastian/global-state", - "version": "1.1.1", + "name": "sebastian/version", + "version": "2.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" }, - "suggest": { - "ext-uopz": "*" + "require": { + "php": ">=5.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -4749,73 +5096,47 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2015-10-12 03:26:01" + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03 07:35:21" }, { "name": "squizlabs/php_codesniffer", - "version": "1.5.x-dev", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "6f3e42d311b882b25b4d409d23a289f4d3b803d5" + "reference": "b95ff2c3b122a3ee4b57d149a57d2afce65522c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6f3e42d311b882b25b4d409d23a289f4d3b803d5", - "reference": "6f3e42d311b882b25b4d409d23a289f4d3b803d5", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/b95ff2c3b122a3ee4b57d149a57d2afce65522c3", + "reference": "b95ff2c3b122a3ee4b57d149a57d2afce65522c3", "shasum": "" }, "require": { + "ext-simplexml": "*", "ext-tokenizer": "*", - "php": ">=5.1.2" + "ext-xmlwriter": "*", + "php": ">=5.4.0" }, - "suggest": { - "phpunit/php-timer": "dev-master" + "require-dev": { + "phpunit/phpunit": "~4.0" }, "bin": [ - "scripts/phpcs" + "bin/phpcs", + "bin/phpcbf" ], "type": "library", "extra": { "branch-alias": { - "dev-phpcs-fixer": "2.0.x-dev" + "dev-master": "3.x-dev" } }, - "autoload": { - "classmap": [ - "CodeSniffer.php", - "CodeSniffer/CLI.php", - "CodeSniffer/Exception.php", - "CodeSniffer/File.php", - "CodeSniffer/Report.php", - "CodeSniffer/Reporting.php", - "CodeSniffer/Sniff.php", - "CodeSniffer/Tokens.php", - "CodeSniffer/Reports/", - "CodeSniffer/CommentParser/", - "CodeSniffer/Tokenizers/", - "CodeSniffer/DocGenerators/", - "CodeSniffer/Standards/AbstractPatternSniff.php", - "CodeSniffer/Standards/AbstractScopeSniff.php", - "CodeSniffer/Standards/AbstractVariableSniff.php", - "CodeSniffer/Standards/IncorrectPatternException.php", - "CodeSniffer/Standards/Generic/Sniffs/", - "CodeSniffer/Standards/MySource/Sniffs/", - "CodeSniffer/Standards/PEAR/Sniffs/", - "CodeSniffer/Standards/PSR1/Sniffs/", - "CodeSniffer/Standards/PSR2/Sniffs/", - "CodeSniffer/Standards/Squiz/Sniffs/", - "CodeSniffer/Standards/Zend/Sniffs/" - ] - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -4826,35 +5147,35 @@ "role": "lead" } ], - "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "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": "2014-12-04 22:32:15" + "time": "2017-05-04 00:33:04" }, { "name": "symfony/browser-kit", - "version": "2.8.x-dev", + "version": "v3.2.8", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "2508ecbfc98b007bc1b670cef40ff821b827c61c" + "reference": "9fab1ab6f77b77f3df5fc5250fc6956811699b57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2508ecbfc98b007bc1b670cef40ff821b827c61c", - "reference": "2508ecbfc98b007bc1b670cef40ff821b827c61c", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/9fab1ab6f77b77f3df5fc5250fc6956811699b57", + "reference": "9fab1ab6f77b77f3df5fc5250fc6956811699b57", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/dom-crawler": "~2.1|~3.0.0" + "php": ">=5.5.9", + "symfony/dom-crawler": "~2.8|~3.0" }, "require-dev": { - "symfony/css-selector": "~2.0,>=2.0.5|~3.0.0", - "symfony/process": "~2.3.34|~2.7,>=2.7.6|~3.0.0" + "symfony/css-selector": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" }, "suggest": { "symfony/process": "" @@ -4862,7 +5183,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -4889,29 +5210,85 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2016-06-06 15:06:25" + "time": "2017-04-12 14:13:17" + }, + { + "name": "symfony/class-loader", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/class-loader.git", + "reference": "fc4c04bfd17130a9dccfded9578353f311967da7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/fc4c04bfd17130a9dccfded9578353f311967da7", + "reference": "fc4c04bfd17130a9dccfded9578353f311967da7", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "symfony/finder": "~2.8|~3.0", + "symfony/polyfill-apcu": "~1.1" + }, + "suggest": { + "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ClassLoader\\": "" + }, + "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 ClassLoader Component", + "homepage": "https://symfony.com", + "time": "2017-04-12 14:13:17" }, { "name": "symfony/css-selector", - "version": "2.8.x-dev", + "version": "v3.2.8", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "9a0b2649328297fb6acd0c823789d92efcbd36ad" + "reference": "02983c144038e697c959e6b06ef6666de759ccbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/9a0b2649328297fb6acd0c823789d92efcbd36ad", - "reference": "9a0b2649328297fb6acd0c823789d92efcbd36ad", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/02983c144038e697c959e6b06ef6666de759ccbc", + "reference": "02983c144038e697c959e6b06ef6666de759ccbc", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -4942,32 +5319,32 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "time": "2017-05-01 14:55:58" }, { "name": "symfony/dependency-injection", - "version": "2.8.x-dev", + "version": "v3.2.8", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "989e033112124943106098f65fa71f372d10c2bb" + "reference": "5e00857475b6d1fa31ff4c76f1fddf1cfa9e8d59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/989e033112124943106098f65fa71f372d10c2bb", - "reference": "989e033112124943106098f65fa71f372d10c2bb", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5e00857475b6d1fa31ff4c76f1fddf1cfa9e8d59", + "reference": "5e00857475b6d1fa31ff4c76f1fddf1cfa9e8d59", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9" }, "conflict": { - "symfony/expression-language": "<2.6" + "symfony/yaml": "<3.2" }, "require-dev": { - "symfony/config": "~2.2|~3.0.0", - "symfony/expression-language": "~2.6|~3.0.0", - "symfony/yaml": "~2.1|~3.0.0" + "symfony/config": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/yaml": "~3.2" }, "suggest": { "symfony/config": "", @@ -4978,7 +5355,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -5005,28 +5382,28 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-06-21 05:43:49" + "time": "2017-04-26 01:39:17" }, { "name": "symfony/dom-crawler", - "version": "2.8.x-dev", + "version": "v3.2.8", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "f282b08f6bbbc72e7af2e9e0c2f896221053f791" + "reference": "f1ad34e8af09ed17570e027cf0c58a12eddec286" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/f282b08f6bbbc72e7af2e9e0c2f896221053f791", - "reference": "f282b08f6bbbc72e7af2e9e0c2f896221053f791", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/f1ad34e8af09ed17570e027cf0c58a12eddec286", + "reference": "f1ad34e8af09ed17570e027cf0c58a12eddec286", "shasum": "" }, "require": { - "php": ">=5.3.9", + "php": ">=5.5.9", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/css-selector": "~2.8|~3.0.0" + "symfony/css-selector": "~2.8|~3.0" }, "suggest": { "symfony/css-selector": "" @@ -5034,7 +5411,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -5061,40 +5438,86 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2016-04-12 18:01:21" + "time": "2017-04-12 14:13:17" }, { - "name": "symfony/polyfill-mbstring", - "version": "dev-master", + "name": "symfony/finder", + "version": "v3.2.8", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "f9bc5072e11b2ad15ea55e0f4171cc870dc33a1d" + "url": "https://github.com/symfony/finder.git", + "reference": "9cf076f8f492f4b1ffac40aae9c2d287b4ca6930" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f9bc5072e11b2ad15ea55e0f4171cc870dc33a1d", - "reference": "f9bc5072e11b2ad15ea55e0f4171cc870dc33a1d", + "url": "https://api.github.com/repos/symfony/finder/zipball/9cf076f8f492f4b1ffac40aae9c2d287b4ca6930", + "reference": "9cf076f8f492f4b1ffac40aae9c2d287b4ca6930", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.5.9" }, - "suggest": { - "ext-mbstring": "For best performance" + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-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": "2017-04-12 14:13:17" + }, + { + "name": "symfony/process", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0", + "reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "3.2-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" + "Symfony\\Component\\Process\\": "" }, - "files": [ - "bootstrap.php" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5103,49 +5526,93 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony Process Component", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" + "time": "2017-04-12 14:13:17" + }, + { + "name": "symfony/stopwatch", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "5a0105afb670dbd38f521105c444de1b8e10cfe3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a0105afb670dbd38f521105c444de1b8e10cfe3", + "reference": "5a0105afb670dbd38f521105c444de1b8e10cfe3", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-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" + } ], - "time": "2016-06-07 08:38:42" + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "time": "2017-04-12 14:13:17" }, { "name": "symfony/translation", - "version": "2.6.x-dev", - "target-dir": "Symfony/Component/Translation", + "version": "v3.2.8", "source": { "type": "git", - "url": "https://github.com/symfony/Translation.git", - "reference": "d84291215b5892834dd8ca8ee52f9cbdb8274904" + "url": "https://github.com/symfony/translation.git", + "reference": "f4a04d2df710f81515df576b2de06bdeee518b83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/d84291215b5892834dd8ca8ee52f9cbdb8274904", - "reference": "d84291215b5892834dd8ca8ee52f9cbdb8274904", + "url": "https://api.github.com/repos/symfony/translation/zipball/f4a04d2df710f81515df576b2de06bdeee518b83", + "reference": "f4a04d2df710f81515df576b2de06bdeee518b83", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/config": "<2.8" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.3,>=2.3.12", - "symfony/intl": "~2.3", - "symfony/phpunit-bridge": "~2.7", - "symfony/yaml": "~2.2" + "symfony/config": "~2.8|~3.0", + "symfony/intl": "^2.8.18|^3.2.5", + "symfony/yaml": "~2.8|~3.0" }, "suggest": { "psr/log": "To use logging capability in translator", @@ -5155,13 +5622,16 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "3.2-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\Translation\\": "" - } + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5179,34 +5649,82 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2015-07-08 05:59:48" + "time": "2017-04-12 14:13:17" + }, + { + "name": "webmozart/assert", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "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": "2016-11-23 20:04:58" } ], "aliases": [], "minimum-stability": "dev", "stability-flags": { - "aura/di": 20, "bodom78/kohana-imagefly": 20, "kohana/core": 20, "kohana/cache": 20, "kohana/image": 20, "kohana/minion": 20, + "ohanzee/database": 20, "ushahidi/shadowhand-email": 20, - "vlucas/phpdotenv": 20, "zeelot/kohana-media": 20, "league/csv": 20, "ddeboer/data-import": 20, "league/event": 20, "beheh/flaps": 20, "doctrine/cache": 20, - "satooshi/php-coveralls": 20, - "kohana/unittest": 20, - "heroku/heroku-buildpack-php": 20 + "heroku/heroku-buildpack-php": 20, + "satooshi/php-coveralls": 20 }, - "prefer-stable": false, + "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=5.4", + "php": ">=5.6.4", "ext-curl": "*", "ext-gd": "*", "ext-imap": "*", diff --git a/docker/build.Dockerfile b/docker/build.Dockerfile index a25fcf2f0f..e18f1a35e2 100644 --- a/docker/build.Dockerfile +++ b/docker/build.Dockerfile @@ -1,4 +1,4 @@ -FROM php:5.5.35-fpm +FROM php:5.6.30-fpm RUN apt-get update && apt-get install -y \ libfreetype6-dev \ @@ -26,7 +26,7 @@ RUN curl -sS https://getcomposer.org/installer | \ WORKDIR /var/www COPY composer.json ./ COPY composer.lock ./ -RUN composer install +RUN composer install --no-autoloader COPY docker/build.run.sh /build.run.sh diff --git a/docker/test.Dockerfile b/docker/test.Dockerfile index 5c5200236a..9eedf85af5 100644 --- a/docker/test.Dockerfile +++ b/docker/test.Dockerfile @@ -1,4 +1,4 @@ -FROM php:5.5.35-fpm +FROM php:5.6.30-fpm RUN apt-get update && apt-get install -y \ libfreetype6-dev \ @@ -26,7 +26,7 @@ RUN curl -sS https://getcomposer.org/installer | \ WORKDIR /var/www COPY composer.json ./ COPY composer.lock ./ -RUN composer install +RUN composer install --no-autoloader COPY docker/test.run.sh /test.run.sh diff --git a/docs/arch-layers.png b/docs/arch-layers.png new file mode 100644 index 0000000000..c058326c4f Binary files /dev/null and b/docs/arch-layers.png differ diff --git a/docs/architecture.md b/docs/architecture.md index e4f3a293be..13b1dfc693 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -40,24 +40,13 @@ Within the API there are two layers: the delivery and the business logic (core a #### Core Application -Within the core application, we use generally follow the [Clean Architecture](http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html). The central part of the business logic is defined as use cases and entities. All dependencies flow inwards towards the entities, which have no dependencies. In order to bring user input to the use cases, we pass create simple request data structures to pass from the delivery layer into the use case. The request structure is a simple array and contains all of the inputs for that specific use case. Once the usecase is complete it returns another simple data structure (response) back to the delivery layer for conversion via a Formatter. Data flow within the platform can be visualized as: +Within the core application, we use generally follow the [Clean Architecture](http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html). The central part of the business logic is defined as use cases and entities. All dependencies flow inwards towards the entities, which have no dependencies. -![api-request-flow](./api-request-flow.png "API Request Flow") -[source](http://www.nomnoml.com/#view/%23title%3A%20General%20API%20request%20flow%0A%0A%5B%3Cstart%3Eapp%5D-%3E%5BKohana%5D%0A%5BKohana%5D-%3E%5BController%5D%0A%5BController%5D-%3E%5B%3Cstate%3Erequest%5D%0A%5B%3Cstate%3Erequest%5D-%3E%5BUsecase%5D%0A%5BUsecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%5BOutputFormatter%5D-%3E%5B%3Cend%3Ejson%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BDependencies%7C%0A%20Repository%3B%0A%20Validator%3B%0A%20Authorizer%3B%0A%20etc...%0A%5Do-%3E%5BUsecase%5D%0A%0A%23direction%3A%20right) - -Specific use cases follow 5 high level patterns for Create, Read, Update, Delete and Search (CRUDS) - -![create-usecase](./create-usecase.png "Create Usecase") -[create](http://www.nomnoml.com/#view/%23title%3A%20Create%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BCreate%20Usecase%5D%0A%5BCreate%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BCreate%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BVerify%20Create%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Create%20Auth%5D-%3E%5BVerify%20Valid%5D%0A%20%20%20%20%20%5BVerify%20Valid%5D-%3E%5BCreate%20Entity%5D%0A%20%20%20%20%20%5BCreate%20Entity%5D-%3E%5BGet%20Created%5D%0A%20%20%20%20%20%5BGet%20Created%5D-%3E%5B%3Cchoice%3E%20Can%20Read%3F%5D%0A%20%20%20%20%20%5B%3Cchoice%3E%20Can%20Read%3F%5D-%3E%5BFormat%20Entity%5D%0A%20%20%20%20%20%5BFormat%20Entity%5D-%3E%5B%3Cend%3E%20return%5D%0A%20%20%20%20%20%5B%3Cchoice%3E%20Can%20Read%3F%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) +![architecture-layers](./arch-layers.png "Software architecture layers") -![read-usecase](./read-usecase.png "Read Usecase") -[read](http://www.nomnoml.com/#view/%23title%3A%20Read%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BRead%20Usecase%5D%0A%5BRead%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BRead%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BVerify%20Read%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Read%20Auth%5D-%3E%5BFormat%20Entity%5D%0A%20%20%20%20%20%5BFormat%20Entity%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) +In order to bring user input to the use cases, we pass simple data structures from the delivery layer into the use case. The request structure is a simple array and contains all of the inputs for that specific use case. Once the usecase is complete it returns another simple data structure (response) back to the delivery layer for conversion via a Formatter. Data flow within the platform can be visualized as: -![update-usecase](./update-usecase.png "UpdateUsecase") -[update](http://www.nomnoml.com/#view/%23title%3A%20Update%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BUpdate%20Usecase%5D%0A%5BUpdate%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BUpdate%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BUpdate%20State%5D%0A%20%20%20%20%20%5BUpdate%20State%5D-%3E%5BVerify%20Update%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Update%20Auth%5D-%3E%5BVerify%20Valid%5D%0A%20%20%20%20%20%5BVerify%20Valid%5D-%3E%5BUpdate%20Entity%5D%0A%20%20%20%20%20%5BUpdate%20Entity%5D-%3E%5B%3Cchoice%3E%20Can%20Read%3F%5D%0A%20%20%20%20%20%5B%3Cchoice%3E%20Can%20Read%3F%5D-%3E%5BFormat%20Entity%5D%0A%20%20%20%20%20%5BFormat%20Entity%5D-%3E%5B%3Cend%3E%20return%5D%0A%20%20%20%20%20%5B%3Cchoice%3E%20Can%20Read%3F%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) - -![delete-usecase](./delete-usecase.png "Delete Usecase") -[delete](http://www.nomnoml.com/#view/%23title%3A%20Delete%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BDelete%20Usecase%5D%0A%5BDelete%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BDelete%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BVerify%20Delete%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Delete%20Auth%5D-%3E%5BDelete%20Entity%5D%0A%20%20%20%20%20%5BDelete%20Entity%5D-%3E%5BVerify%20Read%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Read%20Auth%5D-%3E%5BFormat%20Entity%5D%0A%20%20%20%20%20%5BFormat%20Entity%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) +![api-request-flow](./api-request-flow.png "API Request Flow") +[source](http://www.nomnoml.com/#view/%23title%3A%20General%20API%20request%20flow%0A%0A%5B%3Cstart%3Eapp%5D-%3E%5BKohana%5D%0A%5BKohana%5D-%3E%5BController%5D%0A%5BController%5D-%3E%5B%3Cstate%3Erequest%5D%0A%5B%3Cstate%3Erequest%5D-%3E%5BUsecase%5D%0A%5BUsecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%5BOutputFormatter%5D-%3E%5B%3Cend%3Ejson%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BDependencies%7C%0A%20Repository%3B%0A%20Validator%3B%0A%20Authorizer%3B%0A%20etc...%0A%5Do-%3E%5BUsecase%5D%0A%0A%23direction%3A%20right) -![search-usecase](./search-usecase.png "Search Usecase") -[search](http://www.nomnoml.com/#view/%23title%3A%20Search%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BSearch%20Usecase%5D%0A%5BSearch%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BSearch%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BVerify%20Search%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Search%20Auth%5D-%3E%5BSet%20Search%20Params%5D%0A%20%20%20%20%20%5BSet%20Search%20Params%5D-%3E%5BGet%20Search%20Sesults%5D%0A%20%20%20%20%20%5BGet%20Search%20Sesults%5D-%3E%5BVerify%20Read%20Auth%7C%0A%20%20%20%20%20%20%20%20%5B%3Cstart%3E%20foreach%5D-%3E%5B%3Cchoice%3Ewhile%20results%3F%5D%0A%20%20%20%20%20%20%20%20%5B%3Cchoice%3Ewhile%20results%3F%5D-%3E%5Bcheck%20auth%5D%0A%20%20%20%20%20%20%20%20%5Bcheck%20auth%5D-%3E%5B%3Cchoice%3Ewhile%20results%3F%5D%0A%20%20%20%20%20%20%20%20%5B%3Cchoice%3Ewhile%20results%3F%5D-%3E%5B%3Cend%3E%5D%0A%20%20%20%20%20%5D%0A%20%20%20%20%20%5BVerify%20Read%20Auth%5D-%3E%5BFormat%20Results%5D%0A%20%20%20%20%20%5BFormat%20Results%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) +See [Use Case Internals](./use-case-internals.md) for more detail diff --git a/docs/create-usecase-collab.png b/docs/create-usecase-collab.png new file mode 100644 index 0000000000..8de17327e4 Binary files /dev/null and b/docs/create-usecase-collab.png differ diff --git a/docs/use-case-internals.md b/docs/use-case-internals.md new file mode 100644 index 0000000000..57b9ff1664 --- /dev/null +++ b/docs/use-case-internals.md @@ -0,0 +1,87 @@ +# Use Case Internals + +## What is a use case? + +Part of Hexagonal Architecture is the concept of the Application Boundary. This boundary separates our application as a whole from everything else (both framework and communication with the outside world). + +> A Use Case (sometimes called a Command) is an explicitly defined way in which an application can be used. + +We define how the outside world can communicate with our application by creating "Use Cases". These essentially are classes which name actions that can be taken. For example, our CreatePostUsecase defines that our application can create a post. + +Defining Use Cases has some useful side-affects. For example, we clearly and explicitly can see how our application "wants" to be interacted with. We can plan use cases ahead of time, or add them as needed, but use cases should capture the operations which can happen within our application. + +> Aside: Platform uses some generic CRUDS usecases. These aren't tied to a specific Domain Model (Entity) ie. a Post but rather have the entity and repo injected into them. This makes Use Cases significantly less well defined. A developer can no longer glance at the Use Case directory and see what actions are available. This might be something we can improve in future + +## Anatomy of a Use Case (in platform) + +Use Cases in platform all follow a high level interface. In short they all have a `interact()` method. + +``` +interface Usecase +{ + /** + * @return Array + */ + public function interact(); +} +``` + +To enable building of some generic use cases they also have `isSearch` and `isWrite` methods. + +``` +interface Usecase +{ + /** + * Will this usecase write any data? + * + * @return Boolean + */ + public function isWrite(); + + /** + * Will this usecase search for data? + * + * @return Boolean + */ + public function isSearch(); + + /** + * @return Array + */ + public function interact(); +} +``` + +The actual parameters for each UseCase are injected through setter methods, commonly: `setPayload()`, `setIdentifiers` and `setFilters`. + +## CRUDS use cases + +Most of our use cases follow 5 high level patterns for Create, Read, Update, Delete and Search (CRUDS) + +### Create + +![create-usecase](./create-usecase.png "Create Usecase") +[create](http://www.nomnoml.com/#view/%23title%3A%20Create%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BCreate%20Usecase%5D%0A%5BCreate%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BCreate%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BVerify%20Create%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Create%20Auth%5D-%3E%5BVerify%20Valid%5D%0A%20%20%20%20%20%5BVerify%20Valid%5D-%3E%5BCreate%20Entity%5D%0A%20%20%20%20%20%5BCreate%20Entity%5D-%3E%5BGet%20Created%5D%0A%20%20%20%20%20%5BGet%20Created%5D-%3E%5B%3Cchoice%3E%20Can%20Read%3F%5D%0A%20%20%20%20%20%5B%3Cchoice%3E%20Can%20Read%3F%5D-%3E%5BFormat%20Entity%5D%0A%20%20%20%20%20%5BFormat%20Entity%5D-%3E%5B%3Cend%3E%20return%5D%0A%20%20%20%20%20%5B%3Cchoice%3E%20Can%20Read%3F%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) + +![create-usecase-collab](./create-usecase-collab.png "Create Usecase Collaborators") +[collaborators](http://www.nomnoml.com/#view/%23title%3A%20Create%20UseCase%20Collaborators%0A%0A%5BCreateUsecase%7C%7C%0Ainteract()%0AsetPayload()%5D%0A%0A%5BValidator%5D%3C-%2B%5BCreateUsecase%5D%0A%5BAuthorizer%5D%3C-%2B%5BCreateUsecase%5D%0A%5BFormatter%5D%3C-%2B%5BCreateUsecase%5D%0A%5BRepository%5D%3C-%2B%5BCreateUsecase%5D%0A%0A%5BCreateUsecase%5D-%3E%5B%3Cinput%3E%20payload%5D%0A%0A%23direction%3A%20right) + +### Read + +![read-usecase](./read-usecase.png "Read Usecase") +[read](http://www.nomnoml.com/#view/%23title%3A%20Read%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BRead%20Usecase%5D%0A%5BRead%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BRead%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BVerify%20Read%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Read%20Auth%5D-%3E%5BFormat%20Entity%5D%0A%20%20%20%20%20%5BFormat%20Entity%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) + +### Update + +![update-usecase](./update-usecase.png "UpdateUsecase") +[update](http://www.nomnoml.com/#view/%23title%3A%20Update%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BUpdate%20Usecase%5D%0A%5BUpdate%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BUpdate%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BUpdate%20State%5D%0A%20%20%20%20%20%5BUpdate%20State%5D-%3E%5BVerify%20Update%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Update%20Auth%5D-%3E%5BVerify%20Valid%5D%0A%20%20%20%20%20%5BVerify%20Valid%5D-%3E%5BUpdate%20Entity%5D%0A%20%20%20%20%20%5BUpdate%20Entity%5D-%3E%5B%3Cchoice%3E%20Can%20Read%3F%5D%0A%20%20%20%20%20%5B%3Cchoice%3E%20Can%20Read%3F%5D-%3E%5BFormat%20Entity%5D%0A%20%20%20%20%20%5BFormat%20Entity%5D-%3E%5B%3Cend%3E%20return%5D%0A%20%20%20%20%20%5B%3Cchoice%3E%20Can%20Read%3F%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) + +### Delete + +![delete-usecase](./delete-usecase.png "Delete Usecase") +[delete](http://www.nomnoml.com/#view/%23title%3A%20Delete%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BDelete%20Usecase%5D%0A%5BDelete%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BDelete%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BVerify%20Delete%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Delete%20Auth%5D-%3E%5BDelete%20Entity%5D%0A%20%20%20%20%20%5BDelete%20Entity%5D-%3E%5BVerify%20Read%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Read%20Auth%5D-%3E%5BFormat%20Entity%5D%0A%20%20%20%20%20%5BFormat%20Entity%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) + +### Search + +![search-usecase](./search-usecase.png "Search Usecase") +[search](http://www.nomnoml.com/#view/%23title%3A%20Search%20UseCase%0A%5B%3Cstate%3Erequest%5D-%3E%5BSearch%20Usecase%5D%0A%5BSearch%20Usecase%5D-%3E%5B%3Cstate%3Eresponse%5D%0A%5B%3Cstate%3Eresponse%5D-%3E%5BOutputFormatter%5D%0A%0A%5B%3Cstate%3Erequest%7C%0Apayload%3B%0Aidentifier%3B%0Afilters%5D%0A%0A%5BSearch%20Usecase%7C%0A%20%20%20%20%20%5B%3Cstart%3E%20interact()%5D-%3E%5BGet%20Entity%5D%0A%20%20%20%20%20%5BGet%20Entity%5D-%3E%5BVerify%20Search%20Auth%5D%0A%20%20%20%20%20%5BVerify%20Search%20Auth%5D-%3E%5BSet%20Search%20Params%5D%0A%20%20%20%20%20%5BSet%20Search%20Params%5D-%3E%5BGet%20Search%20Sesults%5D%0A%20%20%20%20%20%5BGet%20Search%20Sesults%5D-%3E%5BVerify%20Read%20Auth%7C%0A%20%20%20%20%20%20%20%20%5B%3Cstart%3E%20foreach%5D-%3E%5B%3Cchoice%3Ewhile%20results%3F%5D%0A%20%20%20%20%20%20%20%20%5B%3Cchoice%3Ewhile%20results%3F%5D-%3E%5Bcheck%20auth%5D%0A%20%20%20%20%20%20%20%20%5Bcheck%20auth%5D-%3E%5B%3Cchoice%3Ewhile%20results%3F%5D%0A%20%20%20%20%20%20%20%20%5B%3Cchoice%3Ewhile%20results%3F%5D-%3E%5B%3Cend%3E%5D%0A%20%20%20%20%20%5D%0A%20%20%20%20%20%5BVerify%20Read%20Auth%5D-%3E%5BFormat%20Results%5D%0A%20%20%20%20%20%5BFormat%20Results%5D-%3E%5B%3Cend%3E%20return%5D%0A%5D%0A%0A%23direction%3A%20right) diff --git a/httpdocs/coverage.php b/httpdocs/coverage.php index 16f2d7ad62..204f204003 100644 --- a/httpdocs/coverage.php +++ b/httpdocs/coverage.php @@ -2,8 +2,11 @@ require __DIR__ . '/../vendor/autoload.php'; -$coverage = new PHP_CodeCoverage; -$coverage->filter()->addDirectoryToBlacklist(__DIR__ . '../vendor/'); +$coverage = new \SebastianBergmann\CodeCoverage\CodeCoverage; +$coverage->setAddUncoveredFilesFromWhitelist(true); +$coverage->filter()->addDirectoryToWhitelist(__DIR__ . '/../application/'); +$coverage->filter()->addDirectoryToWhitelist(__DIR__ . '/../src/'); +$coverage->filter()->addDirectoryToWhitelist(__DIR__ . '/../plugins/*/classes/'); $coverage->start('behat-api-test'); // Initialize the Kohana application @@ -12,5 +15,5 @@ $coverage->stop(); $file = __DIR__ . '/../coverage/behat-' . uniqid() . '.xml'; -$writer = new PHP_CodeCoverage_Report_Clover; +$writer = new \SebastianBergmann\CodeCoverage\Report\Clover; $writer->process($coverage, $file); diff --git a/migrations/20141007125013_created_updated_indexes.php b/migrations/20141007125013_created_updated_indexes.php index e62fe4ef91..221e44b0fd 100644 --- a/migrations/20141007125013_created_updated_indexes.php +++ b/migrations/20141007125013_created_updated_indexes.php @@ -98,6 +98,5 @@ public function change() ->addIndex(['created']) ->addIndex(['updated']) ->update(); - } } diff --git a/migrations/20150323031520_rename_groups_to_stages.php b/migrations/20150323031520_rename_groups_to_stages.php index 5a98131192..3cead69605 100644 --- a/migrations/20150323031520_rename_groups_to_stages.php +++ b/migrations/20150323031520_rename_groups_to_stages.php @@ -20,7 +20,6 @@ public function up() 'delete' => 'CASCADE', ]) ->update(); - } public function down() diff --git a/migrations/20150326163454_add_published_to_column_to_posts.php b/migrations/20150326163454_add_published_to_column_to_posts.php index fec2c3cfec..d199c3adec 100644 --- a/migrations/20150326163454_add_published_to_column_to_posts.php +++ b/migrations/20150326163454_add_published_to_column_to_posts.php @@ -7,7 +7,7 @@ class AddPublishedToColumnToPosts extends AbstractMigration /** * Adding role-specific visibility functionality to posts * By default, all published posts are public, but post owners - * or administrators can specify which roles are able to view + * or administrators can specify which roles are able to view * a given post if desired. Admins still have access to all. */ @@ -20,6 +20,5 @@ public function change() 'null' => true ]) ->update(); - } } diff --git a/migrations/20150612014440_add_users_role_foreign_key.php b/migrations/20150612014440_add_users_role_foreign_key.php index fc56e49d15..5323e2d08d 100644 --- a/migrations/20150612014440_add_users_role_foreign_key.php +++ b/migrations/20150612014440_add_users_role_foreign_key.php @@ -28,7 +28,6 @@ public function up() ]) ->update() ; - } /** diff --git a/migrations/20150716003751_fix_unstructured_post_set_filter.php b/migrations/20150716003751_fix_unstructured_post_set_filter.php index ba43f34f94..ba71d86db0 100644 --- a/migrations/20150716003751_fix_unstructured_post_set_filter.php +++ b/migrations/20150716003751_fix_unstructured_post_set_filter.php @@ -23,6 +23,5 @@ public function up() */ public function down() { - } } diff --git a/migrations/20150829193514_add_notifications_oauth_scope.php b/migrations/20150829193514_add_notifications_oauth_scope.php index b457e86683..70382987e6 100644 --- a/migrations/20150829193514_add_notifications_oauth_scope.php +++ b/migrations/20150829193514_add_notifications_oauth_scope.php @@ -11,7 +11,6 @@ class AddNotificationsOauthScope extends AbstractMigration public function up() { $this->execute("INSERT INTO oauth_scopes (scope, name) VALUES ('notifications', 'notifications')"); - } /** diff --git a/migrations/20150904083146_add_contact_oauth_scope.php b/migrations/20150904083146_add_contact_oauth_scope.php index 1778f3bad4..8b6c7c9432 100644 --- a/migrations/20150904083146_add_contact_oauth_scope.php +++ b/migrations/20150904083146_add_contact_oauth_scope.php @@ -10,7 +10,6 @@ class AddContactOauthScope extends AbstractMigration public function up() { $this->execute("INSERT INTO oauth_scopes (scope, name) VALUES ('contacts', 'contacts')"); - } /** diff --git a/migrations/20151208024527_add_user_to_messages.php b/migrations/20151208024527_add_user_to_messages.php index a74b02d3b6..3517bdf6ef 100644 --- a/migrations/20151208024527_add_user_to_messages.php +++ b/migrations/20151208024527_add_user_to_messages.php @@ -21,7 +21,6 @@ public function up() 'update' => 'CASCADE', ]) ->update(); - } /** diff --git a/migrations/20151208172416_add_csv_oauth_scope.php b/migrations/20151208172416_add_csv_oauth_scope.php index 01b05e862d..63da2d4cb0 100644 --- a/migrations/20151208172416_add_csv_oauth_scope.php +++ b/migrations/20151208172416_add_csv_oauth_scope.php @@ -10,7 +10,6 @@ class AddCsvOauthScope extends AbstractMigration public function up() { $this->execute("INSERT INTO oauth_scopes (scope, name) VALUES ('csv', 'csv')"); - } /** diff --git a/migrations/20160202115439_add_permissions.php b/migrations/20160202115439_add_permissions.php index b1e80c990a..9e2f64a719 100644 --- a/migrations/20160202115439_add_permissions.php +++ b/migrations/20160202115439_add_permissions.php @@ -26,6 +26,5 @@ public function change() ('Manage Settings', 'Manage general settings'), ('Bulk Data Import', 'Import data from external sources') "); - } } diff --git a/migrations/20160215174906_add_role_id.php b/migrations/20160215174906_add_role_id.php index e93e011caa..caa2accce5 100644 --- a/migrations/20160215174906_add_role_id.php +++ b/migrations/20160215174906_add_role_id.php @@ -19,7 +19,6 @@ public function up() ->update(); $this->execute("ALTER TABLE roles DROP PRIMARY KEY;"); $this->execute("ALTER TABLE roles MODIFY id INT AUTO_INCREMENT PRIMARY KEY;"); - } /** diff --git a/migrations/20160503083146_add_migrate_oauth_scope.php b/migrations/20160503083146_add_migrate_oauth_scope.php index 85471628b4..13eb329003 100644 --- a/migrations/20160503083146_add_migrate_oauth_scope.php +++ b/migrations/20160503083146_add_migrate_oauth_scope.php @@ -10,7 +10,6 @@ class AddMigrateOauthScope extends AbstractMigration public function up() { $this->execute("INSERT INTO oauth_scopes (scope, name) VALUES ('migrate', 'migrate')"); - } /** diff --git a/migrations/20160509232531_add_message_location_attribute.php b/migrations/20160509232531_add_message_location_attribute.php index 79b97589dc..f25ba2604b 100644 --- a/migrations/20160509232531_add_message_location_attribute.php +++ b/migrations/20160509232531_add_message_location_attribute.php @@ -34,6 +34,5 @@ public function down() WHERE " . $adapter->quoteColumnName('key') . " = 'message_location' " )->execute(); - } } diff --git a/migrations/20160623184725_set_protected_roles.php b/migrations/20160623184725_set_protected_roles.php index 129c3d8f9d..7ed7a602c4 100644 --- a/migrations/20160623184725_set_protected_roles.php +++ b/migrations/20160623184725_set_protected_roles.php @@ -38,6 +38,5 @@ public function up() */ public function down() { - } } diff --git a/migrations/20161208162710_rename_visible_to_column.php b/migrations/20161208162710_rename_visible_to_column.php index 0e511a2dae..7292146b60 100644 --- a/migrations/20161208162710_rename_visible_to_column.php +++ b/migrations/20161208162710_rename_visible_to_column.php @@ -22,6 +22,5 @@ public function down() $this->table('sets') ->renameColumn('role', 'visible_to') ->update(); - } } diff --git a/migrations/20170311003829_create_webhook_table.php b/migrations/20170311003829_create_webhook_table.php index dbbe5247d3..503971fda1 100644 --- a/migrations/20170311003829_create_webhook_table.php +++ b/migrations/20170311003829_create_webhook_table.php @@ -23,7 +23,6 @@ public function up() 'update' => 'CASCADE', ]) ->create(); - } /** diff --git a/migrations/20170313194004_add_webhook_to_oauth_scope.php b/migrations/20170313194004_add_webhook_to_oauth_scope.php index bdfa0aea08..9f35b7c214 100644 --- a/migrations/20170313194004_add_webhook_to_oauth_scope.php +++ b/migrations/20170313194004_add_webhook_to_oauth_scope.php @@ -11,7 +11,6 @@ class AddWebhookToOauthScope extends AbstractMigration public function up() { $this->execute("INSERT INTO oauth_scopes (scope, name) VALUES ('webhooks', 'webhooks')"); - } /** diff --git a/migrations/20170315231639_add_post_markdown_table.php b/migrations/20170315231639_add_post_markdown_table.php index 8e28a2b4ff..7710fd0a5f 100644 --- a/migrations/20170315231639_add_post_markdown_table.php +++ b/migrations/20170315231639_add_post_markdown_table.php @@ -12,7 +12,7 @@ public function up() $this->table('post_markdown') ->addColumn('post_id', 'integer') ->addColumn('form_attribute_id', 'integer') - ->addColumn('value', 'string', ['null' => true]) + ->addColumn('value', 'text', ['null' => true]) ->addColumn('created', 'integer', ['default' => 0]) ->addColumn('updated', 'integer', ['null' => true]) ->addForeignKey('form_attribute_id', 'form_attributes', 'id', [ diff --git a/migrations/20170317174120_add_private_response_to_form_attribute.php b/migrations/20170317174120_add_private_response_to_form_attribute.php new file mode 100644 index 0000000000..8af35a567d --- /dev/null +++ b/migrations/20170317174120_add_private_response_to_form_attribute.php @@ -0,0 +1,29 @@ +table('form_attributes') + ->addColumn('response_private', 'boolean', [ + 'default' => false, + 'null' => false, + ]) + ->update(); + } + + /** + * Migrate Down. + */ + public function down() + { + $this->table('form_attributes') + ->removeColumn('response_private') + ->update(); + } +} diff --git a/migrations/20170322160413_add_hide_author_to_form.php b/migrations/20170322160413_add_hide_author_to_form.php new file mode 100644 index 0000000000..6f89e3d820 --- /dev/null +++ b/migrations/20170322160413_add_hide_author_to_form.php @@ -0,0 +1,29 @@ +table('forms') + ->addColumn('hide_author', 'boolean', [ + 'default' => false, + 'null' => false, + ]) + ->update(); + } + + /** + * Migrate Down. + */ + public function down() + { + $this->table('forms') + ->removeColumn('hide_author') + ->update(); + } +} diff --git a/migrations/20170322162237_add_description_field_to_form_attribute.php b/migrations/20170322162237_add_description_field_to_form_attribute.php new file mode 100644 index 0000000000..c09fd577ca --- /dev/null +++ b/migrations/20170322162237_add_description_field_to_form_attribute.php @@ -0,0 +1,28 @@ +table('form_attributes') + ->addColumn('description', 'string', [ + 'null' => true + ]) + ->update(); + } + + /** + * Migrate Down. + */ + public function down() + { + $this->table('form_attributes') + ->removeColumn('description') + ->update(); + } +} diff --git a/migrations/20170325110408_add_language_to_user.php b/migrations/20170325110408_add_language_to_user.php new file mode 100644 index 0000000000..7a05ad3d34 --- /dev/null +++ b/migrations/20170325110408_add_language_to_user.php @@ -0,0 +1,28 @@ +table('users') + ->addColumn('language', 'string', [ + 'null' => true, + ]) + ->update(); + } + + /** + * Migrate Down. + */ + public function down() + { + $this->table('users') + ->removeColumn('language') + ->update(); + } +} diff --git a/migrations/20170328080656_add_forms_tags_table.php b/migrations/20170328080656_add_forms_tags_table.php new file mode 100644 index 0000000000..dabffc554e --- /dev/null +++ b/migrations/20170328080656_add_forms_tags_table.php @@ -0,0 +1,33 @@ +table('forms_tags', [ + 'id' => false, + 'primary_key' => ['form_id', 'tag_id'], + ]) + ->addColumn('form_id', 'integer') + ->addForeignKey('form_id', 'forms', 'id', [ + 'delete' => 'CASCADE', + 'update' => 'CASCADE' + ]) + ->addColumn('tag_id', 'integer') + ->addForeignKey('tag_id', 'tags', 'id', [ + 'delete' => 'CASCADE', + 'update' => 'CASCADE' + ]) + ->create(); + } +} diff --git a/migrations/20170331210813_add_show_when_published_to_form_stage.php b/migrations/20170331210813_add_show_when_published_to_form_stage.php new file mode 100644 index 0000000000..9e929d5b73 --- /dev/null +++ b/migrations/20170331210813_add_show_when_published_to_form_stage.php @@ -0,0 +1,29 @@ +table('form_stages') + ->addColumn('show_when_published', 'boolean', [ + 'null' => false, + 'default' => true + ]) + ->update(); + } + + /** + * Migrate Down. + */ + public function down() + { + $this->table('form_stages') + ->removeColumn('show_when_published') + ->update(); + } +} diff --git a/migrations/20170412191954_convert_form_tags_to_form_attribute.php b/migrations/20170412191954_convert_form_tags_to_form_attribute.php new file mode 100644 index 0000000000..76e0436091 --- /dev/null +++ b/migrations/20170412191954_convert_form_tags_to_form_attribute.php @@ -0,0 +1,59 @@ +getAdapter()->getConnection(); + $rows = $this->fetchAll( + "SELECT id + FROM form_stages + WHERE `type` = 'post'" + ); + $tag_rows = $this->fetchAll( + "SELECT id + FROM tags" + ); + $insert = $pdo->prepare( + "INSERT into form_attributes + (`label`,`type`, `required`, `priority`, `cardinality`, `input`, `options`, `key`, `form_stage_id`) + VALUES + ('Categories', 'varchar', 0, 3, 0, 'tags', :tags, :key, :form_stage_id)" + ); + + $tags = []; + + foreach ($tag_rows as $tag_row) { + array_push($tags, (int)$tag_row['id']); + } + $tags = json_encode($tags); + + foreach ($rows as $row) { + $uuid = Uuid::uuid4(); + $key = $uuid->toString(); + $insert->execute( + [ + ':tags' => $tags, + ':key' => $key, + ':form_stage_id' => $row['id'] + ] + ); + } + } + + /** + * Migrate Down. + */ + public function down() + { + $this->execute("DELETE from form_attributes where type = 'varchar' AND input = 'tags'"); + } +} diff --git a/migrations/20170417082819_add_tags_to_forms_tags.php b/migrations/20170417082819_add_tags_to_forms_tags.php new file mode 100644 index 0000000000..2fed17221d --- /dev/null +++ b/migrations/20170417082819_add_tags_to_forms_tags.php @@ -0,0 +1,49 @@ +getAdapter()->getConnection(); + + $forms = $this->fetchAll( + "SELECT id + FROM forms" + ); + $tags = $this->fetchAll( + "SELECT id + FROM tags" + ); + + $insert = $pdo->prepare( + "INSERT into + forms_tags + (`tag_id`, `form_id`) + VALUES(:tag_id, :form_id) + " + ); + + foreach ($forms as $form) { + foreach ($tags as $tag) { + $insert->execute( + [':tag_id' => $tag['id'], + ':form_id' => $form['id'] + ] + ); + } + } + } + + /** + * Migrate Down. + */ + public function down() + { + $this->execute("DELETE from forms_tags"); + } +} diff --git a/migrations/20170417090621_move_post_tag_values_to_post_varchar.php b/migrations/20170417090621_move_post_tag_values_to_post_varchar.php new file mode 100644 index 0000000000..1c807b1474 --- /dev/null +++ b/migrations/20170417090621_move_post_tag_values_to_post_varchar.php @@ -0,0 +1,66 @@ +getAdapter()->getConnection(); + // fetching posts with form_attribute_id + // $posts = $this->fetchAll( + // "SELECT posts.id, posts.form_id, form_attributes.id as form_attribute_id + // FROM posts + // INNER JOIN form_stages + // ON form_stages.form_id = posts.form_id + // INNER JOIN form_attributes + // ON form_attributes.form_stage_id = form_stages.id + // AND form_attributes.input = 'tags' + // AND form_attributes.type = 'varchar'" + // ); + // $insert = $pdo->prepare( + // "INSERT into + // post_varchar + // (`post_id`, `form_attribute_id`, `value`, `created`) + // VALUES(:post_id, :form_attribute_id, :value, :created)" + // ); + // foreach ($posts as $post) { + // $post_tags = $pdo->prepare( + // "SELECT tag_id + // FROM posts_tags + // WHERE post_id = :post_id" + // ); + // $post_tags->execute([':post_id' => $post['id']]); + // // inserting post_ids and tag_ids(value) in post_varchar + // $tags = $post_tags->fetchAll(); + // foreach ($tags as $tag) { + // $insert->execute( + // [ + // ':post_id' => $post['id'], + // ':form_attribute_id' => $post['form_attribute_id'], + // ':value' => $tag['tag_id'], + // ':created' => time() + // ] + // ); + // } + // } + } + + /** + * Migrate Down. + */ + public function down() + { + $this->execute( + "DELETE from post_varchar + WHERE form_attribute_id IN + (SELECT form_attributes.id FROM form_attributes WHERE input = 'tags' AND type = 'varchar')" + ); + } +} diff --git a/migrations/20170507060511_make_show_when_published_to_true.php b/migrations/20170507060511_make_show_when_published_to_true.php new file mode 100644 index 0000000000..6e39bb3c7f --- /dev/null +++ b/migrations/20170507060511_make_show_when_published_to_true.php @@ -0,0 +1,32 @@ +getAdapter()->getConnection(); + $rows = $this->fetchAll("SELECT show_when_published from form_stages"); + $insert = $pdo->prepare( + "UPDATE form_stages + SET show_when_published = true" + ); + foreach ($rows as $row) { + $insert->execute(); + } + } + + public function down() + { + $pdo = $this->getAdapter()->getConnection(); + $rows = $this->fetchAll("SELECT show_when_published from form_stages"); + $insert = $pdo->prepare( + "UPDATE form_stages + SET show_when_published = false" + ); + foreach ($rows as $row) { + $insert->execute(); + } + } +} diff --git a/migrations/20170508191840_change_task_visibility_default.php b/migrations/20170508191840_change_task_visibility_default.php new file mode 100644 index 0000000000..fd24cc6570 --- /dev/null +++ b/migrations/20170508191840_change_task_visibility_default.php @@ -0,0 +1,32 @@ +table('form_stages') + ->changeColumn('show_when_published', 'boolean', [ + 'null' => false, + 'default'=> true + ]) + ->update(); + } + + /** + * Migrate Down. + */ + public function down() + { + $this->table('form_stages') + ->changeColumn('show_when_published', 'boolean', [ + 'null' => true, + 'default'=> true + ]) + ->update(); + } +} diff --git a/migrations/20170519044934_remove_tags_from_tasks.php b/migrations/20170519044934_remove_tags_from_tasks.php new file mode 100644 index 0000000000..7401578506 --- /dev/null +++ b/migrations/20170519044934_remove_tags_from_tasks.php @@ -0,0 +1,20 @@ +execute(" + DELETE FROM `form_attributes` WHERE + `input` = 'tags' AND + `form_stage_id` IN (SELECT `id` FROM `form_stages` WHERE `type` = 'task') + "); + } + + public function down() + { + // No op, not reversible + } +} diff --git a/migrations/20170522004400_remove_tags_from_post_varchar.php b/migrations/20170522004400_remove_tags_from_post_varchar.php new file mode 100644 index 0000000000..1c2d8b1719 --- /dev/null +++ b/migrations/20170522004400_remove_tags_from_post_varchar.php @@ -0,0 +1,21 @@ +execute( + "DELETE from post_varchar + WHERE form_attribute_id IN + (SELECT form_attributes.id FROM form_attributes WHERE input = 'tags' AND type = 'varchar')" + ); + } + + public function down() + { + // No op - not reversible + } +} diff --git a/migrations/20170522004409_join_posts_tags_table_to_attribute.php b/migrations/20170522004409_join_posts_tags_table_to_attribute.php new file mode 100644 index 0000000000..6cf847aaa3 --- /dev/null +++ b/migrations/20170522004409_join_posts_tags_table_to_attribute.php @@ -0,0 +1,86 @@ +getAdapter()->getConnection(); + + $this->table('posts_tags') + ->addColumn('id', 'integer', ['null' => false]) + ->addColumn('form_attribute_id', 'integer') + ->addColumn('created', 'integer', ['default' => 0]) + ->update(); + + // Manually fix up keys + $this->execute('ALTER TABLE posts_tags + DROP PRIMARY KEY, + ADD PRIMARY KEY (id), + ADD INDEX (post_id), + MODIFY COLUMN id INT AUTO_INCREMENT, + ADD UNIQUE INDEX unique_post_tag_attribute_ids (post_id, tag_id, form_attribute_id)'); + + // Make varchar/tags attributes into tags/tags attributes + $this->execute(" + UPDATE form_attributes + SET type = 'tags' + WHERE type = 'varchar' AND input = 'tags' + "); + + $attributes = $this->fetchAll(" + SELECT form_attributes.id, form_stages.form_id + FROM form_attributes + JOIN form_stages ON (form_attributes.form_stage_id = form_stages.id) + WHERE + form_attributes.type = 'tags' AND + form_stages.type = 'post' + "); + + // Set form_attribute_id for posts_tags entries + $insert = $pdo->prepare(' + UPDATE posts_tags JOIN posts ON (posts_tags.post_id = posts.id) + SET form_attribute_id = :attr_id WHERE posts.form_id = :form_id + '); + foreach ($attributes as $attribute) { + $insert->execute([ + ':attr_id' => $attribute['id'], + ':form_id' => $attribute['form_id'] + ]); + } + + // Add foreign key for form_attribute_id + $this->table('posts_tags') + ->addForeignKey('form_attribute_id', 'form_attributes', 'id', [ + 'delete' => 'CASCADE', + 'update' => 'CASCADE', + ]) + ->update(); + } + + public function down() + { + // Make tags/tags attributes into varchar/tags attributes + $this->execute(" + UPDATE form_attributes + SET type = 'varchar' + WHERE type = 'tags' AND input = 'tags' + "); + + // Restore keys/indexs + $this->execute('ALTER TABLE posts_tags + DROP PRIMARY KEY, + ADD PRIMARY KEY (post_id, tag_id), + MODIFY COLUMN id INT, + DROP INDEX unique_post_tag_attribute_ids'); + + // Remove columns + $this->table('posts_tags') + ->dropForeignKey('form_attribute_id') + ->removeColumn('id') + ->removeColumn('form_attribute_id') + ->removeColumn('created') + ->update(); + } +} diff --git a/migrations/20170525003110_drop_forms_tags_table.php b/migrations/20170525003110_drop_forms_tags_table.php new file mode 100644 index 0000000000..781ecba7da --- /dev/null +++ b/migrations/20170525003110_drop_forms_tags_table.php @@ -0,0 +1,51 @@ +dropTable('forms_tags'); + } + + public function down() + { + $this->table('forms_tags', [ + 'id' => false, + 'primary_key' => ['form_id', 'tag_id'], + ]) + ->addColumn('form_id', 'integer') + ->addForeignKey('form_id', 'forms', 'id', [ + 'delete' => 'CASCADE', + 'update' => 'CASCADE' + ]) + ->addColumn('tag_id', 'integer') + ->addForeignKey('tag_id', 'tags', 'id', [ + 'delete' => 'CASCADE', + 'update' => 'CASCADE' + ]) + ->create(); + } +} diff --git a/migrations/20170526014209_make_tags_top_level_when_parent_deleted.php b/migrations/20170526014209_make_tags_top_level_when_parent_deleted.php new file mode 100644 index 0000000000..bd10ac164c --- /dev/null +++ b/migrations/20170526014209_make_tags_top_level_when_parent_deleted.php @@ -0,0 +1,40 @@ +table('tags') + ->dropForeignKey('parent_id') + ->update(); + + $this->table('tags') + ->addForeignKey('parent_id', 'tags', 'id', [ + 'delete' => 'SET_NULL', + 'update' => 'CASCADE', + ]) + ->update(); + } + + /** + * Migrate Down. + */ + public function down() + { + $this->table('tags') + ->dropForeignKey('parent_id') + ->update(); + + $this->table('tags') + ->addForeignKey('parent_id', 'tags', 'id', [ + 'delete' => 'CASCADE', + 'update' => 'CASCADE', + ]) + ->update(); + } +} diff --git a/migrations/ruleset.xml b/migrations/ruleset.xml index 402af32586..27363ab4c6 100644 --- a/migrations/ruleset.xml +++ b/migrations/ruleset.xml @@ -5,5 +5,6 @@ + - \ No newline at end of file + diff --git a/phpspec.yml.dist b/phpspec.yml.dist index 063703131c..2878ca4f39 100644 --- a/phpspec.yml.dist +++ b/phpspec.yml.dist @@ -3,3 +3,4 @@ suites: ushahidi_suite: namespace: Ushahidi psr4_prefix: Ushahidi + spec_path: tests/ diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 2a852af52c..428ef3263d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,11 +1,19 @@ + bootstrap="tests/bootstrap.php" + colors="true" + > - ./application/tests/ + ./tests/ + + + ./application/classes + ./src + ./plugins/*/classes + + diff --git a/puppet/platform/environment.conf b/puppet/platform/environment.conf deleted file mode 100644 index a3131a255c..0000000000 --- a/puppet/platform/environment.conf +++ /dev/null @@ -1 +0,0 @@ -modulepath = modules:../modules:$basemodulepath diff --git a/puppet/platform/manifests/site.pp b/puppet/platform/manifests/site.pp deleted file mode 100644 index 01d816c5ef..0000000000 --- a/puppet/platform/manifests/site.pp +++ /dev/null @@ -1,173 +0,0 @@ -Exec { - path => "/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", -} -File { mode => "0644" } - -file { '/etc/motd': - content => "Welcome to your Ushahidi Platform virtual machine! - Managed by Puppet.\n" -} - -class { 'apt': } - -# Update before install any packages -exec { 'apt-update': - command => '/usr/bin/apt-get update' -} -Apt::Source <| |> -> Exec['apt-update'] -> Package <| |> - -package { - [ - "curl", - "wget", - "postfix", - "byobu", - "nfs-common", - "php5", - "libapache2-mod-php5", - "php5-cli", - "php5-curl", - "php5-gd", - "php5-imap", - "php5-json", - "php5-mcrypt", - "php5-mysqlnd" - ]: - ensure => installed, - require => [ - Exec["apt-update"], - #Exec["apt-upgrade"] - ] -} - -# MySQL setup -class { '::mysql::server': - package_name => 'mysql-server-5.5', - override_options => { - 'mysqld' => { - 'max_connections' => '1024', - 'bind_address' => '0.0.0.0' - } - }, - restart => true -} - -mysql::db { 'ushahidi': - user => 'ushahidi', - password => 'lamulamulamu', - host => '%', - grant => ['ALL'], - charset => 'utf8' -} - -class { 'mysql::client': } - -file { "/etc/php5/apache2/conf.d/99-ushahidi.ini": - ensure => "present", - owner => "root", - group => "root", - mode => "444", - content => template("platform/php-defaults.erb"), - require => Package["libapache2-mod-php5"], -} - -exec { "php-modules": - command => "php5enmod mcrypt imap" -} - -class { 'composer': - suhosin_enabled => false, - github_token => if ( $github_token and $github_token != '' ) { $github_token } else { undef } -} - -# Apache setup - -# Define directories first so that apache class doesn't try to set permissions -file { '/var/www': - ensure => directory, -} - -file { '/var/www/httpdocs': - ensure => directory, -} - -class { 'apache': - default_vhost => false, - require => File["/var/www"], - mpm_module => 'prefork' -} - -apache::mod { 'rewrite': } - -class {'::apache::mod::php': - #package_name => "php54-php", - #path => "${::apache::params::lib_path}/libphp54-php5.so", -} - -apache::vhost { 'ushahidi.dev': - port => '80', - docroot => '/var/www/httpdocs', - directories => [{ path => '/var/www/httpdocs', - allow_override => 'All', - auth_require => 'all granted', - options => ['Indexes', 'FollowSymLinks', 'MultiViews'] - }], - require => File["/var/www/httpdocs"], -} - -# Ushahidi directories and files -file { '/var/www/application/cache': - ensure => directory, - mode => '0777', -} - -file { '/var/www/application/logs': - ensure => directory, - mode => '0777', -} - -file { '/var/www/application/media/uploads': - ensure => directory, - mode => '0777', -} - -file { "/var/www/application/config/environments": - ensure => directory -} - -file { "/var/www/application/config/environments/development": - ensure => directory, - require => File["/var/www/application/config/environments"] -} - -file { "/var/www/.env": - ensure => "present", - content => template("platform/env.erb") -} - -file { "/var/www/httpdocs/.htaccess": - ensure => "present", - content => template("platform/htaccess.erb") -} - -file { "/var/www/html/index.html": - ensure => "absent" -} - -exec { "bin-update": - path => "/usr/local/node/node-default/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - environment => [ - "HOME=/home/vagrant" - ], - user => "vagrant", - command => "/var/www/bin/update --no-interaction", - cwd => "/var/www", - logoutput => true, - timeout => 0, - require => [ Mysql::Db["ushahidi"], - File["/var/www/.env"], - Package["php5-cli"], - Package["php5-mysqlnd"], - Class["composer"] - ] -} diff --git a/puppet/platform/modules/platform/templates/env.erb b/puppet/platform/modules/platform/templates/env.erb deleted file mode 100644 index 3e08d4640c..0000000000 --- a/puppet/platform/modules/platform/templates/env.erb +++ /dev/null @@ -1,5 +0,0 @@ -DB_HOST=<%= scope.lookupvar('::ipaddress_eth1') %> -DB_NAME=ushahidi -DB_PASS=lamulamulamu -DB_TYPE=MySQLi -DB_USER=ushahidi diff --git a/puppet/platform/modules/platform/templates/htaccess.erb b/puppet/platform/modules/platform/templates/htaccess.erb deleted file mode 100644 index 14230606b9..0000000000 --- a/puppet/platform/modules/platform/templates/htaccess.erb +++ /dev/null @@ -1,22 +0,0 @@ -# Turn on URL rewriting -RewriteEngine On - -# Set base directory -RewriteBase / - -# Protect hidden files from being viewed - - Order Deny,Allow - Deny From All - - -# Uncomment to force redirection to https site. -#RewriteCond %{HTTP:X-Forwarded-Proto} =http -#RewriteRule ^(.*)$ https://%{HTTP_HOST}%{ENV:REWRITEBASE}$1 [R=301,L] - -# Allow any files or directories that exist to be displayed directly -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d - -# Rewrite all other URLs to index.php/URL -RewriteRule .* index.php/$0 [PT] diff --git a/puppet/platform/modules/platform/templates/php-defaults.erb b/puppet/platform/modules/platform/templates/php-defaults.erb deleted file mode 100644 index 56fbfe9758..0000000000 --- a/puppet/platform/modules/platform/templates/php-defaults.erb +++ /dev/null @@ -1,4 +0,0 @@ -; WARNING: managed by puppet! -; Ushahidi PHP configuration overrides - -display_errors = On diff --git a/application/classes/Ushahidi/Acl.php b/src/App/Acl.php similarity index 83% rename from application/classes/Ushahidi/Acl.php rename to src/App/Acl.php index af2e03ab8b..c5b0e609ca 100644 --- a/application/classes/Ushahidi/Acl.php +++ b/src/App/Acl.php @@ -1,4 +1,4 @@ -role) { return false; } - + $role = $this->role_repo->getByName($user->role); // Does the user have the permission? diff --git a/application/classes/Ushahidi/Authenticator/Password.php b/src/App/Authenticator/Password.php similarity index 81% rename from application/classes/Ushahidi/Authenticator/Password.php rename to src/App/Authenticator/Password.php index 37f7f10a19..796e6d2641 100644 --- a/application/classes/Ushahidi/Authenticator/Password.php +++ b/src/App/Authenticator/Password.php @@ -1,4 +1,4 @@ -fetchOne()); - $reader->addFilter(function($row) use ($nbColumns) { + $reader->addFilter(function ($row) use ($nbColumns) { return count($row) == $nbColumns; }); @@ -51,6 +53,6 @@ public function process($file) $reader->setLimit($this->limit); } - return new ArrayIterator($reader->fetchAssoc()); + return new \ArrayIterator($reader->fetchAssoc()); } } diff --git a/application/classes/Ushahidi/CSVReaderFactory.php b/src/App/FileReader/CSVReaderFactory.php similarity index 64% rename from application/classes/Ushahidi/CSVReaderFactory.php rename to src/App/FileReader/CSVReaderFactory.php index b38e329d5a..44ae1cca52 100644 --- a/application/classes/Ushahidi/CSVReaderFactory.php +++ b/src/App/FileReader/CSVReaderFactory.php @@ -1,4 +1,4 @@ -config['media_upload_dir']); + return new LocalAdapter($this->config['media_upload_dir']); } } - diff --git a/application/classes/Ushahidi/FilesystemAdapter/Rackspace.php b/src/App/FilesystemAdapter/Rackspace.php similarity index 72% rename from application/classes/Ushahidi/FilesystemAdapter/Rackspace.php rename to src/App/FilesystemAdapter/Rackspace.php index 446dd91387..7c732f28e4 100644 --- a/application/classes/Ushahidi/FilesystemAdapter/Rackspace.php +++ b/src/App/FilesystemAdapter/Rackspace.php @@ -1,4 +1,4 @@ - $this->config['username'], 'apiKey' => $this->config['apiKey'], )); - $store = $client->objectStoreService(null,$this->config['region']); + $store = $client->objectStoreService(null, $this->config['region']); $container = $store->getContainer($this->config['container']); return new Adapter($container); } } - diff --git a/application/classes/Ushahidi/Hasher/Password.php b/src/App/Hasher/Password.php similarity index 78% rename from application/classes/Ushahidi/Hasher/Password.php rename to src/App/Hasher/Password.php index f485ef80a8..ead74656e9 100644 --- a/application/classes/Ushahidi/Hasher/Password.php +++ b/src/App/Hasher/Password.php @@ -1,4 +1,4 @@ -set('tool.acl', $di->lazyNew('Ushahidi\App\Acl')); +$di->setter['Ushahidi\App\Acl']['setRoleRepo'] = $di->lazyGet('repository.role'); + +$di->set('tool.hasher.password', $di->lazyNew('Ushahidi\App\Hasher\Password')); +$di->set('tool.authenticator.password', $di->lazyNew('Ushahidi\App\Authenticator\Password')); + +$di->set('filereader.csv', $di->lazyNew('Ushahidi\App\FileReader\CSV')); +$di->setter['Ushahidi\App\FileReader\CSV']['setReaderFactory'] = + $di->lazyGet('csv.reader_factory'); + +$di->set('csv.reader_factory', $di->lazyNew('Ushahidi\App\FileReader\CSVReaderFactory')); + +// Register filesystem adapter types +// Currently supported: Local filesysten, AWS S3 v3, Rackspace +// the naming scheme must match the cdn type set in config/cdn +$di->set('adapter.local', $di->lazyNew( + 'Ushahidi\App\FilesystemAdapter\Local', + ['config' => $di->lazyGet('cdn.config')] +)); + +$di->set('adapter.aws', $di->lazyNew( + 'Ushahidi\App\FilesystemAdapter\AWS', + ['config' => $di->lazyGet('cdn.config')] +)); + +$di->set('adapter.rackspace', $di->lazyNew( + 'Ushahidi\App\FilesystemAdapter\Rackspace', + ['config' => $di->lazyGet('cdn.config')] +)); + +// Media Filesystem +// The Ushahidi filesystem adapter returns a flysystem adapter for a given +// cdn type based on the provided configuration +$di->set('tool.filesystem', $di->lazyNew('Ushahidi\App\Filesystem')); +$di->params['Ushahidi\App\Filesystem'] = [ + 'adapter' => $di->lazy(function () use ($di) { + $adapter_type = $di->get('cdn.config'); + $fsa = $di->get('adapter.' . $adapter_type['type']); + + return $fsa->getAdapter(); + }) +]; + +// Defined memcached +$di->set('memcached', $di->lazy(function () use ($di) { + $config = $di->get('ratelimiter.config'); + + $memcached = new Memcached(); + $memcached->addServer($config['memcached']['host'], $config['memcached']['port']); + + return $memcached; +})); + +// Set up login rate limiter +$di->set('ratelimiter.login.flap', $di->lazyNew('BehEh\Flaps\Flap')); + +$di->params['BehEh\Flaps\Flap'] = [ + 'storage' => $di->lazyNew('BehEh\Flaps\Storage\DoctrineCacheAdapter'), + 'name' => 'login' +]; + +$di->set('ratelimiter.login.strategy', $di->lazyNew('BehEh\Flaps\Throttling\LeakyBucketStrategy')); + +// 3 requests every 1 minute by default +$di->params['BehEh\Flaps\Throttling\LeakyBucketStrategy'] = [ + 'requests' => 3, + 'timeSpan' => '1m' +]; + +$di->set('ratelimiter.login', $di->lazyNew('Ushahidi\App\RateLimiter')); + +$di->params['Ushahidi\App\RateLimiter'] = [ + 'flap' => $di->lazyGet('ratelimiter.login.flap'), + 'throttlingStrategy' => $di->lazyGet('ratelimiter.login.strategy'), +]; + +$di->params['BehEh\Flaps\Storage\DoctrineCacheAdapter'] = [ + 'cache' => $di->lazyGet('ratelimiter.cache') +]; + +// Rate limit storage cache +$di->set('ratelimiter.cache', function () use ($di) { + $config = $di->get('ratelimiter.config'); + $cache = $config['cache']; + + if ($cache === 'memcached') { + $di->setter['Doctrine\Common\Cache\MemcachedCache']['setMemcached'] = + $di->lazyGet('memcached'); + + return $di->newInstance('Doctrine\Common\Cache\MemcachedCache'); + } elseif ($cache === 'filesystem') { + $di->params['Doctrine\Common\Cache\FilesystemCache'] = [ + 'directory' => $config['filesystem']['directory'], + ]; + + return $di->newInstance('Doctrine\Common\Cache\FilesystemCache'); + } + + // Fall back to using in-memory cache if none is configured + return $di->newInstance('Doctrine\Common\Cache\ArrayCache'); +}); + +// Rate limiter violation handler +$di->setter['BehEh\Flaps\Flap']['setViolationHandler'] = + $di->lazyNew('Ushahidi\App\ThrottlingViolationHandler'); diff --git a/application/classes/Ushahidi/RateLimiter.php b/src/App/RateLimiter.php similarity index 85% rename from application/classes/Ushahidi/RateLimiter.php rename to src/App/RateLimiter.php index 02dda4b0e6..98da9f689c 100644 --- a/application/classes/Ushahidi/RateLimiter.php +++ b/src/App/RateLimiter.php @@ -1,4 +1,4 @@ -add($command()); diff --git a/src/Console/Command.php b/src/Console/Command.php index e9e5fff4e0..48cc7657e8 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -17,7 +17,7 @@ use Symfony\Component\Console\Command\Command as ConsoleCommand; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Helper\TableHelper; +use Symfony\Component\Console\Helper\Table; abstract class Command extends ConsoleCommand { @@ -40,7 +40,7 @@ protected function handleResponse($response, OutputInterface $output) { if (is_array($response)) { // Display arrays as tables. - $table = $this->getHelperSet()->get('table'); + $table = new Table($output); $keys = array_keys($response); @@ -64,7 +64,6 @@ protected function handleResponse($response, OutputInterface $output) // Display the table using compact layout. $table - ->setLayout(TableHelper::LAYOUT_COMPACT) ->render($output); } else { // Otherwise, just write the response. diff --git a/src/Console/Command/Import.php b/src/Console/Command/Import.php index d518994ab8..b4d461283d 100644 --- a/src/Console/Command/Import.php +++ b/src/Console/Command/Import.php @@ -38,7 +38,7 @@ class Import extends Command * Set Data Importers * @param [Ushahidi\DataImport\Importer, ..] $importers */ - public function setImporters(Array $importers) + public function setImporters(array $importers) { $this->importers = $importers; } diff --git a/src/Core/Data.php b/src/Core/Data.php index aff606a7b7..b556ab9230 100644 --- a/src/Core/Data.php +++ b/src/Core/Data.php @@ -33,7 +33,7 @@ abstract class Data * @param Array $data raw input * @return void */ - public function __construct(Array $data) + public function __construct(array $data) { // Get the (empty) array that currently exists, this tells us what // properties are allowed in this object. @@ -88,7 +88,7 @@ public function asArray() * @param Array $compare existing data * @return Data */ - public function getDifferent(Array $compare) + public function getDifferent(array $compare) { // Get the difference of current data and comparison. // This will allow null values in $compare to be overridden, diff --git a/src/Core/Entity.php b/src/Core/Entity.php index 3eded5c5c7..c8ae7c59f7 100644 --- a/src/Core/Entity.php +++ b/src/Core/Entity.php @@ -41,7 +41,7 @@ public function asArray(); * @param Array $data * @return $this */ - public function setState(Array $data); + public function setState(array $data); /** * Get all values that have been changed since initial state was defined. diff --git a/src/Core/Entity/Form.php b/src/Core/Entity/Form.php index 99dd8b2590..90ce73bd29 100644 --- a/src/Core/Entity/Form.php +++ b/src/Core/Entity/Form.php @@ -24,9 +24,11 @@ class Form extends StaticEntity protected $disabled; protected $created; protected $updated; + protected $hide_author; protected $require_approval; protected $everyone_can_create; protected $can_create; + protected $tags; // DataTransformer protected function getDefinition() @@ -46,9 +48,11 @@ protected function getDefinition() 'disabled' => 'bool', 'created' => 'int', 'updated' => 'int', + 'hide_author' => 'bool', 'require_approval' => 'bool', 'everyone_can_create' => 'bool', 'can_create' => 'array', + 'tags' => 'array', ]; } @@ -57,4 +61,11 @@ public function getResource() { return 'forms'; } + + // StatefulData + protected function getImmutable() + { + // Hack: Add computed properties to immutable list + return array_merge(parent::getImmutable(), ['tags', 'can_create']); + } } diff --git a/src/Core/Entity/FormAttribute.php b/src/Core/Entity/FormAttribute.php index fac76c818b..28c16724b2 100644 --- a/src/Core/Entity/FormAttribute.php +++ b/src/Core/Entity/FormAttribute.php @@ -28,6 +28,7 @@ class FormAttribute extends StaticEntity protected $cardinality; protected $config = []; protected $form_stage_id; + protected $response_private; // StatefulData protected function getDerived() @@ -55,6 +56,7 @@ protected function getDefinition() 'config' => '*json', 'form_stage' => false, /* alias */ 'form_stage_id' => 'int', + 'response_private' => 'bool', ]; } diff --git a/src/Core/Entity/FormRoleRepository.php b/src/Core/Entity/FormRoleRepository.php index 936c4918cf..9a908841de 100644 --- a/src/Core/Entity/FormRoleRepository.php +++ b/src/Core/Entity/FormRoleRepository.php @@ -36,5 +36,5 @@ public function existsInFormRole($role_id, $form_id); * @param [Ushahidi\Core\Entity\FormRole, ...] $entities * @return [Ushahidi\Core\Entity\FormRole, ...] */ - public function updateCollection(Array $entities); + public function updateCollection(array $entities); } diff --git a/src/Core/Entity/FormStage.php b/src/Core/Entity/FormStage.php index ba74a88c3a..a42dd1c8d3 100644 --- a/src/Core/Entity/FormStage.php +++ b/src/Core/Entity/FormStage.php @@ -22,6 +22,7 @@ class FormStage extends StaticEntity protected $icon; protected $type; protected $required; + protected $show_when_published; protected $description; // DataTransformer @@ -30,6 +31,7 @@ protected function getDefinition() return [ 'id' => 'int', 'description' => 'string', + 'show_when_published' => 'boolean', 'type' => 'string', 'form_id' => 'int', 'label' => 'string', diff --git a/src/Core/Entity/RoleRepository.php b/src/Core/Entity/RoleRepository.php index 5f30c8ef2f..4482d92d7b 100644 --- a/src/Core/Entity/RoleRepository.php +++ b/src/Core/Entity/RoleRepository.php @@ -22,7 +22,7 @@ interface RoleRepository extends * @param Array $roles * @return Boolean */ - public function doRolesExist(Array $roles = null); + public function doRolesExist(array $roles = null); /** * @param String $name diff --git a/src/Core/Entity/Tag.php b/src/Core/Entity/Tag.php index 5c0f1554c9..45bf47096b 100644 --- a/src/Core/Entity/Tag.php +++ b/src/Core/Entity/Tag.php @@ -26,6 +26,7 @@ class Tag extends StaticEntity protected $priority; protected $created; protected $role; + protected $children; // StatefulData protected function getDerived() @@ -55,6 +56,7 @@ protected function getDefinition() 'priority' => 'int', 'created' => 'int', 'role' => '*json', + 'children' => 'array', ]; } @@ -63,4 +65,9 @@ public function getResource() { return 'tags'; } + protected function getImmutable() + { + // Hack: Add computed properties to immutable list + return array_merge(parent::getImmutable(), ['children']); + } } diff --git a/src/Core/Entity/TagRepository.php b/src/Core/Entity/TagRepository.php new file mode 100644 index 0000000000..d1e11434d5 --- /dev/null +++ b/src/Core/Entity/TagRepository.php @@ -0,0 +1,21 @@ + + * @package Ushahidi\Application + * @copyright 2014 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) + */ + +namespace Ushahidi\Core\Entity; + +use Ushahidi\Core\Entity\Repository\EntityGet; +use Ushahidi\Core\Entity\Repository\EntityExists; + +interface TagRepository extends + EntityGet, + EntityExists +{ +} diff --git a/src/Core/Entity/User.php b/src/Core/Entity/User.php index 74d4716301..ec0e3a745d 100644 --- a/src/Core/Entity/User.php +++ b/src/Core/Entity/User.php @@ -26,6 +26,7 @@ class User extends StaticEntity protected $created; protected $updated; protected $role; + protected $language; // DataTransformer protected function getDefinition() @@ -42,6 +43,7 @@ protected function getDefinition() 'created' => 'int', 'updated' => 'int', 'role' => 'string', + 'language' => 'string', ]; } diff --git a/src/Core/Exception/ValidatorException.php b/src/Core/Exception/ValidatorException.php index 551bcc383c..f3c97e2dc9 100644 --- a/src/Core/Exception/ValidatorException.php +++ b/src/Core/Exception/ValidatorException.php @@ -18,7 +18,7 @@ class ValidatorException extends \InvalidArgumentException { private $errors; - public function __construct($message, Array $errors, Exception $previous = null) + public function __construct($message, array $errors, Exception $previous = null) { $flatErrors = iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($errors)), false); @@ -28,7 +28,7 @@ public function __construct($message, Array $errors, Exception $previous = null) $this->setErrors($errors); } - public function setErrors(Array $errors) + public function setErrors(array $errors) { $this->errors = $errors; } diff --git a/src/Core/SearchData.php b/src/Core/SearchData.php index ca744acf2c..d9ad75c302 100644 --- a/src/Core/SearchData.php +++ b/src/Core/SearchData.php @@ -34,7 +34,7 @@ class SearchData * * @param Array $filters */ - public function __construct(Array $filters = null) + public function __construct(array $filters = null) { if ($filters) { $this->setFilters($filters); @@ -81,7 +81,7 @@ public function __isset($key) * @param Array $sorting * @return $this */ - public function setSortingKeys(Array $sorting) + public function setSortingKeys(array $sorting) { $this->sorting = $sorting; return $this; diff --git a/src/Core/Tool/Authorizer/ContactAuthorizer.php b/src/Core/Tool/Authorizer/ContactAuthorizer.php index 4d7c464036..6b571b8b70 100644 --- a/src/Core/Tool/Authorizer/ContactAuthorizer.php +++ b/src/Core/Tool/Authorizer/ContactAuthorizer.php @@ -56,7 +56,6 @@ public function isAllowed(Entity $entity, $privilege) // Contacts should not be deleted. if ($this->isUserOwner($entity, $user) and in_array($privilege, ['create', 'read', 'update'])) { - return true; } diff --git a/src/Core/Tool/Authorizer/NotificationAuthorizer.php b/src/Core/Tool/Authorizer/NotificationAuthorizer.php index dddc6d7a6f..fd5c7aa402 100644 --- a/src/Core/Tool/Authorizer/NotificationAuthorizer.php +++ b/src/Core/Tool/Authorizer/NotificationAuthorizer.php @@ -56,7 +56,6 @@ public function isAllowed(Entity $entity, $privilege) // Allow create, read, update and delete if owner. if ($this->isUserOwner($entity, $user) and in_array($privilege, ['create', 'read', 'update', 'delete'])) { - return true; } diff --git a/src/Core/Tool/Date.php b/src/Core/Tool/Date.php index e7ab3766b4..5117f1c207 100644 --- a/src/Core/Tool/Date.php +++ b/src/Core/Tool/Date.php @@ -68,7 +68,7 @@ public function getTimestampFromString($time, $format = null) * @param String $format non-default format * @return Array */ - public function addTimestampToResults(Array $results, $key = 'date', $add = 'ts', $format = null) + public function addTimestampToResults(array $results, $key = 'date', $add = 'ts', $format = null) { if (!$format) { $format = $this->getDateFormat(); diff --git a/src/Core/Tool/Mailer.php b/src/Core/Tool/Mailer.php index b38493e132..c9ccbceeca 100644 --- a/src/Core/Tool/Mailer.php +++ b/src/Core/Tool/Mailer.php @@ -23,5 +23,5 @@ interface Mailer * @param Array|null $params Params for populating the template * @return void */ - public function send($to, $type, Array $params = null); + public function send($to, $type, array $params = null); } diff --git a/src/Core/Tool/MappingTransformer.php b/src/Core/Tool/MappingTransformer.php index aefea4aef8..e57543a78a 100644 --- a/src/Core/Tool/MappingTransformer.php +++ b/src/Core/Tool/MappingTransformer.php @@ -17,6 +17,6 @@ interface MappingTransformer extends Transformer { - public function setMap(Array $map); - public function setFixedValues(Array $fixedValues); + public function setMap(array $map); + public function setFixedValues(array $fixedValues); } diff --git a/src/Core/Tool/Transformer.php b/src/Core/Tool/Transformer.php index 33e2d1ae52..0a23c271d7 100644 --- a/src/Core/Tool/Transformer.php +++ b/src/Core/Tool/Transformer.php @@ -15,5 +15,5 @@ interface Transformer { - public function interact(Array $data); + public function interact(array $data); } diff --git a/src/Core/Tool/ValidationEngine.php b/src/Core/Tool/ValidationEngine.php index 01675ab762..7b31e1039c 100644 --- a/src/Core/Tool/ValidationEngine.php +++ b/src/Core/Tool/ValidationEngine.php @@ -19,7 +19,7 @@ interface ValidationEngine * * @param Array $data array of data in $key => $value format */ - public function setData(Array $data); + public function setData(array $data); /** * Get data by its array key @@ -33,7 +33,7 @@ public function getData($key = null); * * @param Array $data array of data in $key => $value format */ - public function setFullData(Array $data); + public function setFullData(array $data); /** * Get full data by its array key @@ -47,7 +47,7 @@ public function getFullData($key = null); * * @return null */ - public function rules($field, Array $rules); + public function rules($field, array $rules); /** * Check the data against the previously set rules diff --git a/src/Core/Tool/Validator.php b/src/Core/Tool/Validator.php index 681476b659..ee2c016f18 100644 --- a/src/Core/Tool/Validator.php +++ b/src/Core/Tool/Validator.php @@ -40,7 +40,7 @@ abstract protected function getRules(); * @param Array $fullData an array of full entity data for reference during validation * @return bool */ - public function check(Array $data, Array $fullData = []) + public function check(array $data, array $fullData = []) { // If no full data is passed, fallback to changed values if (!$fullData) { diff --git a/src/Core/Traits/CollectionLoader.php b/src/Core/Traits/CollectionLoader.php index 52d46bbf1d..388c3600b4 100644 --- a/src/Core/Traits/CollectionLoader.php +++ b/src/Core/Traits/CollectionLoader.php @@ -22,7 +22,7 @@ trait CollectionLoader * @param Array $data * @return Ushahidi\Core\Entity */ - abstract public function getEntity(Array $data = null); + abstract public function getEntity(array $data = null); /** * Converts an array of results into an array of entities, @@ -30,7 +30,7 @@ abstract public function getEntity(Array $data = null); * @param Array $results * @return Array */ - protected function getCollection(Array $results) + protected function getCollection(array $results) { $collection = []; foreach ($results as $row) { diff --git a/src/Core/Traits/DataTransformer.php b/src/Core/Traits/DataTransformer.php index 1727e8e99e..05c7c7dc2d 100644 --- a/src/Core/Traits/DataTransformer.php +++ b/src/Core/Traits/DataTransformer.php @@ -171,7 +171,7 @@ protected function getCustomTransformer($type) * @param Array $data * @return Array */ - protected function transform(Array $data) + protected function transform(array $data) { $definition = $this->getDefinition(); diff --git a/src/Core/Traits/FilterRecords.php b/src/Core/Traits/FilterRecords.php index ce0b72d0f9..74f92fdb6e 100644 --- a/src/Core/Traits/FilterRecords.php +++ b/src/Core/Traits/FilterRecords.php @@ -37,7 +37,7 @@ trait FilterRecords * @param Array $filters * @return $this */ - public function setFilters(Array $filters) + public function setFilters(array $filters) { $this->filters = $filters; return $this; @@ -71,7 +71,7 @@ public function setFilter($name, $value) * @param Array $force force all parameters to be defined * @return Array */ - public function getFilters(Array $allowed, $force = false) + public function getFilters(array $allowed, $force = false) { $filters = array_intersect_key($this->filters, array_flip($allowed)); if ($force) { diff --git a/src/Core/Traits/IdentifyRecords.php b/src/Core/Traits/IdentifyRecords.php index ca167ab287..e8da2a355f 100644 --- a/src/Core/Traits/IdentifyRecords.php +++ b/src/Core/Traits/IdentifyRecords.php @@ -35,7 +35,7 @@ trait IdentifyRecords * @param Array $identifiers * @return $this */ - public function setIdentifiers(Array $identifiers) + public function setIdentifiers(array $identifiers) { $this->identifiers = array_replace($this->identifiers, $identifiers); return $this; diff --git a/src/Core/Traits/ModifyRecords.php b/src/Core/Traits/ModifyRecords.php index 3d757a8952..2add3b79ad 100644 --- a/src/Core/Traits/ModifyRecords.php +++ b/src/Core/Traits/ModifyRecords.php @@ -37,7 +37,7 @@ trait ModifyRecords * @param Array $payload * @return $this */ - public function setPayload(Array $payload) + public function setPayload(array $payload) { $this->payload = $payload; return $this; diff --git a/src/Core/Traits/PostValueRestrictions.php b/src/Core/Traits/PostValueRestrictions.php new file mode 100644 index 0000000000..8d392a466a --- /dev/null +++ b/src/Core/Traits/PostValueRestrictions.php @@ -0,0 +1,54 @@ + + * @package Ushahidi\Application + * @copyright 2014 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) + */ + +namespace Ushahidi\Core\Traits; + +use Ushahidi\Core\Entity\User; +use Ushahidi\Core\Entity\Post; +use Ushahidi\Core\Entity\FormRepository; + +trait PostValueRestrictions +{ + + + public function canUserSeeAuthor(Post $post, FormRepository $form_repo, $user) + { + + if ($post->form_id) { + if ($this->canUserEditForm($post->form_id, $user)) { + return true; + } + + return !$form_repo->isAuthorHidden($post->form_id); + } + + return true; + } + + + /** + * Test whether the post instance requires value restriction + * @param Post $post + * @return Boolean + */ + public function canUserReadPostsValues(Post $post, $user) + { + return $this->canUserEditForm($post->form_id, $user); + } + + /* FormRole */ + protected function canUserEditForm($form_id, $user) + { + return $this->isUserAdmin($user) || $this->hasPermission($user, $this->getPermission()); + } +} diff --git a/src/Core/Traits/StatefulData.php b/src/Core/Traits/StatefulData.php index d3ae1cd51d..7b30691605 100644 --- a/src/Core/Traits/StatefulData.php +++ b/src/Core/Traits/StatefulData.php @@ -30,7 +30,7 @@ trait StatefulData * * @param Array $data */ - public function __construct(Array $data = null) + public function __construct(array $data = null) { // Initialize change tracking. static::$changed[$this->getObjectId()] = []; @@ -123,7 +123,7 @@ final protected function getObjectId() * @param Array $data * @return $this */ - public function setState(Array $data) + public function setState(array $data) { // Allow for data to be filled in by deriving from other values. foreach ($this->getDerived() as $key => $possible) { diff --git a/src/Core/Usecase/CreateRepository.php b/src/Core/Usecase/CreateRepository.php index 052accc5b4..76f9fa5cb2 100644 --- a/src/Core/Usecase/CreateRepository.php +++ b/src/Core/Usecase/CreateRepository.php @@ -28,5 +28,5 @@ public function create(Entity $entity); * @param Array $data * @return Entity */ - public function getEntity(Array $data = null); + public function getEntity(array $data = null); } diff --git a/src/Core/Usecase/ImportUsecase.php b/src/Core/Usecase/ImportUsecase.php index cf8801f926..205e6e226f 100644 --- a/src/Core/Usecase/ImportUsecase.php +++ b/src/Core/Usecase/ImportUsecase.php @@ -109,7 +109,6 @@ public function interact() $created_entities = array(); // Fetch a record foreach ($this->payload as $index => $record) { - // ... transform record $entity = $this->transform($record); diff --git a/src/Core/Usecase/Message/CreateMessage.php b/src/Core/Usecase/Message/CreateMessage.php index cbcdc034b4..1ae8d2b11c 100644 --- a/src/Core/Usecase/Message/CreateMessage.php +++ b/src/Core/Usecase/Message/CreateMessage.php @@ -30,8 +30,7 @@ protected function getEntity() } // If no user information is provided, default to the current session user. - if ( - empty($entity->user_id) && + if (empty($entity->user_id) && $this->auth->getUserId() ) { $entity->setState(['user_id' => $this->auth->getUserId()]); diff --git a/src/Core/Usecase/Post/CreatePost.php b/src/Core/Usecase/Post/CreatePost.php index 6712e9a4bf..103e0c0ad5 100644 --- a/src/Core/Usecase/Post/CreatePost.php +++ b/src/Core/Usecase/Post/CreatePost.php @@ -24,8 +24,7 @@ protected function getEntity() $entity = parent::getEntity(); // If no user information is provided, default to the current session user. - if ( - empty($entity->user_id) && + if (empty($entity->user_id) && empty($entity->author_email) && empty($entity->author_realname) && $this->auth->getUserId() diff --git a/src/Core/Usecase/Post/StatsPostRepository.php b/src/Core/Usecase/Post/StatsPostRepository.php index 2e0077f9ca..8311afe157 100644 --- a/src/Core/Usecase/Post/StatsPostRepository.php +++ b/src/Core/Usecase/Post/StatsPostRepository.php @@ -21,5 +21,5 @@ interface StatsPostRepository * @param SearchData $search * @return Array */ - public function getGroupedTotals(SearchData $search) + public function getGroupedTotals(SearchData $search); } diff --git a/src/Core/Usecase/Post/UpdatePostValueRepository.php b/src/Core/Usecase/Post/UpdatePostValueRepository.php index 8b874a0d9b..032e7e3d1d 100644 --- a/src/Core/Usecase/Post/UpdatePostValueRepository.php +++ b/src/Core/Usecase/Post/UpdatePostValueRepository.php @@ -35,5 +35,5 @@ public function updateValue($id, $value); * @param Integer $post_id * @param Array $ids */ - public function deleteNotIn($post_id, Array $ids); + public function deleteNotIn($post_id, array $ids); } diff --git a/src/Core/Usecase/Post/ValuesForPostRepository.php b/src/Core/Usecase/Post/ValuesForPostRepository.php index c0fd608109..c2b4aa08ea 100644 --- a/src/Core/Usecase/Post/ValuesForPostRepository.php +++ b/src/Core/Usecase/Post/ValuesForPostRepository.php @@ -19,7 +19,12 @@ interface ValuesForPostRepository * @param Array $include_attributes * @return [Ushahidi\Core\Entity\PostValue, ...] */ - public function getAllForPost($post_id, Array $include_attributes = []); + public function getAllForPost( + $post_id, + array $include_attributes = [], + array $exclude_stages = [], + $restricted = false + ); /** * @param int $post_id diff --git a/src/Core/Usecase/ReadRepository.php b/src/Core/Usecase/ReadRepository.php index 37df1bed91..f30923bf3e 100644 --- a/src/Core/Usecase/ReadRepository.php +++ b/src/Core/Usecase/ReadRepository.php @@ -20,5 +20,5 @@ interface ReadRepository extends EntityGet * @param Array $data * @return Entity */ - public function getEntity(Array $data = null); + public function getEntity(array $data = null); } diff --git a/src/Core/Usecase/SearchRepository.php b/src/Core/Usecase/SearchRepository.php index 8049acb6a7..13addab271 100644 --- a/src/Core/Usecase/SearchRepository.php +++ b/src/Core/Usecase/SearchRepository.php @@ -20,7 +20,7 @@ interface SearchRepository * @param Array $data * @return Entity */ - public function getEntity(Array $data = null); + public function getEntity(array $data = null); /** * Get fields that can be used for searches. diff --git a/src/Core/Usecase/Set/VerifySetExists.php b/src/Core/Usecase/Set/VerifySetExists.php index 206e9fae25..fc7ef4d010 100644 --- a/src/Core/Usecase/Set/VerifySetExists.php +++ b/src/Core/Usecase/Set/VerifySetExists.php @@ -13,7 +13,7 @@ use Ushahidi\Core\Entity; -trait verifySetExists +trait VerifySetExists { /** diff --git a/src/Factory/AuthorizerFactory.php b/src/Factory/AuthorizerFactory.php index bd56d292a7..4e7a585492 100644 --- a/src/Factory/AuthorizerFactory.php +++ b/src/Factory/AuthorizerFactory.php @@ -26,7 +26,7 @@ class AuthorizerFactory /** * @param Array $map */ - public function __construct(Array $map) + public function __construct(array $map) { $this->map = $map; } diff --git a/src/Factory/DataFactory.php b/src/Factory/DataFactory.php index 400e8e9763..33b0efff66 100644 --- a/src/Factory/DataFactory.php +++ b/src/Factory/DataFactory.php @@ -28,7 +28,7 @@ class DataFactory /** * @param Array $actions */ - public function __construct(Array $actions) + public function __construct(array $actions) { $this->actions = $actions; } @@ -42,7 +42,7 @@ public function __construct(Array $actions) * @param Array $params * @return Ushahidi\Core\Data */ - public function get($action, Array $params = null) + public function get($action, array $params = null) { if (empty($this->actions[$action])) { throw new \InvalidArgumentException(sprintf( diff --git a/src/Factory/FormatterFactory.php b/src/Factory/FormatterFactory.php index 0653929472..05121f0969 100644 --- a/src/Factory/FormatterFactory.php +++ b/src/Factory/FormatterFactory.php @@ -40,8 +40,8 @@ class FormatterFactory * @param Closure $factory */ public function __construct( - Array $map, - Array $collections, + array $map, + array $collections, $factory ) { $this->map = $map; diff --git a/src/Factory/RepositoryFactory.php b/src/Factory/RepositoryFactory.php index 8119e06628..f0100b7900 100644 --- a/src/Factory/RepositoryFactory.php +++ b/src/Factory/RepositoryFactory.php @@ -26,7 +26,7 @@ class RepositoryFactory /** * @param Array $map */ - public function __construct(Array $map) + public function __construct(array $map) { $this->map = $map; } diff --git a/src/Factory/UsecaseFactory.php b/src/Factory/UsecaseFactory.php index cb659540d7..b820fc2539 100644 --- a/src/Factory/UsecaseFactory.php +++ b/src/Factory/UsecaseFactory.php @@ -68,8 +68,8 @@ public function __construct( FormatterFactory $formatters, RepositoryFactory $repositories, ValidatorFactory $validators, - Array $actions, - Array $map + array $actions, + array $map ) { $this->authorizers = $authorizers; $this->data = $data; diff --git a/src/Factory/ValidatorFactory.php b/src/Factory/ValidatorFactory.php index 55adbc7331..70fcb507cc 100644 --- a/src/Factory/ValidatorFactory.php +++ b/src/Factory/ValidatorFactory.php @@ -27,7 +27,7 @@ class ValidatorFactory /** * @param Array $map */ - public function __construct(Array $map) + public function __construct(array $map) { $this->map = $map; } diff --git a/src/Init.php b/src/Init.php index 5711b52e30..849265137b 100644 --- a/src/Init.php +++ b/src/Init.php @@ -66,6 +66,9 @@ function feature($name) // `namespace.`, such as `acme.tool.hash.magic`. $di = service(); +// Disable auto resolution (as recommended in AuraDI docs) +$di->setAutoResolve(false); + // Console application is used for command line tools. $di->set('app.console', $di->lazyNew('Ushahidi\Console\Application')); @@ -200,11 +203,11 @@ function feature($name) // Use cases are used to join multiple collaborators together for a single interaction. $di->set('factory.usecase', $di->lazyNew('Ushahidi\Factory\UsecaseFactory')); -$di->params['Ushahidi\Api\Factory\UsecaseFactory'] = [ +$di->params['Ushahidi\Factory\UsecaseFactory'] = [ 'authorizers' => $di->lazyGet('factory.authorizer'), 'repositories' => $di->lazyGet('factory.repository'), - 'formatters' => $di->lazyGet('factory.formatters'), - 'validators' => $di->lazyGet('factory.validators'), + 'formatters' => $di->lazyGet('factory.formatter'), + 'validators' => $di->lazyGet('factory.validator'), 'data' => $di->lazyGet('factory.data'), ]; @@ -347,6 +350,7 @@ function feature($name) $di->setter['Ushahidi\Core\Traits\DataImportAccess']['setEnabled'] = $di->lazyGet('data-import.enabled'); // Tools +$di->set('tool.signer', $di->lazyNew('Ushahidi\Core\Tool\Signer')); $di->set('tool.uploader', $di->lazyNew('Ushahidi\Core\Tool\Uploader')); $di->params['Ushahidi\Core\Tool\Uploader'] = [ 'fs' => $di->lazyGet('tool.filesystem'), @@ -396,3 +400,5 @@ function feature($name) ]; $di->set('authorizer.console', $di->lazyNew('Ushahidi\Console\Authorizer\ConsoleAuthorizer')); + +require __DIR__ . '/App/Init.php'; diff --git a/src/ruleset.xml b/src/ruleset.xml new file mode 100644 index 0000000000..5310434f9c --- /dev/null +++ b/src/ruleset.xml @@ -0,0 +1,9 @@ + + + Ushahidi uses PSR2 with tabs instead of spaces + + + + + + diff --git a/application/tests/bootstrap.php b/tests/bootstrap.php similarity index 59% rename from application/tests/bootstrap.php rename to tests/bootstrap.php index 2444416b03..8ac9cf8120 100644 --- a/application/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,24 +1,21 @@ 0) - { + if ($ob_len > 0) { ob_end_flush(); - } - else - { + } else { ob_end_clean(); } } // Enable the unittest module -Kohana::modules(Kohana::modules() + array('unittest' => MODPATH.'unittest')); \ No newline at end of file +// Kohana::modules(Kohana::modules() + array('unittest' => MODPATH.'unittest')); diff --git a/application/tests/datasets/ushahidi/Base.yml b/tests/datasets/ushahidi/Base.yml similarity index 84% rename from application/tests/datasets/ushahidi/Base.yml rename to tests/datasets/ushahidi/Base.yml index 6101d43007..5edd3f86cf 100644 --- a/application/tests/datasets/ushahidi/Base.yml +++ b/tests/datasets/ushahidi/Base.yml @@ -64,7 +64,8 @@ forms: name: "Test Form" type: "report" description: "Testing form" - require_approval: 1 + require_approval: 0 + hide_author: 0 everyone_can_create: 1 - id: 2 @@ -72,6 +73,7 @@ forms: type: "report" description: "Missing persons" require_approval: 0 + hide_author: 0 everyone_can_create: 0 - id: 3 @@ -79,33 +81,72 @@ forms: type: "report" description: "Test video embed" require_approval: 0 + hide_author: 0 + everyone_can_create: 0 + - + id: 4 + name: "Role Restriction" + type: "report" + description: "Test role restriction and private responses" + require_approval: 1 + hide_author: 1 everyone_can_create: 0 form_roles: - id: 1 form_id: 2 role_id: 1 + - + id: 2 + form_id: 4 + role_id: 2 + - + id: 3 + form_id: 4 + role_id: 3 form_stages: - id: 1 form_id: 1 label: "Main" + show_when_published: 1 + type: "post" - id: 2 form_id: 1 label: "2nd step" + show_when_published: 1 + type: "task" - id: 3 form_id: 1 label: "3rd step" + show_when_published: 1 + type: "task" - id: 4 form_id: 2 label: "Main" + show_when_published: 1 + type: "post" - id: 5 form_id: 3 label: "Post" + show_when_published: 1 + type: "post" + - + id: 6 + form_id: 4 + label: "restricted" + show_when_published: 0 + type: "task" + - + id: 7 + form_id: 4 + label: "Post" + show_when_published: 1 + type: "post" form_attributes: - id: 1 @@ -113,6 +154,7 @@ form_attributes: key: "test_varchar" type: "varchar" input: "text" + response_private: 0 required: 0 priority: 1 options: "" @@ -124,6 +166,7 @@ form_attributes: key: "test_point" type: "point" input: "location" + response_private: 0 required: 0 priority: 1 options: "" @@ -135,6 +178,7 @@ form_attributes: key: "full_name" type: "varchar" input: "text" + response_private: 0 required: 0 priority: 1 options: "" @@ -146,6 +190,7 @@ form_attributes: key: "description" type: "description" input: "textarea" + response_private: 0 required: 0 priority: 0 options: "" @@ -157,6 +202,7 @@ form_attributes: key: "date_of_birth" type: "datetime" input: "date" + response_private: 0 required: 0 priority: 3 options: "" @@ -168,6 +214,7 @@ form_attributes: key: "missing_date" type: "datetime" input: "date" + response_private: 0 required: 0 priority: 4 options: "" @@ -179,6 +226,7 @@ form_attributes: key: "last_location" type: "varchar" input: "text" + response_private: 0 required: 1 priority: 5 options: "" @@ -190,6 +238,7 @@ form_attributes: key: "last_location_point" type: "point" input: "location" + response_private: 0 required: 0 priority: 5 options: "" @@ -201,6 +250,7 @@ form_attributes: key: "geometry_test" type: "geometry" input: "text" + response_private: 0 required: 0 priority: 5 options: "" @@ -212,6 +262,7 @@ form_attributes: key: "missing_status" type: "varchar" input: "select" + response_private: 0 required: 0 options: '["information_sought","is_note_author","believed_alive","believed_missing","believed_dead"]' priority: 5 @@ -223,6 +274,7 @@ form_attributes: key: "links" type: "varchar" input: "text" + response_private: 0 required: 0 priority: 7 cardinality: 0 @@ -233,6 +285,7 @@ form_attributes: key: "second_point" type: "point" input: "location" + response_private: 0 required: 0 priority: 5 options: "" @@ -244,6 +297,7 @@ form_attributes: key: "person_status" type: "varchar" input: "select" + response_private: 0 required: 0 options: '["information_sought","is_note_author","believed_alive","believed_missing","believed_dead"]' priority: 5 @@ -255,6 +309,7 @@ form_attributes: key: "media_test" type: "media" input: "upload" + response_private: 0 required: 0 priority: 7 cardinality: 1 @@ -265,6 +320,7 @@ form_attributes: key: "possible_actions" type: "varchar" input: "checkbox" + response_private: 0 required: 0 options: '["ground_search","medical_evacuation"]' priority: 5 @@ -277,6 +333,7 @@ form_attributes: key: "video_field" type: "video" input: "video" + response_private: 0 required: 0 options: '[]' priority: 5 @@ -289,6 +346,7 @@ form_attributes: key: "title" type: "title" input: "text" + response_private: 0 required: 0 priority: 0 options: "" @@ -296,15 +354,148 @@ form_attributes: form_stage_id: 1 - id: 18 + label: "Test Field Level Locking 1" + key: "test_field_locking_hidden_1" + type: "text" + input: "text" + response_private: 1 + required: 0 + priority: 0 + options: "" + cardinality: 1 + form_stage_id: 6 + - + id: 19 + label: "Test Field Level Locking 2" + key: "test_field_locking_visible_1" + type: "varchar" + input: "text" + response_private: 0 + required: 0 + priority: 0 + options: "" + cardinality: 1 + form_stage_id: 6 + - + id: 20 + label: "Test Field Level Locking 3" + key: "test_field_locking_visible_2" + type: "title" + input: "text" + response_private: 0 + required: 0 + priority: 0 + options: "" + cardinality: 1 + form_stage_id: 6 + - + id: 21 + label: "Test Field Level Locking 4" + key: "test_field_locking_hidden_2" + type: "text" + input: "text" + response_private: 1 + required: 0 + priority: 0 + options: "" + cardinality: 1 + form_stage_id: 6 + - + id: 22 + label: "Test Field Level Locking 5" + key: "test_field_locking_visible_3" + type: "varchar" + input: "text" + response_private: 0 + required: 0 + priority: 0 + options: "" + cardinality: 1 + form_stage_id: 6 + - + id: 23 + label: "Test Field Level Locking 6" + key: "test_field_locking_hidden_3" + type: "text" + input: "text" + response_private: 1 + required: 0 + priority: 0 + options: "" + cardinality: 1 + form_stage_id: 7 + - + id: 24 + label: "Test Field Level Locking 7" + key: "test_field_locking_visible_4" + type: "varchar" + input: "text" + response_private: 0 + required: 0 + priority: 0 + options: "" + cardinality: 1 + form_stage_id: 7 + - + id: 25 label: "Test markdown" key: "markdown" type: "markdown" input: "text" + response_private: 0 required: 0 priority: 0 options: "" cardinality: 1 form_stage_id: 1 + - + id: 26 + label: "Categories" + key: "tags1" + type: "tags" + input: "tags" + response_private: 0 + required: 0 + priority: 3 + options: '["1","2","3","4","5","6","7"]' + cardinality: 0 + form_stage_id: 1 + - + id: 27 + label: "Categories" + key: "tags2" + type: "tags" + input: "tags" + response_private: 0 + required: 0 + priority: 3 + options: '["1","2","3","5"]' + cardinality: 0 + form_stage_id: 4 + - + id: 28 + label: "Categories" + key: "tags3" + type: "tags" + input: "tags" + response_private: 0 + required: 0 + priority: 3 + options: '["1","2","3","5","6","7"]' + cardinality: 0 + form_stage_id: 5 + - + id: 29 + label: "Categories" + key: "tags4" + type: "tags" + input: "tags" + response_private: 0 + required: 0 + priority: 3 + options: '["1","2","3","4","5","6","7"]' + cardinality: 0 + form_stage_id: 7 posts: - id: 1 @@ -605,6 +796,36 @@ posts: created: 1412025016 published_to: '["user"]' post_date: "2014-09-29 14:10:16" + - + id: 121 + form_id: 4 + parent_id: + user_id: 3 + author_email: "test@ushahidi.com" + author_realname: "Test Name" + title: "Post published to members" + type: "report" + content: "Post published to members" + status: "published" + locale: "en_us" + created: 1412025016 + published_to: '[]' + post_date: "2014-09-29 14:10:16" + - + id: 122 + form_id: 4 + parent_id: + user_id: 3 + author_email: "test@ushahidi.com" + author_realname: "Test Name" + title: "Post published to members" + type: "report" + content: "Post published to members" + status: "published" + locale: "en_us" + created: 1412025016 + published_to: '["user"]' + post_date: "2014-09-29 14:10:16" post_datetime: post_decimal: post_geometry: @@ -678,6 +899,56 @@ post_varchar: post_id: 1 form_attribute_id: 11 value: "http://ushahidi.com" + - + id: 13 + post_id: 121 + form_attribute_id: 20 + value: "arabic string" + - + id: 14 + post_id: 121 + form_attribute_id: 21 + value: "http://google.com" + - + id: 15 + post_id: 121 + form_attribute_id: 22 + value: "http://ushahidi.com" + - + id: 16 + post_id: 121 + form_attribute_id: 23 + value: "arabic string" + - + id: 17 + post_id: 121 + form_attribute_id: 24 + value: "arabic string" + - + id: 18 + post_id: 122 + form_attribute_id: 20 + value: "arabic string" + - + id: 19 + post_id: 122 + form_attribute_id: 21 + value: "http://google.com" + - + id: 20 + post_id: 122 + form_attribute_id: 22 + value: "http://ushahidi.com" + - + id: 21 + post_id: 122 + form_attribute_id: 23 + value: "arabic string" + - + id: 22 + post_id: 122 + form_attribute_id: 24 + value: "arabic string" post_comments: tags: - @@ -734,12 +1005,15 @@ posts_tags: - post_id: 1 tag_id: 4 + form_attribute_id: 26 - post_id: 1 tag_id: 3 + form_attribute_id: 26 - post_id: 99 tag_id: 3 + form_attribute_id: 26 form_stages_posts: - form_stage_id: 1 diff --git a/application/tests/datasets/ushahidi/sample-large.png b/tests/datasets/ushahidi/sample-large.png similarity index 100% rename from application/tests/datasets/ushahidi/sample-large.png rename to tests/datasets/ushahidi/sample-large.png diff --git a/application/tests/datasets/ushahidi/sample.csv b/tests/datasets/ushahidi/sample.csv similarity index 100% rename from application/tests/datasets/ushahidi/sample.csv rename to tests/datasets/ushahidi/sample.csv diff --git a/application/tests/datasets/ushahidi/sample.png b/tests/datasets/ushahidi/sample.png similarity index 100% rename from application/tests/datasets/ushahidi/sample.png rename to tests/datasets/ushahidi/sample.png diff --git a/application/tests/features/api.acl.feature b/tests/integration/acl.feature similarity index 70% rename from application/tests/features/api.acl.feature rename to tests/integration/acl.feature index 89bbb1f913..3717044930 100644 --- a/application/tests/features/api.acl.feature +++ b/tests/integration/acl.feature @@ -1,12 +1,204 @@ @acl Feature: API Access Control Layer + + Scenario: Anonymous users can create posts + Given that I want to make a new "Post" + And that the request "Authorization" header is "Bearer testanon" + And that the request "data" is: + """ + { + "form_id": 1, + "status": "draft", + "title": "Test creating anonymous post", + "content": "testing post for oauth", + "locale": "en_us", + "values": { + "last_location" : ["Somewhere"] + } + } + """ + When I request "/posts" + Then the guzzle status code should be 204 + + Scenario: Anonymous user can not see restricted fields of public posts + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testanon" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response has a "values" property + And the response has a "values.test_field_locking_visible_4" property + And the response does not have a "values.test_field_locking_hidden_3" property + Then the guzzle status code should be 200 + + Scenario: Anonymous user can not see hidden tasks of public posts + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testanon" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response has a "values" property + And the response has a "values.test_field_locking_visible_4" property + And the response does not have a "values.test_field_locking_visible_2" property + Then the guzzle status code should be 200 + + Scenario: Anonymous user can not see hidden author field of public posts + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testanon" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response does not have a "author_realname" property + And the response does not have a "author_email" property + And the response does not have a "user_id" property + Then the guzzle status code should be 200 + + Scenario: User can not see hidden tasks of public posts + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testbasicuser" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response has a "values" property + And the response has a "values.test_field_locking_visible_4" property + And the response does not have a "values.test_field_locking_visible_2" property + Then the guzzle status code should be 200 + + Scenario: User can not see restricted fields of public posts + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testbasicuser" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response has a "values" property + And the response has a "values.test_field_locking_visible_4" property + And the response does not have a "values.test_field_locking_hidden_3" property + Then the guzzle status code should be 200 + + Scenario: User can not see hidden author field of public posts + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testanon" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response does not have a "author_realname" property + And the response does not have a "author_email" property + And the response does not have a "user" property + Then the guzzle status code should be 200 + + Scenario: User can see restricted fields of posts published to their role when survey restricted to their role + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testmanager" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response has a "values" property + And the response has a "values.test_field_locking_visible_4" property + And the response has a "values.test_field_locking_hidden_3" property + Then the guzzle status code should be 200 + + Scenario: User can see hidden author field of posts published to their role when survey restricted to their role + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testmanager" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response has a "author_realname" property + And the response has a "author_email" property + And the response has a "user" property + Then the guzzle status code should be 200 + + Scenario: User can not see hidden tasks of posts published to their role + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testbasicuser" + And that its "id" is "122" + When I request "/posts" + Then the response is JSON + And the response has a "values" property + And the response has a "values.test_field_locking_visible_4" property + And the response does not have a "values.test_field_locking_visible_2" property + Then the guzzle status code should be 200 + + Scenario: User can see restricted fields of posts published to their role + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testbasicuser" + And that its "id" is "122" + When I request "/posts" + Then the response is JSON + And the response has a "values" property + And the response has a "values.test_field_locking_visible_4" property + And the response does not have a "values.test_field_locking_hidden_3" property + Then the guzzle status code should be 200 + + Scenario: User can not see hidden author field of posts published to their role + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testbasicuser" + And that its "id" is "122" + When I request "/posts" + Then the response is JSON + And the response does not have a "author_realname" property + And the response does not have a "author_email" property + And the response does not have a "user" property + Then the guzzle status code should be 200 + + Scenario: Listing All Stages for a form with hidden stages + Given that I want to get all "Stages" + And that the request "Authorization" header is "Bearer testbasicuser" + When I request "/forms/4/stages" + Then the response is JSON + And the response has a "count" property + And the type of the "count" property is "numeric" + And the "count" property equals "1" + Then the guzzle status code should be 200 + + Scenario: Listing All Stages for a form with hidden stages with edit permission + Given that I want to get all "Stages" + And that the request "Authorization" header is "Bearer testmanager" + When I request "/forms/4/stages" + Then the response is JSON + And the response has a "count" property + And the type of the "count" property is "numeric" + And the "count" property equals "2" + Then the guzzle status code should be 200 + + Scenario: Listing All Attributes for a form with hidden stages + Given that I want to get all "Stages" + And that the request "Authorization" header is "Bearer testbasicuser" + When I request "/forms/4/attributes" + Then the response is JSON + And the response has a "count" property + And the type of the "count" property is "numeric" + And the "count" property equals "8" + Then the guzzle status code should be 200 + + Scenario: Listing All Attributes for a form with hidden stages with edit permission + Given that I want to get all "Stages" + And that the request "Authorization" header is "Bearer testmanager" + When I request "/forms/4/attributes" + Then the response is JSON + And the response has a "count" property + And the type of the "count" property is "numeric" + And the "count" property equals "8" + Then the guzzle status code should be 200 + + Scenario: User can see hidden tasks of posts published when survey restricted to their role + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testmanager" + And that its "id" is "121" + When I request "/posts" + Then the response is JSON + And the response has a "values" property + And the response has a "values.test_field_locking_visible_4" property + And the response has a "values.test_field_locking_visible_2" property + Then the guzzle status code should be 200 + Scenario: Anonymous user can access public posts Given that I want to get all "Posts" And that the request "Authorization" header is "Bearer testanon" When I request "/posts" Then the guzzle status code should be 200 And the response is JSON - And the "count" property equals "10" + And the "count" property equals "11" Scenario: All users can view public posts Given that I want to get all "Posts" @@ -15,7 +207,7 @@ Feature: API Access Control Layer When I request "/posts" Then the guzzle status code should be 200 And the response is JSON - And the "count" property equals "11" + And the "count" property equals "13" Scenario: User can view public and own private posts in collection Given that I want to get all "Posts" @@ -24,7 +216,7 @@ Feature: API Access Control Layer When I request "/posts" Then the guzzle status code should be 200 And the response is JSON - And the "count" property equals "13" + And the "count" property equals "15" Scenario: Admin can view all posts in collection Given that I want to get all "Posts" @@ -33,7 +225,7 @@ Feature: API Access Control Layer When I request "/posts" Then the guzzle status code should be 200 And the response is JSON - And the "count" property equals "16" + And the "count" property equals "19" Scenario: Admin user can view private posts Given that I want to find a "Post" @@ -103,27 +295,6 @@ Feature: API Access Control Layer And the response is JSON And the response has an "errors" property - Scenario: Anonymous users can create posts - Given that I want to make a new "Post" - And that the request "Authorization" header is "Bearer testanon" - And that the request "data" is: - """ - { - "form_id": 1, - "status": "draft", - "title": "Test creating anonymous post", - "content": "testing post for oauth", - "locale": "en_us", - "values": { - "last_location" : ["Somewhere"] - } - } - """ - When I request "/posts" - Then the guzzle status code should be 204 - - - Scenario: Anonymous users can not edit posts Given that I want to update a "Post" And that the request "Authorization" header is "Bearer testanon" @@ -365,6 +536,16 @@ Feature: API Access Control Layer And the response is JSON And the "id" property equals "120" + @resetFixture + Scenario: Anonymous can not view private responses + Given that I want to find a "Post" + And that the request "Authorization" header is "Bearer testanon" + And that its "id" is "121" + When I request "/posts" + Then the guzzle status code should be 200 + And the response is JSON + And the "id" property equals "121" + @resetFixture Scenario: Anonymous can not view post published to members Given that I want to find a "Post" @@ -434,7 +615,7 @@ Feature: API Access Control Layer When I request "/posts" Then the guzzle status code should be 200 And the response is JSON - And the "count" property equals "16" + And the "count" property equals "18" @rolesEnabled Scenario: User with Manage Posts permission can view private posts @@ -556,4 +737,3 @@ Feature: API Access Control Layer And the response has a "columns" property And the "columns.0" property equals "title" Then the guzzle status code should be 200 - diff --git a/tests/integration/bootstrap/FeatureContext.php b/tests/integration/bootstrap/FeatureContext.php new file mode 100644 index 0000000000..ed2edc7999 --- /dev/null +++ b/tests/integration/bootstrap/FeatureContext.php @@ -0,0 +1,83 @@ + + * @package Ushahidi\Application\Tests + * @copyright 2013 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) + */ + +namespace Tests\Integration\Bootstrap; + +use Behat\Behat\Context\Context; +use Behat\Behat\Context\SnippetAcceptingContext; +use Behat\Gherkin\Node\PyStringNode; +use Behat\Gherkin\Node\TableNode; + +class FeatureContext implements SnippetAcceptingContext +{ + + /** @BeforeScenario @private */ + public function makePrivate() + { + $config = \Kohana::$config->load('site'); + $config->set('private', true); + + $config = \Kohana::$config->load('features'); + $config->set('private.enabled', true); + } + + /** @AfterScenario @private */ + public function makePublic() + { + $config = \Kohana::$config->load('site'); + $config->set('private', false); + + $config = \Kohana::$config->load('features'); + $config->set('private.enabled', false); + } + + /** @BeforeScenario @rolesEnabled */ + public function enableRoles() + { + $config = \Kohana::$config->load('features'); + $config->set('roles.enabled', true); + } + + /** @AfterScenario @rolesEnabled */ + public function disableRoles() + { + $config = \Kohana::$config->load('features'); + $config->set('roles.enabled', false); + } + + /** @BeforeScenario @webhooksEnabled */ + public function enableWebhooks() + { + $config = \Kohana::$config->load('features'); + $config->set('webhooks.enabled', true); + } + + /** @AfterScenario @webhooksEnabled */ + public function disableWebhooks() + { + $config = \Kohana::$config->load('features'); + $config->set('webhooks.enabled', false); + } + + /** @BeforeScenario @dataImportEnabled */ + public function enableDataImport() + { + $config = \Kohana::$config->load('features'); + $config->set('data-import.enabled', true); + } + + /** @AfterScenario @dataImportEnabled */ + public function disableDataImport() + { + $config = \Kohana::$config->load('features'); + $config->set('data-import.enabled', false); + } +} diff --git a/tests/integration/bootstrap/KohanaContext.php b/tests/integration/bootstrap/KohanaContext.php new file mode 100644 index 0000000000..d7cbbc4456 --- /dev/null +++ b/tests/integration/bootstrap/KohanaContext.php @@ -0,0 +1,16 @@ +getSession()->getCurrentUrl(); - if (!preg_match($pattern, $actual)) - { + if (!preg_match($pattern, $actual)) { $message = sprintf('Current page "%s" does not match the regex "%s".', $actual, $pattern); throw new Exception($message); } @@ -33,17 +35,17 @@ public function assertFullUrlRegExp($pattern) public function canIntercept() { $driver = $this->getSession()->getDriver(); - if (!$driver instanceof GoutteDriver) - { + if (!$driver instanceof GoutteDriver) { throw new UnsupportedDriverActionException( 'You need to tag the scenario with ' . '"@mink:goutte" or "@mink:symfony". ' . 'Intercepting the redirections is not ' . - 'supported by %s', $driver + 'supported by %s', + $driver ); } } - + /** * @Given /^(.*) without redirection$/ */ @@ -51,10 +53,10 @@ public function theRedirectionsAreIntercepted($step) { $this->canIntercept(); $this->getSession()->getDriver()->getClient()->followRedirects(false); - + return new Step\Given($step); } - + /** * @Given /^(.*) with redirection$/ */ @@ -62,10 +64,10 @@ public function theRedirectionsAreFollowed($step) { $this->canIntercept(); $this->getSession()->getDriver()->getClient()->followRedirects(true); - + return new Step\Given($step); } - + /** * @When /^I follow the redirection$/ * @Then /^I should be redirected$/ @@ -77,7 +79,7 @@ public function iFollowTheRedirection() $client->followRedirects(true); $client->followRedirect(); } - + /** * @Then /^the redirect location should match (?P"([^"]|\\")*")$/ */ @@ -86,11 +88,10 @@ public function redirectLocationShouldMatch($pattern) $this->canIntercept(); $client = $this->getSession()->getDriver()->getClient(); $actual = $client->getResponse()->getHeader('Location'); - + $pattern = $this->fixStepArgument($pattern); - if (!preg_match($pattern, $actual)) - { + if (!preg_match($pattern, $actual)) { $message = sprintf('Redirect location "%s" does not match the regex "%s".', $actual, $pattern); throw new Exception($message); } @@ -103,5 +104,4 @@ public function iShouldHaveCookie($cookie) { $this->assertSession()->cookieExists($cookie); } - } diff --git a/tests/integration/bootstrap/PHPUnitFixtureContext.php b/tests/integration/bootstrap/PHPUnitFixtureContext.php new file mode 100644 index 0000000000..9ac234faef --- /dev/null +++ b/tests/integration/bootstrap/PHPUnitFixtureContext.php @@ -0,0 +1,199 @@ +setUpDBTester('ushahidi/Base'); + $fixtureContext->insertGeometryFixtures(); + } + + /** @AfterFeature */ + public static function featureTearDown(\Behat\Behat\Hook\Scope\AfterFeatureScope $scope) + { + $fixtureContext = new static(); + $fixtureContext->tearDownDBTester('ushahidi/Base'); + } + + /** @BeforeScenario @resetFixture */ + public function scenarioSetup() + { + $this->setUpDBTester('ushahidi/Base'); + $this->insertGeometryFixtures(); + } + + protected function insertGeometryFixtures() + { + $pdo_connection = $this->getConnection()->getConnection(); + $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) + VALUES (1, 1, 8, POINT(12.123, 21.213));"); + $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) + VALUES (7, 1, 8, POINT(12.223, 21.313));"); + $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) + VALUES (2, 99, 8, POINT(11.123, 24.213));"); + $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) + VALUES (3, 9999, 8, POINT(10.123, 26.213));"); + $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) + VALUES (4, 95, 8, POINT(1, 1));"); + $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) + VALUES (5, 95, 12, POINT(1.2, 0.5));"); + $pdo_connection->query("INSERT INTO `post_point` (`id`, `post_id`, `form_attribute_id`, `value`) + VALUES (6, 97, 8, POINT(1, 1));"); + + $pdo_connection->query("INSERT INTO `post_geometry` (`id`, `post_id`, `form_attribute_id`, `value`) + VALUES (1, 1, 9, + GeomFromText('MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), + ((20 35, 45 20, 30 5, 10 10, 10 30, 20 35), + (30 20, 20 25, 20 15, 30 20)))'));"); + } + + /** + * Creates a connection to the unittesting database + * Overriding to fix database type in DSN - must be lowercase + * + * @return PDO + */ + public function getConnection() + { + // Get the unittesting db connection + $config = \Kohana::$config->load('database.'.$this->database_connection); + + if ($config['type'] !== 'pdo') { + // Replace MySQLi with MySQL since MySQLi isn't valid for a DSN + $type = $config['type'] === 'MySQLi' ? 'MySQL' : $config['type']; + + $config['connection']['dsn'] = strtolower($type).':'. + 'host='.$config['connection']['hostname'].';'. + 'dbname='.$config['connection']['database']; + } + + $pdo = new \PDO( + $config['connection']['dsn'], + $config['connection']['username'], + $config['connection']['password'] + ); + + return $this->createDefaultDBConnection($pdo, $config['connection']['database']); + } + + /** + * Returns the test dataset. + * + * @param string|array $dataset Dataset filename + * @return PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected function getDataSet($dataset) + { + return new \PHPUnit_Extensions_Database_DataSet_YamlDataSet( + __DIR__ . '/../../datasets/' . $dataset . '.yml' + ); + } + + + + /** Call this in a BeforeScenario hook */ + public function setUpDBTester($dataset) + { + $this->databaseTester = null; + + $this->getDatabaseTester()->setSetUpOperation($this->getSetUpOperation()); + $this->getDatabaseTester()->setDataSet($this->getDataSet($dataset)); + $this->getDatabaseTester()->onSetUp(); + } + + /** Call this in an AfterScenario hook */ + public function tearDownDBTester($dataset) + { + $this->getDatabaseTester()->setTearDownOperation($this->getTearDownOperation()); + $this->getDatabaseTester()->setDataSet($this->getDataSet($dataset)); + $this->getDatabaseTester()->onTearDown(); + + /** + * Destroy the tester after the test is run to keep DB connections + * from piling up. + */ + $this->databaseTester = null; + } + + /** + * Gets the IDatabaseTester for this testCase. If the IDatabaseTester is + * not set yet, this method calls newDatabaseTester() to obtain a new + * instance. + * + * @return PHPUnit_Extensions_Database_ITester + */ + protected function getDatabaseTester() + { + if (empty($this->databaseTester)) { + $this->databaseTester = $this->newDatabaseTester(); + } + return $this->databaseTester; + } + + /** + * Creates a IDatabaseTester for this testCase. + * + * @return PHPUnit_Extensions_Database_ITester + */ + protected function newDatabaseTester() + { + return new \PHPUnit_Extensions_Database_DefaultTester($this->getConnection()); + } + + /** + * Returns the database operation executed in test setup. + * Overriding to fix Mysql 5.5 truncate errors + * + * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation + */ + protected function getSetUpOperation() + { + //return PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT(); + $cascadeTruncates = true; + return new \PHPUnit_Extensions_Database_Operation_Composite(array( + new \Unittest_Database_Operation_MySQL55Truncate($cascadeTruncates), + \PHPUnit_Extensions_Database_Operation_Factory::INSERT() + )); + } + + /** + * Returns the database operation executed in test cleanup. + * + * @return PHPUnit_Extensions_Database_Operation_DatabaseOperation + */ + protected function getTearDownOperation() + { + return \PHPUnit_Extensions_Database_Operation_Factory::NONE(); + } + + /** + * Creates a new DefaultDatabaseConnection using the given PDO connection + * and database schema name. + * + * @param PDO $connection + * @param string $schema + * @return PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection + */ + protected function createDefaultDBConnection(\PDO $connection, $schema = '') + { + return new \PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection($connection, $schema); + } +} diff --git a/tests/integration/bootstrap/RestContext.php b/tests/integration/bootstrap/RestContext.php new file mode 100644 index 0000000000..d1d3e6b6d0 --- /dev/null +++ b/tests/integration/bootstrap/RestContext.php @@ -0,0 +1,668 @@ + + * @package Ushahidi\Application\Tests + * @copyright 2013 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) + */ + +use Behat\Behat\Context\Context; +use Symfony\Component\Yaml\Yaml; +use stdClass; + +/** + * Rest context. + */ +class RestContext implements Context +{ + + private $restObject = null; + private $restObjectType = null; + private $restObjectMethod = 'get'; + private $client = null; + private $response = null; + private $requestUrl = null; + private $apiUrl = 'api/v3'; + + private $parameters = array(); + private $headers = array(); + private $postFields = array(); + private $postFiles = array(); + + /** + * Initializes context. + * Every scenario gets it's own context object. + */ + public function __construct($baseUrl, $proxyUrl = false) + { + $this->restObject = new stdClass(); + + $options = array(); + if ($proxyUrl) { + $options['curl.options'] = array(CURLOPT_PROXY => $proxyUrl); + } + + $this->client = new \Guzzle\Service\Client($baseUrl, $options); + } + + /** + * Automatically set bearer token so you can forget about it + * @BeforeScenario @oauth2Skip + */ + public function setDefaultBearerAuth() + { + $this->thatTheRequestHeaderIs('Authorization', 'Bearer defaulttoken'); + } + + /** + * @Given /^that I want to make a new "([^"]*)"$/ + */ + public function thatIWantToMakeANew($objectType) + { + // Reset restObject + $this->restObject = new stdClass(); + + $this->restObjectType = ucwords(strtolower($objectType)); + $this->restObjectMethod = 'post'; + } + + /** + * @Given /^that I want to import a "([^"]*)"$/ + */ + public function thatIWantToImportA($objectType) + { + // Reset restObject + $this->restObject = new stdClass(); + + $this->restObjectType = ucwords(strtolower($objectType)); + $this->restObjectMethod = 'post'; + } + + + /** + * @Given /^that I want to submit a new "([^"]*)"$/ + */ + public function thatIWantToSubmitANew($objectType) + { + // Reset restObject + $this->restObject = new stdClass(); + + $this->restObjectType = ucwords(strtolower($objectType)); + $this->restObjectMethod = 'post'; + } + + /** + * @Given /^that I want to update a "([^"]*)"$/ + * @Given /^that I want to update an "([^"]*)"$/ + */ + public function thatIWantToUpdateA($objectType) + { + // Reset restObject + $this->restObject = new stdClass(); + + $this->restObjectType = ucwords(strtolower($objectType)); + $this->restObjectMethod = 'put'; + } + + /** + * @Given /^that I want to find a "([^"]*)"$/ + * @Given /^that I want to find an "([^"]*)"$/ + */ + public function thatIWantToFindA($objectType) + { + // Reset restObject + $this->restObject = new stdClass(); + + $this->restObjectType = ucwords(strtolower($objectType)); + $this->restObjectMethod = 'get'; + } + + /** + * @Given /^that I want to get all "([^"]*)"$/ + */ + public function thatIWantToGetAll($objectType) + { + // Reset restObject + $this->restObject = new stdClass(); + + $this->restObjectType = ucwords(strtolower($objectType)); + $this->restObjectMethod = 'get'; + } + + /** + * @Given /^that I want to delete a "([^"]*)"$/ + * @Given /^that I want to delete an "([^"]*)"$/ + */ + public function thatIWantToDeleteA($objectType) + { + // Reset restObject + $this->restObject = new stdClass(); + + $this->restObjectType = ucwords(strtolower($objectType)); + $this->restObjectMethod = 'delete'; + } + + /** + * @Given /^that the request "([^"]*)" is:$/ + * @Given /^that the request "([^"]*)" is "([^"]*)"$/ + * @Given /^that its "([^"]*)" is "([^"]*)"$/ + */ + public function thatTheRequestPropertyIs($propertyName, $propertyValue) + { + $this->restObject->$propertyName = $propertyValue; + } + + /** + * @Given /^that the request "([^"]*)" header is:$/ + * @Given /^that the request "([^"]*)" header is "([^"]*)"$/ + */ + public function thatTheRequestHeaderIs($headerName, $headerValue) + { + $this->headers[$headerName] = $headerValue; + } + + /** + * @Given /^that the response "([^"]*)" header is "([^"]*)"$/ + */ + public function thatTheResponseHeaderIs($headerName, $headerValue) + { + $this->headers[$headerName] = $headerValue; + } + + /** + * @Given /^that the post field "([^"]*)" is:$/ + * @Given /^that the post field "([^"]*)" is "([^"]*)"$/ + */ + public function thatThePostFieldIs($fieldName, $fieldValue) + { + $this->postFields[$fieldName] = $fieldValue; + } + + /** + * @Given /^that the post file "([^"]*)" is:$/ + * @Given /^that the post file "([^"]*)" is "([^"]*)"$/ + */ + public function thatThePostFileIs($fieldName, $fieldValue) + { + $this->postFiles[$fieldName] = $fieldValue; + } + + /** + * @When /^I request "([^"]*)"$/ + */ + public function iRequest($pageUrl) + { + $this->requestUrl = $this->apiUrl.$pageUrl; + + switch (strtoupper($this->restObjectMethod)) { + case 'GET': + $request = (array)$this->restObject; + $id = ( isset($request['id']) ) ? $request['id'] : ''; + $http_request = $this->client + ->get($this->requestUrl.'/'.$id); + + if (isset($request['query string'])) { + $url = $http_request->getUrl(true); + $url->setQuery((string) trim($request['query string'])); + $http_request->setUrl($url); + } + break; + case 'POST': + $request = (array)$this->restObject; + // If post fields or files are set assume this is a 'normal' POST request + if ($this->postFields or $this->postFiles) { + $http_request = $this->client + ->post($this->requestUrl) + ->addPostFields($this->postFields) + ->addPostFiles($this->preparePostFileData($this->postFiles)); + } // Otherwise assume we have JSON + else { + $http_request = $this->client + ->post($this->requestUrl) + ->setBody($request['data']); + } + break; + case 'PUT': + $request = (array)$this->restObject; + $id = ( isset($request['id']) ) ? $request['id'] : ''; + $http_request = $this->client + ->put($this->requestUrl.'/'.$id) + ->setBody($request['data']); + break; + case 'DELETE': + $request = (array)$this->restObject; + $id = ( isset($request['id']) ) ? $request['id'] : ''; + $http_request = $this->client + ->delete($this->requestUrl.'/'.$id); + break; + } + + try { + $http_request + ->addHeaders($this->headers) + ->send(); + } catch (\Guzzle\Http\Exception\BadResponseException $e) { + // Don't care. + // 4xx and 5xx statuses are valid error responses + } + + // Get response object + $this->response = $http_request->getResponse(); + + // Create fake response object if Guzzle doesn't give us one + if (! $this->response instanceof \Guzzle\Http\Message\Response) { + $this->response = new \Guzzle\Http\Message\Response(null, null, null); + } + } + + /** + * @Then /^the response is JSON$/ + */ + public function theResponseIsJson() + { + $data = json_decode($this->response->getBody(true), true); + + // Check for NULL not empty - since [] and {} will be empty but valid + if ($data === null) { + // Get further error info + switch (json_last_error()) { + case JSON_ERROR_NONE: + $error = 'No errors'; + break; + case JSON_ERROR_DEPTH: + $error = 'Maximum stack depth exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + $error = 'Underflow or the modes mismatch'; + break; + case JSON_ERROR_CTRL_CHAR: + $error = 'Unexpected control character found'; + break; + case JSON_ERROR_SYNTAX: + $error = 'Syntax error, malformed JSON'; + break; + case JSON_ERROR_UTF8: + $error = 'Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + default: + $error = 'Unknown error'; + break; + } + + throw new \Exception( + "Response was not JSON\nBody:" . $this->response->getBody(true) . "\nError: " . $error + ); + } + } + + /** + * @Then /^the response is JSONP$/ + */ + public function theResponseIsJsonp() + { + $result = preg_match('/^.+\(({.+})\)$/', $this->response->getBody(true), $matches); + + if ($result != 1 or empty($matches[1])) { + throw new \Exception("Response was not JSONP\nBody:" . $this->response->getBody(true)); + } + + $data = json_decode($matches[1]); + + // Check for NULL not empty - since [] and {} will be empty but valid + if ($data === null) { + // Get further error info + switch (json_last_error()) { + case JSON_ERROR_NONE: + $error = 'No errors'; + break; + case JSON_ERROR_DEPTH: + $error = 'Maximum stack depth exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + $error = 'Underflow or the modes mismatch'; + break; + case JSON_ERROR_CTRL_CHAR: + $error = 'Unexpected control character found'; + break; + case JSON_ERROR_SYNTAX: + $error = 'Syntax error, malformed JSON'; + break; + case JSON_ERROR_UTF8: + $error = 'Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + default: + $error = 'Unknown error'; + break; + } + + throw new \Exception( + "Response was not JSONP\nBody:" . $this->response->getBody(true) . "\nError: " . $error + ); + } + } + + /** + * @Given /^the response has a "([^"]*)" property$/ + * @Given /^the response has an "([^"]*)" property$/ + */ + public function theResponseHasAProperty($propertyName) + { + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + if (\Arr::path($data, $propertyName) === null) { + throw new \Exception("Property '".$propertyName."' is not set!\n"); + } + } + + /** + * @Given /^the response does not have a "([^"]*)" property$/ + * @Given /^the response does not have an "([^"]*)" property$/ + */ + public function theResponseDoesNotHaveAProperty($propertyName) + { + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + if (\Arr::path($data, $propertyName) !== null) { + throw new \Exception("Property '".$propertyName."' is set but should not be!\n"); + } + } + + /** + * @Then /^the "([^"]*)" property equals "([^"]*)"$/ + */ + public function thePropertyEquals($propertyName, $propertyValue) + { + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + $actualPropertyValue = \Arr::path($data, $propertyName); + + if ($actualPropertyValue === null) { + throw new \Exception("Property '".$propertyName."' is not set!\n"); + } + // Check the value - note this has to use != since $propertValue + // is always a string so strict comparison would fail. + if ($actualPropertyValue != $propertyValue) { + throw new \Exception( + "Property value mismatch on '" . $propertyName . "'! ". + "(given: " . $propertyValue . ", match: " . $actualPropertyValue . ")" + ); + } + } + + /** + * @Then /^the "([^"]*)" property is true$/ + */ + public function thePropertyIsTrue($propertyName) + { + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + $actualPropertyValue = \Arr::path($data, $propertyName); + + if ($actualPropertyValue === null) { + throw new \Exception("Property '".$propertyName."' is not set!\n"); + } + if ($actualPropertyValue !== true) { + throw new \Exception('Property \''.$propertyName.'\' is not true! (match: '.$actualPropertyValue.')'); + } + } + + /** + * @Then /^the "([^"]*)" property is false$/ + */ + public function thePropertyIsFalse($propertyName) + { + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + $actualPropertyValue = \Arr::path($data, $propertyName); + + if ($actualPropertyValue === null) { + throw new \Exception("Property '".$propertyName."' is not set!\n"); + } + if ($actualPropertyValue !== false) { + throw new \Exception('Property \''.$propertyName.'\' is not false! (match: '.$actualPropertyValue.')'); + } + } + + /** + * @Given /^the "([^"]*)" property contains "([^"]*)"$/ + */ + public function thePropertyContains($propertyName, $propertyContainsValue) + { + + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + $actualPropertyValue = \Arr::path($data, $propertyName); + + if ($actualPropertyValue === null) { + throw new Exception("Property '".$propertyName."' is not set!\n"); + } + + if (is_array($actualPropertyValue) and ! in_array($propertyContainsValue, $actualPropertyValue)) { + throw new \Exception( + 'Property \''.$propertyName.'\' does not contain value!' . + '(given: '.$propertyContainsValue.', match: '.json_encode($actualPropertyValue).')' + ); + } elseif (is_string($actualPropertyValue) and strpos($actualPropertyValue, $propertyContainsValue) === false) { + throw new \Exception( + 'Property \''.$propertyName.'\' does not contain value!' . + '(given: '.$propertyContainsValue.', match: '.$actualPropertyValue.')' + ); + } elseif (!is_array($actualPropertyValue) and !is_string($actualPropertyValue)) { + throw new \Exception( + "Property '".$propertyName."' could not be compared. Must be string or array.\n" + ); + } + } + + /** + * @Given /^the "([^"]*)" property does not contain "([^"]*)"$/ + */ + public function thePropertyDoesNotContains($propertyName, $propertyContainsValue) + { + + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + $actualPropertyValue = \Arr::path($data, $propertyName); + + if ($actualPropertyValue === null) { + throw new Exception("Property '".$propertyName."' is not set!\n"); + } + + if (is_array($actualPropertyValue) and in_array($propertyContainsValue, $actualPropertyValue)) { + throw new \Exception( + 'Property \''.$propertyName.'\' contains value!' . + '(given: '.$propertyContainsValue.', match: '.json_encode($actualPropertyValue).')' + ); + } elseif (is_string($actualPropertyValue) and strpos($actualPropertyValue, $propertyContainsValue) !== false) { + throw new \Exception( + 'Property \''.$propertyName.'\' does not contain value!' . + '(given: '.$propertyContainsValue.', match: '.$actualPropertyValue.')' + ); + } elseif (!is_array($actualPropertyValue) and !is_string($actualPropertyValue)) { + throw new \Exception( + "Property '".$propertyName."' could not be compared. Must be string or array.\n" + ); + } + } + + /** + * @Given /^the "([^"]*)" property count is "([^"]*)"$/ + */ + public function thePropertyCountIs($propertyName, $propertyCountValue) + { + + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + $actualPropertyValue = \Arr::path($data, $propertyName); + + if ($actualPropertyValue === null) { + throw new \Exception("Property '".$propertyName."' is not set!\n"); + } + + if (is_array($actualPropertyValue) and count($actualPropertyValue) != $propertyCountValue) { + throw new \Exception( + 'Property \''.$propertyName.'\' count does not match!' . + '(given: '.$propertyCountValue.', match: '.count($actualPropertyValue).')' + ); + } elseif (!is_array($actualPropertyValue)) { + throw new \Exception("Property '".$propertyName."' could not be compared. Must be an array.\n"); + } + } + + /** + * @Given /^the type of the "([^"]*)" property is "([^"]*)"$/ + */ + public function theTypeOfThePropertyIs($propertyName, $typeString) + { + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + $actualPropertyValue = \Arr::path($data, $propertyName); + + if ($actualPropertyValue === null) { + throw new \Exception("Property '".$propertyName."' is not set!\n"); + } + // check our type + switch (strtolower($typeString)) { + case 'numeric': + if (!is_numeric($actualPropertyValue)) { + throw new \Exception("Property '".$propertyName."' is not of the correct type: ".$typeString."!\n"); + } + break; + } + } + + /** + * @Then /^the "([^"]*)" property is empty$/ + */ + public function thePropertyIsEmpty($propertyName) + { + $data = json_decode($this->response->getBody(true), true); + + $this->theResponseIsJson(); + + $actualPropertyValue = \Arr::path($data, $propertyName); + + if (!empty($actualPropertyValue)) { + throw new \Exception("Property '{$propertyName}' is not empty!\n"); + } + } + + /** + * @Then /^the guzzle status code should be (\d+)$/ + */ + public function theRestResponseStatusCodeShouldBe($httpStatus) + { + if ((string)$this->response->getStatusCode() !== $httpStatus) { + throw new \Exception('HTTP code does not match '.$httpStatus. + ' (actual: '.$this->response->getStatusCode().')'); + } + } + + /** + * @Then /^the "([^"]*)" header should exist$/ + */ + public function theRestHeaderShouldExist($header) + { + if (!$this->response->hasHeader($header)) { + throw new \Exception('HTTP header does not exist '.$header); + } + } + + /** + * @Then /^the the ([^"]*)" header should be "([^"]*)"$/ + */ + public function theRestHeaderShouldExistBe($header, $contents) + { + if ((string)$this->response->getHeader($header) !== $contents) { + throw new \Exception('HTTP header ' . $header . ' does not match '.$contents. + ' (actual: '.$this->response->getHeader($header).')'); + } + } + + + /** + * @Then /^echo last response$/ + */ + public function echoLastResponse() + { + var_dump( + $this->requestUrl."\n\n". + $this->response + ); + } + + /** + * @Given /^that the api_url is "([^"]*)"$/ + */ + public function thatTheApiUrlIs($api_url) + { + $this->apiUrl = $api_url; + } + + /** + * @AfterScenario + */ + public function afterScenarioCheckError(\Behat\Behat\Hook\Scope\AfterScenarioScope $scope) + { + // If scenario failed, dump response + if (!$scope->getTestResult()->isPassed() and $this->response) { + $this->echoLastResponse(); + } + } + + private function preparePostFileData($postFiles) + { + //Check if post files is not empty + if (count($postFiles) > 0) { + array_walk_recursive($postFiles, array($this, 'prefixAppPath')); + return $postFiles; + } + return $postFiles; + } + + /** + * Make the path to upload files to, relative to the application directory + * + * @param string $item the path to the file to be uploaded + * @return string path to application folder + */ + private function prefixAppPath(&$item) + { + $item = DOCROOT.$item; + } + + /** + * @Given /^that I want to count all "([^"]*)"$/ + */ + public function thatIWantToCountAll($objectType) + { + // Reset restObject + $this->restObject = new stdClass(); + + $this->restObjectType = ucwords(strtolower($objectType)); + $this->restObjectMethod = 'get'; + } +} diff --git a/application/tests/features/api.collections.feature b/tests/integration/collections.feature similarity index 100% rename from application/tests/features/api.collections.feature rename to tests/integration/collections.feature diff --git a/application/tests/features/collections/api.posts.feature b/tests/integration/collections/posts.feature similarity index 100% rename from application/tests/features/collections/api.posts.feature rename to tests/integration/collections/posts.feature diff --git a/application/tests/features/api.config.feature b/tests/integration/config.feature similarity index 100% rename from application/tests/features/api.config.feature rename to tests/integration/config.feature diff --git a/application/tests/features/api.contacts.feature b/tests/integration/contacts.feature similarity index 100% rename from application/tests/features/api.contacts.feature rename to tests/integration/contacts.feature diff --git a/application/tests/features/api.csv.feature b/tests/integration/csv.feature similarity index 100% rename from application/tests/features/api.csv.feature rename to tests/integration/csv.feature diff --git a/application/tests/features/data-provider/frontlinesms.feature b/tests/integration/data-provider/frontlinesms.feature similarity index 100% rename from application/tests/features/data-provider/frontlinesms.feature rename to tests/integration/data-provider/frontlinesms.feature diff --git a/application/tests/features/data-provider/smssync.feature b/tests/integration/data-provider/smssync.feature similarity index 100% rename from application/tests/features/data-provider/smssync.feature rename to tests/integration/data-provider/smssync.feature diff --git a/application/tests/features/api.dataproviders.feature b/tests/integration/dataproviders.feature similarity index 100% rename from application/tests/features/api.dataproviders.feature rename to tests/integration/dataproviders.feature diff --git a/application/tests/features/api.forms.feature b/tests/integration/forms.feature similarity index 95% rename from application/tests/features/api.forms.feature rename to tests/integration/forms.feature index dee814ba00..e2285a3003 100644 --- a/application/tests/features/api.forms.feature +++ b/tests/integration/forms.feature @@ -35,7 +35,8 @@ Feature: Testing the Forms API "description":"This is a test form updated by BDD testing", "disabled":true, "require_approval":false, - "everyone_can_create":false + "everyone_can_create":false, + "tags": [1,2,3,"junk"] } """ And that its "id" is "1" @@ -142,6 +143,15 @@ Feature: Testing the Forms API Then the guzzle status code should be 200 Scenario: Finding a Form after roles have been set. + Given that I want to update a "FormRole" + And that the request "data" is: + """ + { + "roles": [1,2] + } + """ + When I request "/forms/1/roles" + Then the response is JSON Given that I want to find a "Form" And that its "id" is "1" When I request "/forms" diff --git a/application/tests/features/forms/api.attributes.feature b/tests/integration/forms/attributes.feature similarity index 98% rename from application/tests/features/forms/api.attributes.feature rename to tests/integration/forms/attributes.feature index b88bf72e6f..b9d656875c 100644 --- a/application/tests/features/forms/api.attributes.feature +++ b/tests/integration/forms/attributes.feature @@ -169,22 +169,24 @@ Feature: Testing the Form Attributes API And the response has a "errors" property Then the guzzle status code should be 404 + @resetFixture Scenario: Listing All Attributes for a form Given that I want to get all "Attributes" When I request "/forms/1/attributes" Then the response is JSON And the response has a "count" property And the type of the "count" property is "numeric" - And the "count" property equals "19" + And the "count" property equals "18" Then the guzzle status code should be 200 - Scenario: Listing All Attributes + @resetFixture + Scenario: Listing All Attributes Given that I want to get all "Attributes" When I request "/forms/attributes" Then the response is JSON And the response has a "count" property And the type of the "count" property is "numeric" - And the "count" property equals "20" + And the "count" property equals "29" Then the guzzle status code should be 200 Scenario: Search for point attributes diff --git a/application/tests/features/forms/api.stages.feature b/tests/integration/forms/stages.feature similarity index 100% rename from application/tests/features/forms/api.stages.feature rename to tests/integration/forms/stages.feature diff --git a/application/tests/features/api.layers.feature b/tests/integration/layers.feature similarity index 100% rename from application/tests/features/api.layers.feature rename to tests/integration/layers.feature diff --git a/application/tests/features/api.media.feature b/tests/integration/media.feature similarity index 97% rename from application/tests/features/api.media.feature rename to tests/integration/media.feature index eda699ddbb..b836b9125d 100644 --- a/application/tests/features/api.media.feature +++ b/tests/integration/media.feature @@ -121,6 +121,6 @@ Feature: Testing the Media API When I request "/media" Then the response is JSON And the response has a "errors" property - Then the "errors.1.message" property equals "File type not supported. Please upload an image file." - Then the "errors.2.message" property equals "The file size should be less than 1 MB" + #Then the "errors.1.message" property equals "File type not supported. Please upload an image file." + Then the "errors.1.message" property equals "The file size should be less than 1 MB" Then the guzzle status code should be 422 diff --git a/application/tests/features/api.messages.feature b/tests/integration/messages.feature similarity index 100% rename from application/tests/features/api.messages.feature rename to tests/integration/messages.feature diff --git a/application/tests/features/api.migration.feature b/tests/integration/migration.feature similarity index 100% rename from application/tests/features/api.migration.feature rename to tests/integration/migration.feature diff --git a/application/tests/features/api.notifications.feature b/tests/integration/notifications.feature similarity index 100% rename from application/tests/features/api.notifications.feature rename to tests/integration/notifications.feature diff --git a/application/tests/features/api.oauth.feature b/tests/integration/oauth.feature similarity index 100% rename from application/tests/features/api.oauth.feature rename to tests/integration/oauth.feature diff --git a/application/tests/features/api.permissions.feature b/tests/integration/permissions.feature similarity index 100% rename from application/tests/features/api.permissions.feature rename to tests/integration/permissions.feature diff --git a/application/tests/features/api.posts.feature b/tests/integration/posts.feature similarity index 95% rename from application/tests/features/api.posts.feature rename to tests/integration/posts.feature index 8dd04435ae..3f4458127d 100644 --- a/application/tests/features/api.posts.feature +++ b/tests/integration/posts.feature @@ -31,9 +31,9 @@ Feature: Testing the Posts API "links":[ "http://google.com", "http://facebook.com" - ] + ], + "tags1": [1] }, - "tags":["explosion"], "completed_stages":[1] } """ @@ -80,9 +80,9 @@ Feature: Testing the Posts API "links":[ "http://google.com", "http://facebook.com" - ] + ], + "tags1": ["explosion"] }, - "tags":["explosion"], "completed_stages":[1] } """ @@ -178,7 +178,7 @@ Feature: Testing the Posts API Then the guzzle status code should be 200 @create - Scenario: Creating a Post with a form that does not require approval but try to set status should fail + Scenario: Creating a Post with a form that does not require approval but try to set status should pass Given that I want to make a new "Post" And that the request "Authorization" header is "Bearer testbasicuser" And that the request "data" is: @@ -199,7 +199,7 @@ Feature: Testing the Posts API """ When I request "/posts" Then the response is JSON - Then the guzzle status code should be 422 + Then the guzzle status code should be 200 @create Scenario: Creating an Post with invalid data returns an error @@ -512,6 +512,79 @@ Feature: Testing the Posts API And the "values.last_location_point.0.lon" property equals "-85.39" Then the guzzle status code should be 200 + @update + Scenario: Updating a post and remove some values + Given that I want to update a "Post" + And that the request "data" is: + """ + { + "form":1, + "title":"Update 1", + "type":"report", + "status":"published", + "locale":"en_US", + "values": + { + "full_name":["David Kobia"], + "description":["Skinny, homeless Kenyan last seen in the vicinity of the greyhound station"], + "date_of_birth":[], + "missing_date":["2012/09/25"], + "last_location":["atlanta"], + "last_location_point":[ + { + "lat": 33.755, + "lon": -85.39 + } + ], + "missing_status":["believed_missing"], + "links":[ + "abc123", + "def456" + ] + } + } + """ + And that its "id" is "1" + When I request "/posts" + Then the response is JSON + And the response has a "id" property + # Update 2 + Given that I want to update a "Post" + And that the request "data" is: + """ + { + "form":1, + "title":"Update 2", + "type":"report", + "status":"published", + "locale":"en_US", + "values": + { + "full_name":["David Kobia"], + "description":["Skinny, homeless Kenyan last seen in the vicinity of the greyhound station"], + "date_of_birth":[], + "missing_date":["2012/09/25"], + "last_location":["atlanta"], + "last_location_point":[ + { + "lat": 33.755, + "lon": -85.39 + } + ], + "missing_status":["believed_missing"], + "links":[ + "def456" + ] + } + } + """ + And that its "id" is "1" + When I request "/posts" + Then the response is JSON + And the response has a "id" property + And the "values.links" property count is "1" + Then the guzzle status code should be 200 + @update Scenario: Updating a Post to update tags Given that I want to update a "Post" @@ -921,8 +994,8 @@ Feature: Testing the Posts API Then the response is JSON And the response has a "count" property And the type of the "count" property is "numeric" - And the "count" property equals "12" - And the "total_count" property equals "12" + And the "count" property equals "14" + And the "total_count" property equals "14" Then the guzzle status code should be 200 @resetFixture @search @@ -977,8 +1050,8 @@ Feature: Testing the Posts API Then the response is JSON And the response has a "count" property And the type of the "count" property is "numeric" - And the "count" property equals "1" - And the "total_count" property equals "1" + And the "count" property equals "3" + And the "total_count" property equals "3" Then the guzzle status code should be 200 @resetFixture @search @@ -1125,34 +1198,6 @@ Feature: Testing the Posts API And the "count" property equals "2" Then the guzzle status code should be 200 - @resetFixture @search - Scenario: Filter All Posts by single stage - Given that I want to get all "Posts" - And that the request "query string" is: - """ - current_stage=3 - """ - When I request "/posts" - Then the response is JSON - And the response has a "count" property - And the type of the "count" property is "numeric" - And the "count" property equals "1" - Then the guzzle status code should be 200 - - @resetFixture @search - Scenario: Filter All Posts by multiple stages - Given that I want to get all "Posts" - And that the request "query string" is: - """ - current_stage=1,3 - """ - When I request "/posts" - Then the response is JSON - And the response has a "count" property - And the type of the "count" property is "numeric" - And the "count" property equals "9" - Then the guzzle status code should be 200 - @resetFixture @search Scenario: Filter All Posts by multiple collections Given that I want to get all "Posts" diff --git a/application/tests/features/posts/api.geojson.feature b/tests/integration/posts/geojson.feature similarity index 100% rename from application/tests/features/posts/api.geojson.feature rename to tests/integration/posts/geojson.feature diff --git a/application/tests/features/posts/api.revisions.feature b/tests/integration/posts/revisions.feature similarity index 100% rename from application/tests/features/posts/api.revisions.feature rename to tests/integration/posts/revisions.feature diff --git a/application/tests/features/posts/api.translations.feature b/tests/integration/posts/translations.feature similarity index 100% rename from application/tests/features/posts/api.translations.feature rename to tests/integration/posts/translations.feature diff --git a/application/tests/features/posts/api.updates.feature b/tests/integration/posts/updates.feature similarity index 100% rename from application/tests/features/posts/api.updates.feature rename to tests/integration/posts/updates.feature diff --git a/application/tests/features/api.roles.feature b/tests/integration/roles.feature similarity index 100% rename from application/tests/features/api.roles.feature rename to tests/integration/roles.feature diff --git a/application/tests/features/api.savedsearch.feature b/tests/integration/savedsearch.feature similarity index 100% rename from application/tests/features/api.savedsearch.feature rename to tests/integration/savedsearch.feature diff --git a/application/tests/features/api.stats.feature b/tests/integration/stats.feature similarity index 100% rename from application/tests/features/api.stats.feature rename to tests/integration/stats.feature diff --git a/application/tests/features/api.tags.feature b/tests/integration/tags.feature similarity index 94% rename from application/tests/features/api.tags.feature rename to tests/integration/tags.feature index 3926f56c60..eefcd23fa9 100644 --- a/application/tests/features/api.tags.feature +++ b/tests/integration/tags.feature @@ -267,6 +267,20 @@ Feature: Testing the Tags API When I request "/tags" Then the guzzle status code should be 200 + @resetFixture + Scenario: Deleting a tag removes it from attribute options + Given that I want to delete a "Tag" + And that its "id" is "1" + When I request "/tags" + Then the guzzle status code should be 200 + Given that I want to find a "Attribute" + And that its "id" is "26" + When I request "/forms/1/attributes" + Then the response is JSON + And the response has an "options" property + And the "options" property does not contain "1" + Then the guzzle status code should be 200 + Scenario: Deleting a non-existent Tag Given that I want to delete a "Tag" And that its "id" is "35" diff --git a/application/tests/features/api.users.feature b/tests/integration/users.feature similarity index 100% rename from application/tests/features/api.users.feature rename to tests/integration/users.feature diff --git a/application/tests/features/users/api.users.me.feature b/tests/integration/users/users.me.feature similarity index 100% rename from application/tests/features/users/api.users.me.feature rename to tests/integration/users/users.me.feature diff --git a/application/tests/features/api.webhooks.feature b/tests/integration/webhooks.feature similarity index 100% rename from application/tests/features/api.webhooks.feature rename to tests/integration/webhooks.feature diff --git a/spec/Core/Tool/DateSpec.php b/tests/spec/Core/Tool/DateSpec.php similarity index 100% rename from spec/Core/Tool/DateSpec.php rename to tests/spec/Core/Tool/DateSpec.php diff --git a/spec/Core/Tool/UploaderSpec.php b/tests/spec/Core/Tool/UploaderSpec.php similarity index 100% rename from spec/Core/Tool/UploaderSpec.php rename to tests/spec/Core/Tool/UploaderSpec.php diff --git a/spec/Core/Usecase/CreateUsecaseSpec.php b/tests/spec/Core/Usecase/CreateUsecaseSpec.php similarity index 100% rename from spec/Core/Usecase/CreateUsecaseSpec.php rename to tests/spec/Core/Usecase/CreateUsecaseSpec.php diff --git a/spec/Core/Usecase/DeleteUsecaseSpec.php b/tests/spec/Core/Usecase/DeleteUsecaseSpec.php similarity index 100% rename from spec/Core/Usecase/DeleteUsecaseSpec.php rename to tests/spec/Core/Usecase/DeleteUsecaseSpec.php diff --git a/spec/Core/Usecase/Message/ReceiveMessageSpec.php b/tests/spec/Core/Usecase/Message/ReceiveMessageSpec.php similarity index 100% rename from spec/Core/Usecase/Message/ReceiveMessageSpec.php rename to tests/spec/Core/Usecase/Message/ReceiveMessageSpec.php diff --git a/spec/Core/Usecase/ReadUsecaseSpec.php b/tests/spec/Core/Usecase/ReadUsecaseSpec.php similarity index 100% rename from spec/Core/Usecase/ReadUsecaseSpec.php rename to tests/spec/Core/Usecase/ReadUsecaseSpec.php diff --git a/spec/Core/Usecase/SearchUsecaseSpec.php b/tests/spec/Core/Usecase/SearchUsecaseSpec.php similarity index 100% rename from spec/Core/Usecase/SearchUsecaseSpec.php rename to tests/spec/Core/Usecase/SearchUsecaseSpec.php diff --git a/spec/Core/Usecase/UpdateUsecaseSpec.php b/tests/spec/Core/Usecase/UpdateUsecaseSpec.php similarity index 100% rename from spec/Core/Usecase/UpdateUsecaseSpec.php rename to tests/spec/Core/Usecase/UpdateUsecaseSpec.php diff --git a/spec/Core/Usecase/User/LoginUserSpec.php b/tests/spec/Core/Usecase/User/LoginUserSpec.php similarity index 100% rename from spec/Core/Usecase/User/LoginUserSpec.php rename to tests/spec/Core/Usecase/User/LoginUserSpec.php diff --git a/spec/ruleset.xml b/tests/spec/ruleset.xml similarity index 81% rename from spec/ruleset.xml rename to tests/spec/ruleset.xml index b63e9a9a20..2d4aeedff0 100644 --- a/spec/ruleset.xml +++ b/tests/spec/ruleset.xml @@ -6,5 +6,6 @@ + - \ No newline at end of file + diff --git a/application/tests/classes/Core/Traits/DataTranformerTest.php b/tests/unit/Core/Traits/DataTransformerTest.php similarity index 66% rename from application/tests/classes/Core/Traits/DataTranformerTest.php rename to tests/unit/Core/Traits/DataTransformerTest.php index 34f144453b..833afdc4b8 100644 --- a/application/tests/classes/Core/Traits/DataTranformerTest.php +++ b/tests/unit/Core/Traits/DataTransformerTest.php @@ -1,4 +1,4 @@ - '*date' - ]; - } - - public function pTransform($data) { - return $this->transform($data); - } -} - -class DataTransformerTest extends Unittest_TestCase { +/** + * @backupGlobals disabled + * @preserveGlobalState disabled + */ +class DataTransformerTest extends \PHPUnit\Framework\TestCase +{ /** * Test get method */ - public function test_transformDate() + public function testTransformDate() { - $mock = new mockDataTransformer(); + $mock = new MockDataTransformer(); - $original_date = new DateTime('2014-12-01 11:00', new DateTimeZone('UTC')); + $original_date = new \DateTime('2014-12-01 11:00', new \DateTimeZone('UTC')); $date1 = $mock->pTransform(['date' => $original_date])['date']; $this->assertInstanceOf('DateTimeInterface', $date1); $this->assertNotSame($original_date, $date1); @@ -46,7 +38,6 @@ public function test_transformDate() $date3 = $mock->pTransform(['date' => '2016-10-15T12:18:27+13:00'])['date']; $this->assertInstanceOf('DateTimeInterface', $date3); $this->assertEquals('2016-10-14 23:18:27', $date3->format('Y-m-d H:i:s')); - $this->assertEquals('2016-10-14T23:18:27+00:00', $date3->format(DateTime::W3C)); + $this->assertEquals('2016-10-14T23:18:27+00:00', $date3->format(\DateTime::W3C)); } - } diff --git a/tests/unit/Core/Traits/MockDataTransformer.php b/tests/unit/Core/Traits/MockDataTransformer.php new file mode 100644 index 0000000000..821eafc38c --- /dev/null +++ b/tests/unit/Core/Traits/MockDataTransformer.php @@ -0,0 +1,20 @@ + '*date' + ]; + } + + public function pTransform($data) + { + return $this->transform($data); + } +} diff --git a/application/tests/classes/Ushahidi/PostValueTest.php b/tests/unit/Ushahidi/PostValueRepositoryTest.php similarity index 84% rename from application/tests/classes/Ushahidi/PostValueTest.php rename to tests/unit/Ushahidi/PostValueRepositoryTest.php index 17bb552998..df70ea80a8 100644 --- a/application/tests/classes/Ushahidi/PostValueTest.php +++ b/tests/unit/Ushahidi/PostValueRepositoryTest.php @@ -1,4 +1,4 @@ -repository = $this->getMockBuilder('Ushahidi_Repository_Post_Value') + $this->repository = $this->getMockBuilder(\Ushahidi_Repository_Post_Value::class) ->setMethods(['selectOne', 'selectQuery', 'getTable']) ->disableOriginalConstructor() ->getMock(); - $this->postvalue = $this->getMock('Ushahidi\Core\Entity\Post_Value'); + $this->postvalue = $this->createMock(\Ushahidi\Core\Entity\PostValue::class); } /** * Test get method */ - public function test_get() + public function testGet() { $this->repository->expects($this->any()) ->method('selectOne') @@ -49,7 +56,7 @@ public function test_get() /** * Test get method */ - public function test_getAllForPost() + public function testGetAllForPost() { // Create mocks $mockQueryBuilder = $this->getMockBuilder('Database_Query_Builder_Select') @@ -93,5 +100,4 @@ public function test_getAllForPost() $this->assertCount(3, $values); $this->assertInstanceOf('Ushahidi\Core\Entity\PostValue', current($values)); } - } diff --git a/application/tests/classes/Util/BoundingBoxTest.php b/tests/unit/Util/BoundingBoxTest.php similarity index 81% rename from application/tests/classes/Util/BoundingBoxTest.php rename to tests/unit/Util/BoundingBoxTest.php index d3b9036df8..89357c78c0 100644 --- a/application/tests/classes/Util/BoundingBoxTest.php +++ b/tests/unit/Util/BoundingBoxTest.php @@ -1,4 +1,4 @@ -assertEquals('POLYGON((-180 -90,180 -90,180 90,-180 90,-180 -90))', $bb->toWKT()); - + $bb = new Util_BoundingBox(-1, -1, 1, 1); $this->assertEquals('POLYGON((-1 -1,1 -1,1 1,-1 1,-1 -1))', $bb->toWKT()); } - + /** * Test Bounding Box to array * * @return void */ - public function test_as_array() + public function testAsArray() { $bb = new Util_BoundingBox(-180, -90, 180, 90); $this->assertEquals(array(-180, -90, 180, 90), $bb->as_array()); - + $bb = new Util_BoundingBox(-1, -1, 1, 1); $this->assertEquals(array(-1, -1, 1, 1), $bb->as_array()); } - + /** * Test Bounding Box to geometry * * @return void */ - public function test_toGeometry() + public function testToGeometry() { $bb = new Util_BoundingBox(-180, -90, 180, 90); $geom = $bb->toGeometry(); $this->assertEquals('POLYGON((-180 -90,180 -90,180 90,-180 90,-180 -90))', $geom->toWKT()); - + $bb = new Util_BoundingBox(-1, -1, 1, 1); $geom = $bb->toGeometry(); $this->assertEquals('POLYGON((-1 -1,1 -1,1 1,-1 1,-1 -1))', $geom->toWKT()); } -} \ No newline at end of file +} diff --git a/application/tests/classes/Util/TileTest.php b/tests/unit/Util/TileTest.php similarity index 88% rename from application/tests/classes/Util/TileTest.php rename to tests/unit/Util/TileTest.php index 24290676d9..cd4047a139 100644 --- a/application/tests/classes/Util/TileTest.php +++ b/tests/unit/Util/TileTest.php @@ -1,4 +1,4 @@ -assertEquals(1, Util_Tile::numTiles(0)); $this->assertEquals(2, Util_Tile::numTiles(1)); $this->assertEquals(4, Util_Tile::numTiles(2)); $this->assertEquals(256, Util_Tile::numTiles(8)); } - + /** * Test tileToBoundingBox * * @return void */ - public function test_tileToBoundingBox() + public function testTileToBoundingBox() { $bb = Util_Tile::tileToBoundingBox(0, 0, 0); $this->assertAttributeEquals(85.051100, 'north', $bb, '', 0.0002); $this->assertAttributeEquals(-85.051100, 'south', $bb, '', 0.0002); $this->assertAttributeEquals(-180, 'west', $bb, '', 0.0002); $this->assertAttributeEquals(180, 'east', $bb, '', 0.0002); - + $bb = Util_Tile::tileToBoundingBox(1, 1, 1); $this->assertAttributeEquals(0, 'north', $bb, '', 0.0002); $this->assertAttributeEquals(-85.051100, 'south', $bb, '', 0.0002); $this->assertAttributeEquals(0, 'west', $bb, '', 0.0002); $this->assertAttributeEquals(180, 'east', $bb, '', 0.0002); - + $bb = Util_Tile::tileToBoundingBox(2, 2, 1); $this->assertAttributeEquals(66.5131, 'north', $bb, '', 0.0002); $this->assertAttributeEquals(0, 'south', $bb, '', 0.0002); $this->assertAttributeEquals(0, 'west', $bb, '', 0.0002); $this->assertAttributeEquals(90, 'east', $bb, '', 0.0002); - + $bb = Util_Tile::tileToBoundingBox(8, 13, 14); $this->assertAttributeEquals(83.026183, 'north', $bb, '', 0.0002); $this->assertAttributeEquals(82.853346, 'south', $bb, '', 0.0002); $this->assertAttributeEquals(-161.718750, 'west', $bb, '', 0.0002); $this->assertAttributeEquals(-160.312500, 'east', $bb, '', 0.0002); } - + /** * Test tileToLon * * @return void */ - public function test_tileToLon() + public function testTileToLon() { $this->assertEquals(-180, Util_Tile::tileToLon(0, 0), '', 0.0002); $this->assertEquals(0, Util_Tile::tileToLon(1, 1), '', 0.0002); $this->assertEquals(0, Util_Tile::tileToLon(2, 2), '', 0.0002); $this->assertEquals(-163.125000, Util_Tile::tileToLon(12, 8), '', 0.0002); } - + /** * Test tileToLat * * @return void */ - public function test_tileToLat() + public function testTileToLat() { $this->assertEquals(85.05112, Util_Tile::tileToLat(0, 0), '', 0.0002); $this->assertEquals(0, Util_Tile::tileToLat(1, 1), '', 0.0002); $this->assertEquals(0, Util_Tile::tileToLat(2, 2), '', 0.0002); $this->assertEquals(83.026183, Util_Tile::tileToLat(14, 8), '', 0.0002); } -} \ No newline at end of file +}