From c1fca88fc3f5be20218d92922add07726161458b Mon Sep 17 00:00:00 2001 From: Arun Bhalla Date: Thu, 25 May 2017 02:34:42 -0700 Subject: [PATCH 01/30] [CH3370] Support publishing events via ld-relay --- composer.json | 2 +- src/LaunchDarkly/CurlEventPublisher.php | 63 ++++++++++++++++++++ src/LaunchDarkly/EventProcessor.php | 76 +++++++----------------- src/LaunchDarkly/EventPublisher.php | 18 ++++++ src/LaunchDarkly/LDClient.php | 21 +++++-- src/LaunchDarkly/RelayEventPublisher.php | 52 ++++++++++++++++ 6 files changed, 173 insertions(+), 59 deletions(-) create mode 100644 src/LaunchDarkly/CurlEventPublisher.php create mode 100644 src/LaunchDarkly/EventPublisher.php create mode 100644 src/LaunchDarkly/RelayEventPublisher.php diff --git a/composer.json b/composer.json index 2ed48998a..8f18b4c7b 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "zendframework/zend-serializer": "^2.7" }, "suggest": { - "guzzlehttp/guzzle": "(^6.2.1) Required when using the default FeatureRequester", + "guzzlehttp/guzzle": "(^6.2.1) Required when using RelayEventPublisher or the default FeatureRequester", "kevinrob/guzzle-cache-middleware": "(^1.4.1) Recommended for performance when using the default FeatureRequester", "predis/predis": "(^1.0) Required when using LDDFeatureRequester" }, diff --git a/src/LaunchDarkly/CurlEventPublisher.php b/src/LaunchDarkly/CurlEventPublisher.php new file mode 100644 index 000000000..d14a6e152 --- /dev/null +++ b/src/LaunchDarkly/CurlEventPublisher.php @@ -0,0 +1,63 @@ +_sdkKey = $apiKey; + + $eventsUri = LDClient::DEFAULT_EVENTS_URI; + if (isset($options['events_uri'])) { + $eventsUri = $options['events_uri']; + } + $url = parse_url(rtrim($eventsUri,'/')); + $this->_host = $url['host']; + $this->_ssl = $url['scheme'] === 'https'; + if (isset($url['port'])) { + $this->_port = $url['port']; + } + else { + $this->_port = $this->_ssl ? 443 : 80; + } + if (isset($url['path'])) { + $this->_path = $url['path']; + } + else { + $this->_path = ''; + } + + if (array_key_exists('curl', $options)) { + $this->_curl = $options['curl']; + } + } + + public function publish($payload) { + $args = $this->createArgs($payload); + + return $this->makeRequest($args); + } + + private function createArgs($payload) { + $scheme = $this->_ssl ? "https://" : "http://"; + $args = " -X POST"; + $args.= " -H 'Content-Type: application/json'"; + $args.= " -H " . escapeshellarg("Authorization: " . $this->_sdkKey); + $args.= " -H 'User-Agent: PHPClient/" . LDClient::VERSION . "'"; + $args.= " -H 'Accept: application/json'"; + $args.= " -d " . escapeshellarg($payload); + $args.= " " . escapeshellarg($scheme . $this->_host . ":" . $this->_port . $this->_path . "/bulk"); + return $args; + } + + private function makeRequest($args) { + $cmd = $this->_curl . " " . $args . ">> /dev/null 2>&1 &"; + shell_exec($cmd); + return true; + } +} \ No newline at end of file diff --git a/src/LaunchDarkly/EventProcessor.php b/src/LaunchDarkly/EventProcessor.php index cfa74043e..621789097 100644 --- a/src/LaunchDarkly/EventProcessor.php +++ b/src/LaunchDarkly/EventProcessor.php @@ -6,44 +6,13 @@ */ class EventProcessor { - private $_sdkKey; + private $_eventPublisher; private $_queue; private $_capacity; private $_timeout; - private $_host; - private $_port; - private $_ssl; - private $_curl = '/usr/bin/env curl'; public function __construct($apiKey, $options = array()) { - $this->_sdkKey = $apiKey; - if (!isset($options['events_uri'])) { - $this->_host = 'events.launchdarkly.com'; - $this->_port = 443; - $this->_ssl = true; - $this->_path = ''; - } - else { - $url = parse_url(rtrim($options['events_uri'],'/')); - $this->_host = $url['host']; - $this->_ssl = $url['scheme'] === 'https'; - if (isset($url['port'])) { - $this->_port = $url['port']; - } - else { - $this->_port = $this->_ssl ? 443 : 80; - } - if (isset($url['path'])) { - $this->_path = $url['path']; - } - else { - $this->_path = ''; - } - } - - if (array_key_exists('curl', $options)) { - $this->_curl = $options['curl']; - } + $this->_eventPublisher = $this->getEventPublisher($apiKey, $options); $this->_capacity = $options['capacity']; $this->_timeout = $options['timeout']; @@ -76,28 +45,29 @@ protected function flush() { $payload = json_encode($this->_queue); - $args = $this->createArgs($payload); - - return $this->makeRequest($args); + return $this->_eventPublisher->publish($payload); } - private function createArgs($payload) { - $scheme = $this->_ssl ? "https://" : "http://"; - $args = " -X POST"; - $args.= " -H 'Content-Type: application/json'"; - $args.= " -H " . escapeshellarg("Authorization: " . $this->_sdkKey); - $args.= " -H 'User-Agent: PHPClient/" . LDClient::VERSION . "'"; - $args.= " -H 'Accept: application/json'"; - $args.= " -d " . escapeshellarg($payload); - $args.= " " . escapeshellarg($scheme . $this->_host . ":" . $this->_port . $this->_path . "/bulk"); - return $args; - } - - private function makeRequest($args) { - $cmd = $this->_curl . " " . $args . ">> /dev/null 2>&1 &"; - shell_exec($cmd); - return true; - } + /** + * @param string $sdkKey + * @param mixed[] $options + * @return EventPublisher + */ + private function getEventPublisher($sdkKey, array $options) + { + if (isset($options['event_publisher']) && $options['event_publisher'] instanceof EventPublisher) { + return $options['event_publisher']; + } + if (isset($options['event_publisher_class'])) { + $eventPublisherClass = $options['event_publisher_class']; + } else { + $eventPublisherClass = CurlEventPublisher::class; + } + if (!is_a($eventPublisherClass, EventPublisher::class, true)) { + throw new \InvalidArgumentException; + } + return new $eventPublisherClass($sdkKey, $options); + } } \ No newline at end of file diff --git a/src/LaunchDarkly/EventPublisher.php b/src/LaunchDarkly/EventPublisher.php new file mode 100644 index 000000000..63b9446e8 --- /dev/null +++ b/src/LaunchDarkly/EventPublisher.php @@ -0,0 +1,18 @@ +_sdkKey = $sdkKey; @@ -51,6 +57,11 @@ public function __construct($sdkKey, $options = array()) { } else { $this->_baseUri = rtrim($options['base_uri'], '/'); } + if (!isset($options['events_uri'])) { + $this->_eventsUri = self::DEFAULT_EVENTS_URI; + } else { + $this->_eventsUri = rtrim($options['events_uri'], '/'); + } if (isset($options['send_events'])) { $this->_send_events = $options['send_events']; } @@ -82,15 +93,15 @@ public function __construct($sdkKey, $options = array()) { $this->_eventProcessor = new EventProcessor($sdkKey, $options); - $this->_featureRequester = $this->getFeatureRequester($options, $sdkKey); + $this->_featureRequester = $this->getFeatureRequester($sdkKey, $options); } /** - * @param mixed[] $options * @param string $sdkKey + * @param mixed[] $options * @return FeatureRequester */ - private function getFeatureRequester(array $options, $sdkKey) + private function getFeatureRequester($sdkKey, array $options) { if (isset($options['feature_requester']) && $options['feature_requester'] instanceof FeatureRequester) { return $options['feature_requester']; diff --git a/src/LaunchDarkly/RelayEventPublisher.php b/src/LaunchDarkly/RelayEventPublisher.php new file mode 100644 index 000000000..fcffe656e --- /dev/null +++ b/src/LaunchDarkly/RelayEventPublisher.php @@ -0,0 +1,52 @@ +_sdkKey = $apiKey; + $this->_logger = $options['logger']; + if (isset($options['events_uri'])) { + $this->_eventsUri = $options['events_uri']; + } else { + $this->_eventsUri = LDClient::DEFAULT_EVENTS_URI; + } + $this->_requestOptions = [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'Authorization' => $this->_sdkKey, + 'User-Agent' => 'PHPClient/' . LDClient::VERSION, + 'Accept' => 'application/json' + ], + 'timeout' => $options['timeout'], + 'connect_timeout' => $options['connect_timeout'] + ]; + } + + public function publish($payload) { + $client = new Client(['base_uri' => $this->_eventsUri]); + + try { + $options = $this->_requestOptions; + $options['body'] = $payload; + $response = $client->request('POST', '/bulk', $options); + + return $response->getStatusCode() < 300; + } catch (\Exception $e) { + $this->_logger->warning("RelayEventPublisher::publish caught $e"); + return false; + } + } +} \ No newline at end of file From ae90fe1d9810968fa58b4f96b1f424c5a48b7286 Mon Sep 17 00:00:00 2001 From: Arun Bhalla Date: Thu, 25 May 2017 12:13:44 -0700 Subject: [PATCH 02/30] Rename `apiKey` to `sdkKey` --- src/LaunchDarkly/ApcLDDFeatureRequester.php | 4 ++-- src/LaunchDarkly/CurlEventPublisher.php | 4 ++-- src/LaunchDarkly/EventProcessor.php | 4 ++-- src/LaunchDarkly/LDDFeatureRequester.php | 6 +++--- src/LaunchDarkly/RelayEventPublisher.php | 4 ++-- tests/LDDFeatureRequesterTest.php | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/LaunchDarkly/ApcLDDFeatureRequester.php b/src/LaunchDarkly/ApcLDDFeatureRequester.php index ad4a36af7..d6d56e005 100644 --- a/src/LaunchDarkly/ApcLDDFeatureRequester.php +++ b/src/LaunchDarkly/ApcLDDFeatureRequester.php @@ -13,8 +13,8 @@ class ApcLDDFeatureRequester extends LDDFeatureRequester { protected $_expiration = 30; - function __construct($baseUri, $apiKey, $options) { - parent::__construct($baseUri, $apiKey, $options); + function __construct($baseUri, $sdkKey, $options) { + parent::__construct($baseUri, $sdkKey, $options); if (isset($options['apc_expiration'])) { $this->_expiration = (int)$options['apc_expiration']; diff --git a/src/LaunchDarkly/CurlEventPublisher.php b/src/LaunchDarkly/CurlEventPublisher.php index d14a6e152..e898edbed 100644 --- a/src/LaunchDarkly/CurlEventPublisher.php +++ b/src/LaunchDarkly/CurlEventPublisher.php @@ -9,8 +9,8 @@ class CurlEventPublisher implements EventPublisher private $_ssl; private $_curl = '/usr/bin/env curl'; - function __construct($apiKey, array $options = array()) { - $this->_sdkKey = $apiKey; + function __construct($sdkKey, array $options = array()) { + $this->_sdkKey = $sdkKey; $eventsUri = LDClient::DEFAULT_EVENTS_URI; if (isset($options['events_uri'])) { diff --git a/src/LaunchDarkly/EventProcessor.php b/src/LaunchDarkly/EventProcessor.php index 621789097..af6ea81ab 100644 --- a/src/LaunchDarkly/EventProcessor.php +++ b/src/LaunchDarkly/EventProcessor.php @@ -11,8 +11,8 @@ class EventProcessor { private $_capacity; private $_timeout; - public function __construct($apiKey, $options = array()) { - $this->_eventPublisher = $this->getEventPublisher($apiKey, $options); + public function __construct($sdkKey, $options = array()) { + $this->_eventPublisher = $this->getEventPublisher($sdkKey, $options); $this->_capacity = $options['capacity']; $this->_timeout = $options['timeout']; diff --git a/src/LaunchDarkly/LDDFeatureRequester.php b/src/LaunchDarkly/LDDFeatureRequester.php index 67142b538..dd5ec7262 100644 --- a/src/LaunchDarkly/LDDFeatureRequester.php +++ b/src/LaunchDarkly/LDDFeatureRequester.php @@ -7,7 +7,7 @@ class LDDFeatureRequester implements FeatureRequester { protected $_baseUri; - protected $_apiKey; + protected $_sdkKey; protected $_options; protected $_features_key; /** @var LoggerInterface */ @@ -15,9 +15,9 @@ class LDDFeatureRequester implements FeatureRequester { /** @var ClientInterface */ private $_connection; - function __construct($baseUri, $apiKey, $options) { + function __construct($baseUri, $sdkKey, $options) { $this->_baseUri = $baseUri; - $this->_apiKey = $apiKey; + $this->_sdkKey = $sdkKey; if (!isset($options['redis_host'])) { $options['redis_host'] = 'localhost'; } diff --git a/src/LaunchDarkly/RelayEventPublisher.php b/src/LaunchDarkly/RelayEventPublisher.php index fcffe656e..8b59dc992 100644 --- a/src/LaunchDarkly/RelayEventPublisher.php +++ b/src/LaunchDarkly/RelayEventPublisher.php @@ -15,8 +15,8 @@ class RelayEventPublisher implements EventPublisher /** @var mixed[] */ private $_requestOptions; - function __construct($apiKey, array $options = array()) { - $this->_sdkKey = $apiKey; + function __construct($sdkKey, array $options = array()) { + $this->_sdkKey = $sdkKey; $this->_logger = $options['logger']; if (isset($options['events_uri'])) { $this->_eventsUri = $options['events_uri']; diff --git a/tests/LDDFeatureRequesterTest.php b/tests/LDDFeatureRequesterTest.php index 97bfcc428..2fb2d7d07 100644 --- a/tests/LDDFeatureRequesterTest.php +++ b/tests/LDDFeatureRequesterTest.php @@ -29,7 +29,7 @@ protected function setUp() public function testGet() { - $sut = new LDDFeatureRequester('example.com', 'MyApiKey', [ + $sut = new LDDFeatureRequester('example.com', 'MySdkKey', [ 'logger' => $this->logger, 'predis_client' => $this->predisClient, ]); From 384a406f63bc5bc7100c3d9745d19af2203d0bf1 Mon Sep 17 00:00:00 2001 From: Arun Bhalla Date: Thu, 25 May 2017 15:09:27 -0700 Subject: [PATCH 03/30] Add documentation for GuzzleEventPublisher and CurlEventPublisher --- README.md | 29 +++++++++++++++---- composer.json | 2 +- src/LaunchDarkly/CurlEventPublisher.php | 10 +++++++ src/LaunchDarkly/EventPublisher.php | 3 ++ ...Publisher.php => GuzzleEventPublisher.php} | 14 +++++++-- 5 files changed, 49 insertions(+), 9 deletions(-) rename src/LaunchDarkly/{RelayEventPublisher.php => GuzzleEventPublisher.php} (69%) diff --git a/README.md b/README.md index db889dd62..368d8ed30 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Require Guzzle as a dependency: It will then be used as the default way of fetching flags. -With Guzzle, you could persist your cache somewhere other than the default in-memory store, like Memcached or Redis. You could then specify your cache when initializing the client with the [cache option](https://github.com/launchdarkly/php-client/blob/master/src/LaunchDarkly/LDClient.php#L42). +With Guzzle, you could persist your cache somewhere other than the default in-memory store, like Memcached or Redis. You could then specify your cache when initializing the client with the [cache option](https://github.com/launchdarkly/php-client/blob/master/src/LaunchDarkly/LDClient.php#L44). $client = new LaunchDarkly\LDClient("YOUR_SDK_KEY", array("cache" => $cacheStorage)); @@ -66,15 +66,32 @@ With Guzzle, you could persist your cache somewhere other than the default in-me Using LD-Relay ============== -* Setup [ld-relay](https://github.com/launchdarkly/ld-relay) in [daemon-mode](https://github.com/launchdarkly/ld-relay#redis-storage-and-daemon-mode) with Redis +The LaunchDarkly Relay Proxy ([ld-relay](https://github.com/launchdarkly/ld-relay)) consumes the LaunchDarkly streaming API and can update +a Redis cache operating in your production environment. The ld-relay offers many benefits such as performance and feature flag consistency. With PHP applications, we strongly recommend setting up ld-relay with a Redis store. -* Require Predis as a dependency: +1. Set up ld-relay in [daemon-mode](https://github.com/launchdarkly/ld-relay#redis-storage-and-daemon-mode) with Redis - php composer.phar require "predis/predis:1.0.*" +2. Require Predis as a dependency: -* Create the LDClient with the Redis feature requester as an option: + php composer.phar require "predis/predis:1.0.*" - $client = new LaunchDarkly\LDClient("your_sdk_key", ['feature_requester_class' => 'LaunchDarkly\LDDFeatureRequester', 'redis_host' => 'your.redis.host', 'redis_port' => 6379]); +3. Create the LDClient with the Redis feature requester as an option: + + $client = new LaunchDarkly\LDClient("your_sdk_key", [ + 'feature_requester_class' => 'LaunchDarkly\LDDFeatureRequester', + 'redis_host' => 'your.redis.host', + 'redis_port' => 6379 + ]); + +4. If ld-relay is configured for [event forwarding](https://github.com/launchdarkly/ld-relay#event-forwarding), you can configure the LDClient to publish events to ld-relay instead of directly to `events.launchdarkly.com`. Using `GuzzleEventPublisher` with ld-relay event forwarding can be an efficient alternative to the default `curl`-based event publishing. + + $client = new LaunchDarkly\LDClient("your_sdk_key", [ + 'event_publisher_class' => 'LaunchDarkly\GuzzleEventPublisher', + 'events_uri' => 'http://your-ldrelay-host:8030', + 'feature_requester_class' => 'LaunchDarkly\LDDFeatureRequester', + 'redis_host' => 'your.redis.host', + 'redis_port' => 6379 + ]); Testing ------- diff --git a/composer.json b/composer.json index 8f18b4c7b..28d09d16e 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "zendframework/zend-serializer": "^2.7" }, "suggest": { - "guzzlehttp/guzzle": "(^6.2.1) Required when using RelayEventPublisher or the default FeatureRequester", + "guzzlehttp/guzzle": "(^6.2.1) Required when using GuzzleEventPublisher or the default FeatureRequester", "kevinrob/guzzle-cache-middleware": "(^1.4.1) Recommended for performance when using the default FeatureRequester", "predis/predis": "(^1.0) Required when using LDDFeatureRequester" }, diff --git a/src/LaunchDarkly/CurlEventPublisher.php b/src/LaunchDarkly/CurlEventPublisher.php index e898edbed..96131ed55 100644 --- a/src/LaunchDarkly/CurlEventPublisher.php +++ b/src/LaunchDarkly/CurlEventPublisher.php @@ -1,6 +1,16 @@ getStatusCode() < 300; } catch (\Exception $e) { - $this->_logger->warning("RelayEventPublisher::publish caught $e"); + $this->_logger->warning("GuzzleEventPublisher::publish caught $e"); return false; } } From fbe5bfc6823edfa4b82f57672a32e503935180b0 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 13 Oct 2017 14:17:19 -0700 Subject: [PATCH 04/30] implement private user attributes --- src/LaunchDarkly/EventProcessor.php | 9 +- src/LaunchDarkly/EventSerializer.php | 87 +++++++++++++ src/LaunchDarkly/LDClient.php | 4 +- src/LaunchDarkly/LDUser.php | 45 ++----- src/LaunchDarkly/LDUserBuilder.php | 10 +- src/LaunchDarkly/Util.php | 2 +- tests/EventSerializerTest.php | 187 +++++++++++++++++++++++++++ tests/LDUserTest.php | 26 ---- 8 files changed, 300 insertions(+), 70 deletions(-) create mode 100644 src/LaunchDarkly/EventSerializer.php create mode 100644 tests/EventSerializerTest.php diff --git a/src/LaunchDarkly/EventProcessor.php b/src/LaunchDarkly/EventProcessor.php index f408ac635..a199a43a8 100644 --- a/src/LaunchDarkly/EventProcessor.php +++ b/src/LaunchDarkly/EventProcessor.php @@ -7,13 +7,15 @@ class EventProcessor { private $_eventPublisher; + private $_eventSerializer; private $_queue; private $_capacity; private $_timeout; public function __construct($sdkKey, $options = array()) { $this->_eventPublisher = $this->getEventPublisher($sdkKey, $options); - + $this->_eventSerializer = new EventSerializer($options); + $this->_capacity = $options['capacity']; $this->_timeout = $options['timeout']; @@ -47,7 +49,10 @@ public function flush() { return null; } - $payload = json_encode($this->_queue); + $payload = $this->_eventSerializer->serializeEvents($this->_queue); + + // We don't expect flush to be called more than once per request cycle, but let's empty the queue just in case + $this->_queue = array(); return $this->_eventPublisher->publish($payload); } diff --git a/src/LaunchDarkly/EventSerializer.php b/src/LaunchDarkly/EventSerializer.php new file mode 100644 index 000000000..d980417d1 --- /dev/null +++ b/src/LaunchDarkly/EventSerializer.php @@ -0,0 +1,87 @@ +_allAttrsPrivate = isset($options['allAttrsPrivate']) && $options['allAttrsPrivate']; + $this->_privateAttrNames = isset($options['privateAttrNames']) ? $options['privateAttrNames'] : array(); + } + + public function serializeEvents($events) { + $filtered = array(); + foreach ($events as $e) { + array_push($filtered, $this->filterEvent($e)); + } + return json_encode($filtered); + } + + private function filterEvent($e) { + $ret = array(); + foreach ($e as $key => $value) { + if ($key == 'user') { + $ret[$key] = $this->serializeUser($value); + } + else { + $ret[$key] = $value; + } + } + return $ret; + } + + private function isPrivateAttr($name, $userPrivateAttrs, &$allPrivateAttrs) { + if ($this->_allAttrsPrivate || + array_search($name, $userPrivateAttrs) !== FALSE || + array_search($name, $this->_privateAttrNames) !== FALSE) { + $allPrivateAttrs[$name] = $name; + return true; + } + else { + return false; + } + } + + private function serializeUser($user) { + $json = array("key" => $user->getKey()); + $userPrivateAttrs = $user->getPrivateAttrs(); + $allPrivateAttrs = array(); + + $attrs = array( + 'secondary' => $user->getSecondary(), + 'ip' => $user->getIP(), + 'country' => $user->getCountry(), + 'email' => $user->getEmail(), + 'name' => $user->getName(), + 'avatar' => $user->getAvatar(), + 'firstName' => $user->getFirstName(), + 'lastName' => $user->getLastName(), + 'anonymous' => $user->getAnonymous() + ); + foreach ($attrs as $key => $value) { + if ($value != null && !$this->isPrivateAttr($key, $userPrivateAttrs, $allPrivateAttrs)) { + $json[$key] = $value; + } + } + if (!empty($user->getCustom())) { + $customs = array(); + foreach ($user->getCustom() as $key => $value) { + if ($value != null && !$this->isPrivateAttr($key, $userPrivateAttrs, $allPrivateAttrs)) { + $customs[$key] = $value; + } + } + $json['custom'] = $customs; + } + if (count($allPrivateAttrs)) { + $pa = array_keys($allPrivateAttrs); + sort($pa); + $json['privateAttrs'] = $pa; + } + return $json; + } +} diff --git a/src/LaunchDarkly/LDClient.php b/src/LaunchDarkly/LDClient.php index 64d007b52..1dc276398 100644 --- a/src/LaunchDarkly/LDClient.php +++ b/src/LaunchDarkly/LDClient.php @@ -207,7 +207,7 @@ public function track($eventName, $user, $data) { } $event = array(); - $event['user'] = $user->toJSON(); + $event['user'] = $user; $event['kind'] = "custom"; $event['creationDate'] = Util::currentTimeUnixMillis(); $event['key'] = $eventName; @@ -229,7 +229,7 @@ public function identify($user) { } $event = array(); - $event['user'] = $user->toJSON(); + $event['user'] = $user; $event['kind'] = "identify"; $event['creationDate'] = Util::currentTimeUnixMillis(); $event['key'] = $user->getKey(); diff --git a/src/LaunchDarkly/LDUser.php b/src/LaunchDarkly/LDUser.php index 76aaac5fe..b309c6d3c 100644 --- a/src/LaunchDarkly/LDUser.php +++ b/src/LaunchDarkly/LDUser.php @@ -18,6 +18,7 @@ class LDUser { protected $_lastName = null; protected $_anonyomus = false; protected $_custom = array(); + protected $_privateAttrs = array(); /** * @param string $key Unique key for the user. For authenticated users, this may be a username or e-mail address. For anonymous users, this could be an IP address or session ID. @@ -32,7 +33,8 @@ class LDUser { * @param boolean|null $anonymous Whether this is an anonymous user * @param array|null $custom Other custom attributes that can be used to create custom rules */ - public function __construct($key, $secondary = null, $ip = null, $country = null, $email = null, $name = null, $avatar = null, $firstName = null, $lastName = null, $anonymous = null, $custom = array()) { + public function __construct($key, $secondary = null, $ip = null, $country = null, $email = null, $name = null, $avatar = null, $firstName = null, $lastName = null, $anonymous = null, $custom = array(), + $privateAttrs = array()) { if ($key !== null) { $this->_key = strval($key); } @@ -46,6 +48,7 @@ public function __construct($key, $secondary = null, $ip = null, $country = null $this->_lastName = $lastName; $this->_anonymous = $anonymous; $this->_custom = $custom; + $this->_privateAttrs = $privateAttrs; } public function getValueForEvaluation($attr) { @@ -129,43 +132,11 @@ public function getAnonymous() { return $this->_anonymous; } + public function getPrivateAttrs() { + return $this->_privateAttrs; + } + public function isKeyBlank() { return isset($this->_key) && empty($this->_key); } - - public function toJSON() { - $json = array("key" => $this->_key); - - if (isset($this->_secondary)) { - $json['secondary'] = $this->_secondary; - } - if (isset($this->_ip)) { - $json['ip'] = $this->_ip; - } - if (isset($this->_country)) { - $json['country'] = $this->_country; - } - if (isset($this->_email)) { - $json['email'] = $this->_email; - } - if (isset($this->_name)) { - $json['name'] = $this->_name; - } - if (isset($this->_avatar)) { - $json['avatar'] = $this->_avatar; - } - if (isset($this->_firstName)) { - $json['firstName'] = $this->_firstName; - } - if (isset($this->_lastName)) { - $json['lastName'] = $this->_lastName; - } - if (isset($this->_custom) && !empty($this->_custom)) { - $json['custom'] = $this->_custom; - } - if (isset($this->_anonymous)) { - $json['anonymous'] = $this->_anonymous; - } - return $json; - } } diff --git a/src/LaunchDarkly/LDUserBuilder.php b/src/LaunchDarkly/LDUserBuilder.php index e0a4484d7..9065432e7 100644 --- a/src/LaunchDarkly/LDUserBuilder.php +++ b/src/LaunchDarkly/LDUserBuilder.php @@ -13,7 +13,8 @@ class LDUserBuilder { protected $_lastName = null; protected $_anonymous = null; protected $_custom = array(); - + protected $_privateAttrs = array(); + public function __construct($key) { $this->_key = $key; } @@ -68,8 +69,13 @@ public function custom($custom) { return $this; } + public function privateAttrs($privateAttrs) { + $this->_privateAttrs = $privateAttrs; + return $this; + } + public function build() { - return new LDUser($this->_key, $this->_secondary, $this->_ip, $this->_country, $this->_email, $this->_name, $this->_avatar, $this->_firstName, $this->_lastName, $this->_anonymous, $this->_custom); + return new LDUser($this->_key, $this->_secondary, $this->_ip, $this->_country, $this->_email, $this->_name, $this->_avatar, $this->_firstName, $this->_lastName, $this->_anonymous, $this->_custom, $this->_privateAttrs); } } \ No newline at end of file diff --git a/src/LaunchDarkly/Util.php b/src/LaunchDarkly/Util.php index e1d84897a..b2eb3b246 100644 --- a/src/LaunchDarkly/Util.php +++ b/src/LaunchDarkly/Util.php @@ -36,7 +36,7 @@ public static function currentTimeUnixMillis() { */ public static function newFeatureRequestEvent($key, $user, $value, $default, $version = null, $prereqOf = null) { $event = array(); - $event['user'] = $user->toJSON(); + $event['user'] = $user; $event['value'] = $value; $event['kind'] = "feature"; $event['creationDate'] = Util::currentTimeUnixMillis(); diff --git a/tests/EventSerializerTest.php b/tests/EventSerializerTest.php new file mode 100644 index 000000000..70662922f --- /dev/null +++ b/tests/EventSerializerTest.php @@ -0,0 +1,187 @@ +firstName('Sue') + ->custom(array('bizzle' => 'def', 'dizzle' => 'ghi')) + ->build(); + } + + private function getUserSpecifyingOwnPrivateAttr() { + return (new LDUserBuilder('abc'))->firstName('Sue') + ->custom(array('bizzle' => 'def', 'dizzle' => 'ghi')) + ->privateAttrs(array('dizzle', 'unused')) + ->build(); + } + + private function getFullUserResult() { + return array( + 'key' => 'abc', + 'firstName' => 'Sue', + 'custom' => array('bizzle' => 'def', 'dizzle' => 'ghi') + ); + } + + private function getUserResultWithAllAttrsHidden() { + return array( + 'key' => 'abc', + 'custom' => array(), + 'privateAttrs' => array('bizzle', 'dizzle', 'firstName') + ); + } + + private function getUserResultWithSomeAttrsHidden() { + return array( + 'key' => 'abc', + 'custom' => array('dizzle' => 'ghi'), + 'privateAttrs' => array('bizzle', 'firstName') + ); + } + + private function getUserResultWithOwnSpecifiedAttrHidden() { + return array( + 'key' => 'abc', + 'firstName' => 'Sue', + 'custom' => array('bizzle' => 'def'), + 'privateAttrs' => array('dizzle') + ); + } + + private function makeEvent($user) { + return array( + 'creationDate' => 1000000, + 'key' => 'abc', + 'kind' => 'thing', + 'user' => $user + ); + } + + private function getJsonForUserBySerializingEvent($user) { + $es = new EventSerializer(array()); + $event = $this->makeEvent($user); + return json_decode($es->serializeEvents(array($event)), true)[0]['user']; + } + + public function testAllUserAttrsSerialized() { + $es = new EventSerializer(array()); + $event = $this->makeEvent($this->getUser()); + $json = $es->serializeEvents(array($event)); + $expected = $this->makeEvent($this->getFullUserResult()); + $this->assertEquals(array($expected), json_decode($json, true)); + } + + public function testAllUserAttrsPrivate() { + $es = new EventSerializer(array('allAttrsPrivate' => true)); + $event = $this->makeEvent($this->getUser()); + $json = $es->serializeEvents(array($event)); + $expected = $this->makeEvent($this->getUserResultWithAllAttrsHidden()); + $this->assertEquals(array($expected), json_decode($json, true)); + } + + public function testSomeUserAttrsPrivate() { + $es = new EventSerializer(array('privateAttrNames' => array('firstName', 'bizzle'))); + $event = $this->makeEvent($this->getUser()); + $json = $es->serializeEvents(array($event)); + $expected = $this->makeEvent($this->getUserResultWithSomeAttrsHidden()); + $this->assertEquals(array($expected), json_decode($json, true)); + } + + public function testPerUserPrivateAttr() { + $es = new EventSerializer(array()); + $event = $this->makeEvent($this->getUserSpecifyingOwnPrivateAttr()); + $json = $es->serializeEvents(array($event)); + $expected = $this->makeEvent($this->getUserResultWithOwnSpecifiedAttrHidden()); + $this->assertEquals(array($expected), json_decode($json, true)); + } + + public function testPerUserPrivateAttrPlusGlobalPrivateAttrs() { + $es = new EventSerializer(array('privateAttrNames' => array('firstName', 'bizzle'))); + $event = $this->makeEvent($this->getUserSpecifyingOwnPrivateAttr()); + $json = $es->serializeEvents(array($event)); + $expected = $this->makeEvent($this->getUserResultWithAllAttrsHidden()); + $this->assertEquals(array($expected), json_decode($json, true)); + } + + public function testUserKey() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("foo@bar.com", $json['key']); + } + + public function testEmptyCustom() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertFalse(isset($json['custom'])); + } + + public function testUserSecondary() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->secondary("secondary")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("secondary", $json['secondary']); + } + + public function testLDUserIP() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->ip("127.0.0.1")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("127.0.0.1", $json['ip']); + } + + public function testLDUserCountry() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->country("US")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("US", $json['country']); + } + + public function testLDUserEmail() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->email("foo+test@bar.com")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("foo+test@bar.com", $json['email']); + } + + public function testLDUserName() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->name("Foo Bar")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("Foo Bar", $json['name']); + } + + public function testLDUserAvatar() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->avatar("http://www.gravatar.com/avatar/1")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("http://www.gravatar.com/avatar/1", $json['avatar']); + } + + public function testLDUserFirstName() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->firstName("Foo")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("Foo", $json['firstName']); + } + + public function testLDUserLastName() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->lastName("Bar")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals("Bar", $json['lastName']); + } + + public function testLDUserAnonymous() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->anonymous(true)->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertEquals(true, $json['anonymous']); + } +} + diff --git a/tests/LDUserTest.php b/tests/LDUserTest.php index 0dfbb0d01..9253ad415 100644 --- a/tests/LDUserTest.php +++ b/tests/LDUserTest.php @@ -9,96 +9,71 @@ public function testLDUserKey() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->build(); $this->assertEquals("foo@bar.com", $user->getKey()); - $json = $user->toJSON(); - $this->assertEquals("foo@bar.com", $json['key']); } public function testCoerceLDUserKey() { $builder = new LDUserBuilder(3); $user = $builder->build(); $this->assertEquals("string", gettype($user->getKey())); - $json = $user->toJSON(); - $this->assertEquals("string", gettype($json['key'])); } public function testEmptyCustom() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->build(); - $json = $user->toJSON(); - $this->assertTrue(!isset($json['custom'])); } public function testLDUserSecondary() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->secondary("secondary")->build(); $this->assertEquals("secondary", $user->getSecondary()); - $json = $user->toJSON(); - $this->assertEquals("secondary", $json['secondary']); } public function testLDUserIP() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->ip("127.0.0.1")->build(); $this->assertEquals("127.0.0.1", $user->getIP()); - $json = $user->toJSON(); - $this->assertEquals("127.0.0.1", $json['ip']); } public function testLDUserCountry() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->country("US")->build(); $this->assertEquals("US", $user->getCountry()); - $json = $user->toJSON(); - $this->assertEquals("US", $json['country']); } public function testLDUserEmail() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->email("foo+test@bar.com")->build(); $this->assertEquals("foo+test@bar.com", $user->getEmail()); - $json = $user->toJSON(); - $this->assertEquals("foo+test@bar.com", $json['email']); } public function testLDUserName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->name("Foo Bar")->build(); $this->assertEquals("Foo Bar", $user->getName()); - $json = $user->toJSON(); - $this->assertEquals("Foo Bar", $json['name']); } public function testLDUserAvatar() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->avatar("http://www.gravatar.com/avatar/1")->build(); $this->assertEquals("http://www.gravatar.com/avatar/1", $user->getAvatar()); - $json = $user->toJSON(); - $this->assertEquals("http://www.gravatar.com/avatar/1", $json['avatar']); } public function testLDUserFirstName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->firstName("Foo")->build(); $this->assertEquals("Foo", $user->getFirstName()); - $json = $user->toJSON(); - $this->assertEquals("Foo", $json['firstName']); } public function testLDUserLastName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->lastName("Bar")->build(); $this->assertEquals("Bar", $user->getLastName()); - $json = $user->toJSON(); - $this->assertEquals("Bar", $json['lastName']); } public function testLDUserAnonymous() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->anonymous(true)->build(); $this->assertEquals(true, $user->getAnonymous()); - $json = $user->toJSON(); - $this->assertEquals(true, $json['anonymous']); - } public function testLDUserBlankKey() { @@ -116,4 +91,3 @@ public function testLDUserBlankKey() { $this->assertFalse($user->isKeyBlank()); } } - From 7e954063c6d1d552d404f8b1cb7e81d3595487ae Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 13 Oct 2017 14:25:53 -0700 Subject: [PATCH 05/30] oh what the heck, let's write pure functions even in PHP --- src/LaunchDarkly/EventSerializer.php | 30 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/LaunchDarkly/EventSerializer.php b/src/LaunchDarkly/EventSerializer.php index d980417d1..d32d8ebb5 100644 --- a/src/LaunchDarkly/EventSerializer.php +++ b/src/LaunchDarkly/EventSerializer.php @@ -35,16 +35,10 @@ private function filterEvent($e) { return $ret; } - private function isPrivateAttr($name, $userPrivateAttrs, &$allPrivateAttrs) { - if ($this->_allAttrsPrivate || + private function isPrivateAttr($name, $userPrivateAttrs) { + return ($this->_allAttrsPrivate || array_search($name, $userPrivateAttrs) !== FALSE || - array_search($name, $this->_privateAttrNames) !== FALSE) { - $allPrivateAttrs[$name] = $name; - return true; - } - else { - return false; - } + array_search($name, $this->_privateAttrNames) !== FALSE); } private function serializeUser($user) { @@ -64,15 +58,25 @@ private function serializeUser($user) { 'anonymous' => $user->getAnonymous() ); foreach ($attrs as $key => $value) { - if ($value != null && !$this->isPrivateAttr($key, $userPrivateAttrs, $allPrivateAttrs)) { - $json[$key] = $value; + if ($value != null) { + if ($this->isPrivateAttr($key, $userPrivateAttrs)) { + $allPrivateAttrs[$key] = $key; + } + else { + $json[$key] = $value; + } } } if (!empty($user->getCustom())) { $customs = array(); foreach ($user->getCustom() as $key => $value) { - if ($value != null && !$this->isPrivateAttr($key, $userPrivateAttrs, $allPrivateAttrs)) { - $customs[$key] = $value; + if ($value != null) { + if ($this->isPrivateAttr($key, $userPrivateAttrs)) { + $allPrivateAttrs[$key] = $key; + } + else { + $customs[$key] = $value; + } } } $json['custom'] = $customs; From 99261222c64d57bb1e52d42ce4a69c2df7054bbe Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 13 Oct 2017 14:30:01 -0700 Subject: [PATCH 06/30] consistent test names --- tests/EventSerializerTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/EventSerializerTest.php b/tests/EventSerializerTest.php index 70662922f..b7f7436e1 100644 --- a/tests/EventSerializerTest.php +++ b/tests/EventSerializerTest.php @@ -128,56 +128,56 @@ public function testUserSecondary() { $this->assertEquals("secondary", $json['secondary']); } - public function testLDUserIP() { + public function testUserIP() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->ip("127.0.0.1")->build(); $json = $this->getJsonForUserBySerializingEvent($user); $this->assertEquals("127.0.0.1", $json['ip']); } - public function testLDUserCountry() { + public function testUserCountry() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->country("US")->build(); $json = $this->getJsonForUserBySerializingEvent($user); $this->assertEquals("US", $json['country']); } - public function testLDUserEmail() { + public function testUserEmail() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->email("foo+test@bar.com")->build(); $json = $this->getJsonForUserBySerializingEvent($user); $this->assertEquals("foo+test@bar.com", $json['email']); } - public function testLDUserName() { + public function testUserName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->name("Foo Bar")->build(); $json = $this->getJsonForUserBySerializingEvent($user); $this->assertEquals("Foo Bar", $json['name']); } - public function testLDUserAvatar() { + public function testUserAvatar() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->avatar("http://www.gravatar.com/avatar/1")->build(); $json = $this->getJsonForUserBySerializingEvent($user); $this->assertEquals("http://www.gravatar.com/avatar/1", $json['avatar']); } - public function testLDUserFirstName() { + public function testUserFirstName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->firstName("Foo")->build(); $json = $this->getJsonForUserBySerializingEvent($user); $this->assertEquals("Foo", $json['firstName']); } - public function testLDUserLastName() { + public function testUserLastName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->lastName("Bar")->build(); $json = $this->getJsonForUserBySerializingEvent($user); $this->assertEquals("Bar", $json['lastName']); } - public function testLDUserAnonymous() { + public function testUserAnonymous() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->anonymous(true)->build(); $json = $this->getJsonForUserBySerializingEvent($user); From 51a6af1d51595a1e9b03127bc38b4ad956ed6b5b Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Wed, 18 Oct 2017 14:39:30 -0700 Subject: [PATCH 07/30] revise private user info naming conventions & methods to match Java SDK --- src/LaunchDarkly/EventSerializer.php | 6 +-- src/LaunchDarkly/LDUser.php | 10 ++--- src/LaunchDarkly/LDUserBuilder.php | 55 +++++++++++++++++++++++++--- tests/EventSerializerTest.php | 16 ++++---- 4 files changed, 67 insertions(+), 20 deletions(-) diff --git a/src/LaunchDarkly/EventSerializer.php b/src/LaunchDarkly/EventSerializer.php index d32d8ebb5..add0d1bb8 100644 --- a/src/LaunchDarkly/EventSerializer.php +++ b/src/LaunchDarkly/EventSerializer.php @@ -10,8 +10,8 @@ class EventSerializer { private $_privateAttrNames; public function __construct($options) { - $this->_allAttrsPrivate = isset($options['allAttrsPrivate']) && $options['allAttrsPrivate']; - $this->_privateAttrNames = isset($options['privateAttrNames']) ? $options['privateAttrNames'] : array(); + $this->_allAttrsPrivate = isset($options['allAttributesPrivate']) && $options['allAttributesPrivate']; + $this->_privateAttrNames = isset($options['privateAttributeNames']) ? $options['privateAttributeNames'] : array(); } public function serializeEvents($events) { @@ -43,7 +43,7 @@ private function isPrivateAttr($name, $userPrivateAttrs) { private function serializeUser($user) { $json = array("key" => $user->getKey()); - $userPrivateAttrs = $user->getPrivateAttrs(); + $userPrivateAttrs = $user->getPrivateAttributeNames(); $allPrivateAttrs = array(); $attrs = array( diff --git a/src/LaunchDarkly/LDUser.php b/src/LaunchDarkly/LDUser.php index b309c6d3c..fdd4d110e 100644 --- a/src/LaunchDarkly/LDUser.php +++ b/src/LaunchDarkly/LDUser.php @@ -18,7 +18,7 @@ class LDUser { protected $_lastName = null; protected $_anonyomus = false; protected $_custom = array(); - protected $_privateAttrs = array(); + protected $_privateAttributeNames = array(); /** * @param string $key Unique key for the user. For authenticated users, this may be a username or e-mail address. For anonymous users, this could be an IP address or session ID. @@ -34,7 +34,7 @@ class LDUser { * @param array|null $custom Other custom attributes that can be used to create custom rules */ public function __construct($key, $secondary = null, $ip = null, $country = null, $email = null, $name = null, $avatar = null, $firstName = null, $lastName = null, $anonymous = null, $custom = array(), - $privateAttrs = array()) { + $privateAttributeNames = array()) { if ($key !== null) { $this->_key = strval($key); } @@ -48,7 +48,7 @@ public function __construct($key, $secondary = null, $ip = null, $country = null $this->_lastName = $lastName; $this->_anonymous = $anonymous; $this->_custom = $custom; - $this->_privateAttrs = $privateAttrs; + $this->_privateAttributeNames = $privateAttributeNames; } public function getValueForEvaluation($attr) { @@ -132,8 +132,8 @@ public function getAnonymous() { return $this->_anonymous; } - public function getPrivateAttrs() { - return $this->_privateAttrs; + public function getPrivateAttributeNames() { + return $this->_privateAttributeNames; } public function isKeyBlank() { diff --git a/src/LaunchDarkly/LDUserBuilder.php b/src/LaunchDarkly/LDUserBuilder.php index 9065432e7..58843aefe 100644 --- a/src/LaunchDarkly/LDUserBuilder.php +++ b/src/LaunchDarkly/LDUserBuilder.php @@ -13,7 +13,7 @@ class LDUserBuilder { protected $_lastName = null; protected $_anonymous = null; protected $_custom = array(); - protected $_privateAttrs = array(); + protected $_privateAttributeNames = array(); public function __construct($key) { $this->_key = $key; @@ -24,41 +24,81 @@ public function secondary($secondary) { return $this; } + public function privateSecondary($seondary) { + array_push($this->_privateAttributeNames, 'secondary'); + return $this->secondary($secondary); + } + public function ip($ip) { $this->_ip = $ip; return $this; } + public function privateIp($ip) { + array_push($this->_privateAttributeNames, 'ip'); + return $this->ip($ip); + } + public function country($country) { $this->_country = $country; return $this; } + public function privateCountry($country) { + array_push($this->_privateAttributeNames, 'country'); + return $this->country($country); + } + public function email($email) { $this->_email = $email; return $this; } + public function privateEmail($email) { + array_push($this->_privateAttributeNames, 'email'); + return $this->email($email); + } + public function name($name) { $this->_name = $name; return $this; } + public function privateName($name) { + array_push($this->_privateAttributeNames, 'name'); + return $this->name($name); + } + public function avatar($avatar) { $this->_avatar = $avatar; return $this; } + public function privateAvatar($avatar) { + array_push($this->_privateAttributeNames, 'avatar'); + return $this->avatar($avatar); + } + public function firstName($firstName) { $this->_firstName = $firstName; return $this; } + public function privateFirstName($firstName) { + array_push($this->_privateAttributeNames, 'firstName'); + return $this->firstName($firstName); + } + public function lastName($lastName) { $this->_lastName = $lastName; return $this; } + public function privateLastName($lastName) { + array_push($this->_privateAttributeNames, 'lastName'); + return $this->lastName($lastName); + } + public function anonymous($anonymous) { $this->_anonymous = $anonymous; return $this; @@ -69,13 +109,18 @@ public function custom($custom) { return $this; } - public function privateAttrs($privateAttrs) { - $this->_privateAttrs = $privateAttrs; + public function customAttribute($customKey, $customValue) { + $this->_custom[$customKey] = $customValue; return $this; } - + + public function privateCustomAttribute($customKey, $customValue) { + array_push($this->_privateAttributeNames, $customKey); + return $this->customAttribute($customKey, $customValue); + } + public function build() { - return new LDUser($this->_key, $this->_secondary, $this->_ip, $this->_country, $this->_email, $this->_name, $this->_avatar, $this->_firstName, $this->_lastName, $this->_anonymous, $this->_custom, $this->_privateAttrs); + return new LDUser($this->_key, $this->_secondary, $this->_ip, $this->_country, $this->_email, $this->_name, $this->_avatar, $this->_firstName, $this->_lastName, $this->_anonymous, $this->_custom, $this->_privateAttributeNames); } } \ No newline at end of file diff --git a/tests/EventSerializerTest.php b/tests/EventSerializerTest.php index b7f7436e1..59b4d93c2 100644 --- a/tests/EventSerializerTest.php +++ b/tests/EventSerializerTest.php @@ -7,15 +7,17 @@ class EventSerializerTest extends \PHPUnit_Framework_TestCase { private function getUser() { - return (new LDUserBuilder('abc'))->firstName('Sue') + return (new LDUserBuilder('abc')) + ->firstName('Sue') ->custom(array('bizzle' => 'def', 'dizzle' => 'ghi')) ->build(); } private function getUserSpecifyingOwnPrivateAttr() { - return (new LDUserBuilder('abc'))->firstName('Sue') - ->custom(array('bizzle' => 'def', 'dizzle' => 'ghi')) - ->privateAttrs(array('dizzle', 'unused')) + return (new LDUserBuilder('abc')) + ->firstName('Sue') + ->customAttribute('bizzle', 'def') + ->privateCustomAttribute('dizzle', 'ghi') ->build(); } @@ -76,7 +78,7 @@ public function testAllUserAttrsSerialized() { } public function testAllUserAttrsPrivate() { - $es = new EventSerializer(array('allAttrsPrivate' => true)); + $es = new EventSerializer(array('allAttributesPrivate' => true)); $event = $this->makeEvent($this->getUser()); $json = $es->serializeEvents(array($event)); $expected = $this->makeEvent($this->getUserResultWithAllAttrsHidden()); @@ -84,7 +86,7 @@ public function testAllUserAttrsPrivate() { } public function testSomeUserAttrsPrivate() { - $es = new EventSerializer(array('privateAttrNames' => array('firstName', 'bizzle'))); + $es = new EventSerializer(array('privateAttributeNames' => array('firstName', 'bizzle'))); $event = $this->makeEvent($this->getUser()); $json = $es->serializeEvents(array($event)); $expected = $this->makeEvent($this->getUserResultWithSomeAttrsHidden()); @@ -100,7 +102,7 @@ public function testPerUserPrivateAttr() { } public function testPerUserPrivateAttrPlusGlobalPrivateAttrs() { - $es = new EventSerializer(array('privateAttrNames' => array('firstName', 'bizzle'))); + $es = new EventSerializer(array('privateAttributeNames' => array('firstName', 'bizzle'))); $event = $this->makeEvent($this->getUserSpecifyingOwnPrivateAttr()); $json = $es->serializeEvents(array($event)); $expected = $this->makeEvent($this->getUserResultWithAllAttrsHidden()); From 0bac87ff1cb2d94b1202b5e1696185684d9ae4b9 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Wed, 18 Oct 2017 16:13:44 -0700 Subject: [PATCH 08/30] typo --- src/LaunchDarkly/LDUserBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LaunchDarkly/LDUserBuilder.php b/src/LaunchDarkly/LDUserBuilder.php index 58843aefe..ad91ec7d0 100644 --- a/src/LaunchDarkly/LDUserBuilder.php +++ b/src/LaunchDarkly/LDUserBuilder.php @@ -24,7 +24,7 @@ public function secondary($secondary) { return $this; } - public function privateSecondary($seondary) { + public function privateSecondary($secondary) { array_push($this->_privateAttributeNames, 'secondary'); return $this->secondary($secondary); } From 7475d87995b785416617f8266eb11087b34a6f2c Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Wed, 18 Oct 2017 16:13:50 -0700 Subject: [PATCH 09/30] unit tests for user builder --- tests/LDUserTest.php | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tests/LDUserTest.php b/tests/LDUserTest.php index 9253ad415..fd8a635dc 100644 --- a/tests/LDUserTest.php +++ b/tests/LDUserTest.php @@ -28,48 +28,117 @@ public function testLDUserSecondary() { $this->assertEquals("secondary", $user->getSecondary()); } + public function testLDUserPrivateSecondary() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateSecondary("secondary")->build(); + $this->assertEquals("secondary", $user->getSecondary()); + $this->assertEquals(array("secondary"), $user->getPrivateAttributeNames()); + } + public function testLDUserIP() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->ip("127.0.0.1")->build(); $this->assertEquals("127.0.0.1", $user->getIP()); } + public function testLDUserPrivateIP() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateIp("127.0.0.1")->build(); + $this->assertEquals("127.0.0.1", $user->getIP()); + $this->assertEquals(array("ip"), $user->getPrivateAttributeNames()); + } + public function testLDUserCountry() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->country("US")->build(); $this->assertEquals("US", $user->getCountry()); } + public function testLDUserPrivateCountry() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateCountry("US")->build(); + $this->assertEquals("US", $user->getCountry()); + $this->assertEquals(array("country"), $user->getPrivateAttributeNames()); + } + public function testLDUserEmail() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->email("foo+test@bar.com")->build(); $this->assertEquals("foo+test@bar.com", $user->getEmail()); } + public function testLDUserPrivateEmail() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateEmail("foo+test@bar.com")->build(); + $this->assertEquals("foo+test@bar.com", $user->getEmail()); + $this->assertEquals(array("email"), $user->getPrivateAttributeNames()); + } + public function testLDUserName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->name("Foo Bar")->build(); $this->assertEquals("Foo Bar", $user->getName()); } + public function testLDUserPrivateName() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateName("Foo Bar")->build(); + $this->assertEquals("Foo Bar", $user->getName()); + $this->assertEquals(array("name"), $user->getPrivateAttributeNames()); + } + public function testLDUserAvatar() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->avatar("http://www.gravatar.com/avatar/1")->build(); $this->assertEquals("http://www.gravatar.com/avatar/1", $user->getAvatar()); } + public function testLDUserPrivateAvatar() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateAvatar("http://www.gravatar.com/avatar/1")->build(); + $this->assertEquals("http://www.gravatar.com/avatar/1", $user->getAvatar()); + $this->assertEquals(array("avatar"), $user->getPrivateAttributeNames()); + } + public function testLDUserFirstName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->firstName("Foo")->build(); $this->assertEquals("Foo", $user->getFirstName()); } + public function testLDUserPrivateFirstName() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateFirstName("Foo")->build(); + $this->assertEquals("Foo", $user->getFirstName()); + $this->assertEquals(array("firstName"), $user->getPrivateAttributeNames()); + } + public function testLDUserLastName() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->lastName("Bar")->build(); $this->assertEquals("Bar", $user->getLastName()); } + public function testLDUserPrivateLastName() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateLastName("Bar")->build(); + $this->assertEquals("Bar", $user->getLastName()); + $this->assertEquals(array("lastName"), $user->getPrivateAttributeNames()); + } + + public function testLDUserCustom() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->customAttribute("foo", "bar")->customAttribute("baz", "boo")->build(); + $this->assertEquals(array("foo" => "bar", "baz" => "boo"), $user->getCustom()); + } + + public function testLDUserPrivateCustom() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateCustomAttribute("foo", "bar")->privateCustomAttribute("baz", "boo")->build(); + $this->assertEquals(array("foo" => "bar", "baz" => "boo"), $user->getCustom()); + $this->assertEquals(array("foo", "baz"), $user->getPrivateAttributeNames()); + } + public function testLDUserAnonymous() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->anonymous(true)->build(); From 913146e7bfa626879cfb52c31221a0ca8ac9de94 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Wed, 18 Oct 2017 16:19:15 -0700 Subject: [PATCH 10/30] factor out common logic --- src/LaunchDarkly/EventSerializer.php | 39 +++++++++++----------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/src/LaunchDarkly/EventSerializer.php b/src/LaunchDarkly/EventSerializer.php index add0d1bb8..5b7d40e6e 100644 --- a/src/LaunchDarkly/EventSerializer.php +++ b/src/LaunchDarkly/EventSerializer.php @@ -35,10 +35,19 @@ private function filterEvent($e) { return $ret; } - private function isPrivateAttr($name, $userPrivateAttrs) { - return ($this->_allAttrsPrivate || - array_search($name, $userPrivateAttrs) !== FALSE || - array_search($name, $this->_privateAttrNames) !== FALSE); + private function filterAttrs($attrs, &$json, $userPrivateAttrs, &$allPrivateAttrs) { + foreach ($attrs as $key => $value) { + if ($value != null) { + if ($this->_allAttrsPrivate || + array_search($key, $userPrivateAttrs) !== FALSE || + array_search($key, $this->_privateAttrNames) !== FALSE) { + $allPrivateAttrs[$key] = true; + } + else { + $json[$key] = $value; + } + } + } } private function serializeUser($user) { @@ -57,28 +66,10 @@ private function serializeUser($user) { 'lastName' => $user->getLastName(), 'anonymous' => $user->getAnonymous() ); - foreach ($attrs as $key => $value) { - if ($value != null) { - if ($this->isPrivateAttr($key, $userPrivateAttrs)) { - $allPrivateAttrs[$key] = $key; - } - else { - $json[$key] = $value; - } - } - } + $this->filterAttrs($attrs, $json, $userPrivateAttrs, $allPrivateAttrs); if (!empty($user->getCustom())) { $customs = array(); - foreach ($user->getCustom() as $key => $value) { - if ($value != null) { - if ($this->isPrivateAttr($key, $userPrivateAttrs)) { - $allPrivateAttrs[$key] = $key; - } - else { - $customs[$key] = $value; - } - } - } + $this->filterAttrs($user->getCustom(), $customs, $userPrivateAttrs, $allPrivateAttrs); $json['custom'] = $customs; } if (count($allPrivateAttrs)) { From 2cfebd25f80bf467c7a4073053d1aa7c886e993c Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 20 Oct 2017 13:38:29 -0700 Subject: [PATCH 11/30] stop trying to do HTTP after we get a 401 --- src/LaunchDarkly/EventProcessor.php | 14 ++++++++++++-- src/LaunchDarkly/EventPublisher.php | 6 +++++- src/LaunchDarkly/GuzzleEventPublisher.php | 7 +++++-- src/LaunchDarkly/GuzzleFeatureRequester.php | 21 ++++++++++++++++++--- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/LaunchDarkly/EventProcessor.php b/src/LaunchDarkly/EventProcessor.php index f408ac635..726ccac5d 100644 --- a/src/LaunchDarkly/EventProcessor.php +++ b/src/LaunchDarkly/EventProcessor.php @@ -10,12 +10,15 @@ class EventProcessor { private $_queue; private $_capacity; private $_timeout; + private $_logger; + private $_stopped = FALSE; public function __construct($sdkKey, $options = array()) { $this->_eventPublisher = $this->getEventPublisher($sdkKey, $options); $this->_capacity = $options['capacity']; $this->_timeout = $options['timeout']; + $this->_logger = $options['logger']; $this->_queue = array(); } @@ -43,13 +46,20 @@ public function enqueue($event) { * @return bool Whether the events were successfully published */ public function flush() { - if (empty($this->_queue)) { + if ($this->_stopped || empty($this->_queue)) { return null; } $payload = json_encode($this->_queue); - return $this->_eventPublisher->publish($payload); + $this->queue = array(); + + try { + $this->_eventPublisher->publish($payload); + } catch (InvalidSDKException $e) { + $this->_logger->error("Received 401 error, no further events will be posted during lifetime of LD client since SDK key is invalid"); + $this->_stopped = TRUE; + } } /** diff --git a/src/LaunchDarkly/EventPublisher.php b/src/LaunchDarkly/EventPublisher.php index 0b21d6fb7..da3980b7c 100644 --- a/src/LaunchDarkly/EventPublisher.php +++ b/src/LaunchDarkly/EventPublisher.php @@ -18,4 +18,8 @@ public function __construct($sdkKey, array $options); * @return bool Whether the events were successfully published */ public function publish($payload); -} \ No newline at end of file +} + +class InvalidSDKKeyException extends \Exception +{ +} diff --git a/src/LaunchDarkly/GuzzleEventPublisher.php b/src/LaunchDarkly/GuzzleEventPublisher.php index 27c728110..12b1431d8 100644 --- a/src/LaunchDarkly/GuzzleEventPublisher.php +++ b/src/LaunchDarkly/GuzzleEventPublisher.php @@ -47,16 +47,19 @@ function __construct($sdkKey, array $options = array()) { public function publish($payload) { $client = new Client(['base_uri' => $this->_eventsUri]); + $response = null; try { $options = $this->_requestOptions; $options['body'] = $payload; $response = $client->request('POST', '/bulk', $options); - - return $response->getStatusCode() < 300; } catch (\Exception $e) { $this->_logger->warning("GuzzleEventPublisher::publish caught $e"); return false; } + if ($response && ($response->getStatusCode() == 401)) { + throw new InvalidSDKKeyException(); + } + return $response && ($response->getStatusCode() < 300); } } \ No newline at end of file diff --git a/src/LaunchDarkly/GuzzleFeatureRequester.php b/src/LaunchDarkly/GuzzleFeatureRequester.php index af3e006df..fb301c9c1 100644 --- a/src/LaunchDarkly/GuzzleFeatureRequester.php +++ b/src/LaunchDarkly/GuzzleFeatureRequester.php @@ -21,6 +21,8 @@ class GuzzleFeatureRequester implements FeatureRequester private $_logger; /** @var boolean */ private $_loggedCacheNotice = FALSE; + /** @var boolean */ + private $_stopped = FALSE; function __construct($baseUri, $sdkKey, $options) { @@ -55,6 +57,9 @@ function __construct($baseUri, $sdkKey, $options) */ public function get($key) { + if ($this->_stopped) { + return null; + } try { $uri = $this->_baseUri . self::SDK_FLAGS . "/" . $key; $response = $this->_client->get($uri, $this->_defaults); @@ -65,7 +70,7 @@ public function get($key) if ($code == 404) { $this->_logger->warning("GuzzleFeatureRequester::get returned 404. Feature flag does not exist for key: " . $key); } else { - $this->_logger->error("GuzzleFeatureRequester::get received an unexpected HTTP status code $code"); + $this->handleUnexpectedStatus($code, "GuzzleFeatureRequester::get"); } return null; } @@ -77,15 +82,25 @@ public function get($key) * @return array()|null The decoded FeatureFlags, or null if missing */ public function getAll() { + if ($this->_stopped) { + return null; + } try { $uri = $this->_baseUri . self::SDK_FLAGS; $response = $this->_client->get($uri, $this->_defaults); $body = $response->getBody(); return array_map(FeatureFlag::getDecoder(), json_decode($body, true)); } catch (BadResponseException $e) { - $code = $e->getResponse()->getStatusCode(); - $this->_logger->error("GuzzleFeatureRequester::getAll received an unexpected HTTP status code $code"); + $this->handleUnexpectedStatus($e->getResponse()->getStatusCode(), "GuzzleFeatureRequester::getAll"); return null; } } + + private function handleUnexpectedStatus($code, $method) { + $this->_logger->error("$method received an unexpected HTTP status code $code"); + if ($code == 401) { + $this->_logger->error("Received 401 error, no further feature requests will be made during lifetime of LD client since SDK key is invalid"); + $this->stopped = TRUE; + } + } } \ No newline at end of file From 29ad4618c96576c8baaafe6cb934b03af7e967f7 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 20 Oct 2017 14:47:16 -0700 Subject: [PATCH 12/30] better implementation - put entire client offline the first time we see a 401 --- src/LaunchDarkly/CurlEventPublisher.php | 13 +++++--- src/LaunchDarkly/EventProcessor.php | 10 ++---- src/LaunchDarkly/EventPublisher.php | 4 --- src/LaunchDarkly/GuzzleFeatureRequester.php | 11 +------ src/LaunchDarkly/LDClient.php | 35 +++++++++++++++++++-- 5 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/LaunchDarkly/CurlEventPublisher.php b/src/LaunchDarkly/CurlEventPublisher.php index 96131ed55..b19e91e93 100644 --- a/src/LaunchDarkly/CurlEventPublisher.php +++ b/src/LaunchDarkly/CurlEventPublisher.php @@ -55,7 +55,7 @@ public function publish($payload) { private function createArgs($payload) { $scheme = $this->_ssl ? "https://" : "http://"; - $args = " -X POST"; + $args = " -s -i -X POST"; $args.= " -H 'Content-Type: application/json'"; $args.= " -H " . escapeshellarg("Authorization: " . $this->_sdkKey); $args.= " -H 'User-Agent: PHPClient/" . LDClient::VERSION . "'"; @@ -66,8 +66,13 @@ private function createArgs($payload) { } private function makeRequest($args) { - $cmd = $this->_curl . " " . $args . ">> /dev/null 2>&1 &"; - shell_exec($cmd); - return true; + $cmd = $this->_curl . " " . $args . " 2>&1"; + $output = shell_exec($cmd); + preg_match('#^HTTP/[^ ]* *([0-9]*)#', $output, $matches); + $status = intval($matches[1]); + if ($status == 401) { + throw new InvalidSDKKeyException(); + } + return ($status < 300); } } \ No newline at end of file diff --git a/src/LaunchDarkly/EventProcessor.php b/src/LaunchDarkly/EventProcessor.php index 726ccac5d..b144fa805 100644 --- a/src/LaunchDarkly/EventProcessor.php +++ b/src/LaunchDarkly/EventProcessor.php @@ -11,7 +11,6 @@ class EventProcessor { private $_capacity; private $_timeout; private $_logger; - private $_stopped = FALSE; public function __construct($sdkKey, $options = array()) { $this->_eventPublisher = $this->getEventPublisher($sdkKey, $options); @@ -46,7 +45,7 @@ public function enqueue($event) { * @return bool Whether the events were successfully published */ public function flush() { - if ($this->_stopped || empty($this->_queue)) { + if (empty($this->_queue)) { return null; } @@ -54,12 +53,7 @@ public function flush() { $this->queue = array(); - try { - $this->_eventPublisher->publish($payload); - } catch (InvalidSDKException $e) { - $this->_logger->error("Received 401 error, no further events will be posted during lifetime of LD client since SDK key is invalid"); - $this->_stopped = TRUE; - } + $this->_eventPublisher->publish($payload); } /** diff --git a/src/LaunchDarkly/EventPublisher.php b/src/LaunchDarkly/EventPublisher.php index da3980b7c..bfcc27764 100644 --- a/src/LaunchDarkly/EventPublisher.php +++ b/src/LaunchDarkly/EventPublisher.php @@ -19,7 +19,3 @@ public function __construct($sdkKey, array $options); */ public function publish($payload); } - -class InvalidSDKKeyException extends \Exception -{ -} diff --git a/src/LaunchDarkly/GuzzleFeatureRequester.php b/src/LaunchDarkly/GuzzleFeatureRequester.php index fb301c9c1..0c913fff0 100644 --- a/src/LaunchDarkly/GuzzleFeatureRequester.php +++ b/src/LaunchDarkly/GuzzleFeatureRequester.php @@ -21,8 +21,6 @@ class GuzzleFeatureRequester implements FeatureRequester private $_logger; /** @var boolean */ private $_loggedCacheNotice = FALSE; - /** @var boolean */ - private $_stopped = FALSE; function __construct($baseUri, $sdkKey, $options) { @@ -57,9 +55,6 @@ function __construct($baseUri, $sdkKey, $options) */ public function get($key) { - if ($this->_stopped) { - return null; - } try { $uri = $this->_baseUri . self::SDK_FLAGS . "/" . $key; $response = $this->_client->get($uri, $this->_defaults); @@ -82,9 +77,6 @@ public function get($key) * @return array()|null The decoded FeatureFlags, or null if missing */ public function getAll() { - if ($this->_stopped) { - return null; - } try { $uri = $this->_baseUri . self::SDK_FLAGS; $response = $this->_client->get($uri, $this->_defaults); @@ -99,8 +91,7 @@ public function getAll() { private function handleUnexpectedStatus($code, $method) { $this->_logger->error("$method received an unexpected HTTP status code $code"); if ($code == 401) { - $this->_logger->error("Received 401 error, no further feature requests will be made during lifetime of LD client since SDK key is invalid"); - $this->stopped = TRUE; + throw new InvalidSDKKeyException(); } } } \ No newline at end of file diff --git a/src/LaunchDarkly/LDClient.php b/src/LaunchDarkly/LDClient.php index 64d007b52..53b0323ec 100644 --- a/src/LaunchDarkly/LDClient.php +++ b/src/LaunchDarkly/LDClient.php @@ -5,6 +5,13 @@ use Monolog\Logger; use Psr\Log\LoggerInterface; +/** + * Used internally. + */ +class InvalidSDKKeyException extends \Exception +{ +} + /** * A client for the LaunchDarkly API. */ @@ -144,7 +151,12 @@ public function variation($key, $user, $default = false) { if ($user->isKeyBlank()) { $this->_logger->warning("User key is blank. Flag evaluation will proceed, but the user will not be stored in LaunchDarkly."); } - $flag = $this->_featureRequester->get($key); + try { + $flag = $this->_featureRequester->get($key); + } catch (InvalidSDKKeyException $e) { + $this->handleInvalidSDKKey(); + return $default; + } if (is_null($flag)) { $this->_sendFlagRequestEvent($key, $user, $default, $default); @@ -252,7 +264,15 @@ public function allFlags($user) { $this->_logger->warn("allFlags called with null user or null/empty user key! Returning null"); return null; } - $flags = $this->_featureRequester->getAll(); + if ($this->isOffline()) { + return null; + } + try { + $flags = $this->_featureRequester->getAll(); + } catch (InvalidSDKKeyException $e) { + $this->handleInvalidSDKKey(); + return null; + } if ($flags === null) { return null; } @@ -285,7 +305,11 @@ public function secureModeHash($user) { */ public function flush() { - return $this->_eventProcessor->flush(); + try { + return $this->_eventProcessor->flush(); + } catch (InvalidSDKKeyException $e) { + $this->handleInvalidSDKKey()); + } } /** @@ -310,4 +334,9 @@ protected function _get_default($key, $default) { return $default; } } + + protected function handleInvalidSDKKey() { + $this->_logger->error("Received 401 error, no further HTTP requests will be made during lifetime of LDClient since SDK key is invalid"); + $this->_offline = true; + } } From 86b452414e2830ad4609217bec436b0b63a24f1c Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 20 Oct 2017 14:54:52 -0700 Subject: [PATCH 13/30] revert unneeded changes --- src/LaunchDarkly/EventProcessor.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/LaunchDarkly/EventProcessor.php b/src/LaunchDarkly/EventProcessor.php index b144fa805..f408ac635 100644 --- a/src/LaunchDarkly/EventProcessor.php +++ b/src/LaunchDarkly/EventProcessor.php @@ -10,14 +10,12 @@ class EventProcessor { private $_queue; private $_capacity; private $_timeout; - private $_logger; public function __construct($sdkKey, $options = array()) { $this->_eventPublisher = $this->getEventPublisher($sdkKey, $options); $this->_capacity = $options['capacity']; $this->_timeout = $options['timeout']; - $this->_logger = $options['logger']; $this->_queue = array(); } @@ -51,9 +49,7 @@ public function flush() { $payload = json_encode($this->_queue); - $this->queue = array(); - - $this->_eventPublisher->publish($payload); + return $this->_eventPublisher->publish($payload); } /** From 02f4cefef32566e0928ed8c8a072cc313980b5c0 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 20 Oct 2017 14:57:10 -0700 Subject: [PATCH 14/30] revert CurlEventPublisher changes - see PR comments --- src/LaunchDarkly/CurlEventPublisher.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/LaunchDarkly/CurlEventPublisher.php b/src/LaunchDarkly/CurlEventPublisher.php index b19e91e93..96131ed55 100644 --- a/src/LaunchDarkly/CurlEventPublisher.php +++ b/src/LaunchDarkly/CurlEventPublisher.php @@ -55,7 +55,7 @@ public function publish($payload) { private function createArgs($payload) { $scheme = $this->_ssl ? "https://" : "http://"; - $args = " -s -i -X POST"; + $args = " -X POST"; $args.= " -H 'Content-Type: application/json'"; $args.= " -H " . escapeshellarg("Authorization: " . $this->_sdkKey); $args.= " -H 'User-Agent: PHPClient/" . LDClient::VERSION . "'"; @@ -66,13 +66,8 @@ private function createArgs($payload) { } private function makeRequest($args) { - $cmd = $this->_curl . " " . $args . " 2>&1"; - $output = shell_exec($cmd); - preg_match('#^HTTP/[^ ]* *([0-9]*)#', $output, $matches); - $status = intval($matches[1]); - if ($status == 401) { - throw new InvalidSDKKeyException(); - } - return ($status < 300); + $cmd = $this->_curl . " " . $args . ">> /dev/null 2>&1 &"; + shell_exec($cmd); + return true; } } \ No newline at end of file From 15fd0efe552f399839380855cfbd6c4ae7923356 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 20 Oct 2017 17:42:33 -0700 Subject: [PATCH 15/30] typo --- src/LaunchDarkly/LDClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LaunchDarkly/LDClient.php b/src/LaunchDarkly/LDClient.php index 53b0323ec..464bed943 100644 --- a/src/LaunchDarkly/LDClient.php +++ b/src/LaunchDarkly/LDClient.php @@ -308,7 +308,7 @@ public function flush() try { return $this->_eventProcessor->flush(); } catch (InvalidSDKKeyException $e) { - $this->handleInvalidSDKKey()); + $this->handleInvalidSDKKey(); } } From a3b86caf0e92c2a47ad90f862c05ece8e2494e61 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Mon, 1 Jan 2018 12:36:33 -0800 Subject: [PATCH 16/30] use underscore naming convention for config options --- src/LaunchDarkly/EventSerializer.php | 4 ++-- tests/EventSerializerTest.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/LaunchDarkly/EventSerializer.php b/src/LaunchDarkly/EventSerializer.php index 5b7d40e6e..5dc083163 100644 --- a/src/LaunchDarkly/EventSerializer.php +++ b/src/LaunchDarkly/EventSerializer.php @@ -10,8 +10,8 @@ class EventSerializer { private $_privateAttrNames; public function __construct($options) { - $this->_allAttrsPrivate = isset($options['allAttributesPrivate']) && $options['allAttributesPrivate']; - $this->_privateAttrNames = isset($options['privateAttributeNames']) ? $options['privateAttributeNames'] : array(); + $this->_allAttrsPrivate = isset($options['all_attributes_private']) && $options['all_attributes_private']; + $this->_privateAttrNames = isset($options['private_attribute_names']) ? $options['private_attribute_names'] : array(); } public function serializeEvents($events) { diff --git a/tests/EventSerializerTest.php b/tests/EventSerializerTest.php index 59b4d93c2..432273bc0 100644 --- a/tests/EventSerializerTest.php +++ b/tests/EventSerializerTest.php @@ -78,7 +78,7 @@ public function testAllUserAttrsSerialized() { } public function testAllUserAttrsPrivate() { - $es = new EventSerializer(array('allAttributesPrivate' => true)); + $es = new EventSerializer(array('all_attributes_private' => true)); $event = $this->makeEvent($this->getUser()); $json = $es->serializeEvents(array($event)); $expected = $this->makeEvent($this->getUserResultWithAllAttrsHidden()); @@ -86,7 +86,7 @@ public function testAllUserAttrsPrivate() { } public function testSomeUserAttrsPrivate() { - $es = new EventSerializer(array('privateAttributeNames' => array('firstName', 'bizzle'))); + $es = new EventSerializer(array('private_attribute_names' => array('firstName', 'bizzle'))); $event = $this->makeEvent($this->getUser()); $json = $es->serializeEvents(array($event)); $expected = $this->makeEvent($this->getUserResultWithSomeAttrsHidden()); @@ -102,7 +102,7 @@ public function testPerUserPrivateAttr() { } public function testPerUserPrivateAttrPlusGlobalPrivateAttrs() { - $es = new EventSerializer(array('privateAttributeNames' => array('firstName', 'bizzle'))); + $es = new EventSerializer(array('private_attribute_names' => array('firstName', 'bizzle'))); $event = $this->makeEvent($this->getUserSpecifyingOwnPrivateAttr()); $json = $es->serializeEvents(array($event)); $expected = $this->makeEvent($this->getUserResultWithAllAttrsHidden()); From 90dfe937b810907b933b0a336a33389278c35e79 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Mon, 1 Jan 2018 12:50:24 -0800 Subject: [PATCH 17/30] document private attribute options (and all user builder setters) --- src/LaunchDarkly/LDClient.php | 2 + src/LaunchDarkly/LDUserBuilder.php | 71 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/LaunchDarkly/LDClient.php b/src/LaunchDarkly/LDClient.php index 1dc276398..cb45560e1 100644 --- a/src/LaunchDarkly/LDClient.php +++ b/src/LaunchDarkly/LDClient.php @@ -49,6 +49,8 @@ class LDClient { * - feature_requester_class: An optional class implementing LaunchDarkly\FeatureRequester, if `feature_requester` is not specified. Defaults to GuzzleFeatureRequester. * - event_publisher: An optional LaunchDarkly\EventPublisher instance. * - event_publisher_class: An optional class implementing LaunchDarkly\EventPublisher, if `event_publisher` is not specified. Defaults to CurlEventPublisher. + * - all_attributes_private: True if no user attributes (other than the key) should be sent back to LaunchDarkly. By default, this is false. + * - private_attribute_names: An optional array of user attribute names to be marked private. Any users sent to LaunchDarkly with this configuration active will have attributes with these names removed. You can also set private attributes on a per-user basis in LDUserBuilder. */ public function __construct($sdkKey, $options = array()) { $this->_sdkKey = $sdkKey; diff --git a/src/LaunchDarkly/LDUserBuilder.php b/src/LaunchDarkly/LDUserBuilder.php index ad91ec7d0..f08b523cb 100644 --- a/src/LaunchDarkly/LDUserBuilder.php +++ b/src/LaunchDarkly/LDUserBuilder.php @@ -1,6 +1,14 @@ builder that helps construct LDUser objects. + * + * Note that all user attributes, except for key and anonymous, can be designated as + * private so that they will not be sent back to LaunchDarkly. You can do this either on a per-user basis in + * LDUserBuilder, or globally via the private_attribute_names and all_attributes_private + * options in the client configuration. + */ class LDUserBuilder { protected $_key = null; protected $_secondary = null; @@ -15,6 +23,9 @@ class LDUserBuilder { protected $_custom = array(); protected $_privateAttributeNames = array(); + /** + * Creates a builder with the specified key. + */ public function __construct($key) { $this->_key = $key; } @@ -29,91 +40,151 @@ public function privateSecondary($secondary) { return $this->secondary($secondary); } + /** + * Sets the IP for a user. + */ public function ip($ip) { $this->_ip = $ip; return $this; } + /** + * Sets the IP for a user, and ensures that the IP attribute will not be sent back to LaunchDarkly. + */ public function privateIp($ip) { array_push($this->_privateAttributeNames, 'ip'); return $this->ip($ip); } + /** + * Sets the country for a user. The country should be a valid ISO 3166-1 + * alpha-2 or alpha-3 code. If it is not a valid ISO-3166-1 code, an attempt will be made to look up the country by its name. + * If that fails, a warning will be logged, and the country will not be set. + */ public function country($country) { $this->_country = $country; return $this; } + /** + * Sets the country for a user, and ensures that the country attribute will not be sent back to LaunchDarkly. + * The country should be a valid ISO 3166-1 + * alpha-2 or alpha-3 code. If it is not a valid ISO-3166-1 code, an attempt will be made to look up the country by its name. + * If that fails, a warning will be logged, and the country will not be set. + */ public function privateCountry($country) { array_push($this->_privateAttributeNames, 'country'); return $this->country($country); } + /** + * Sets the user's email address. + */ public function email($email) { $this->_email = $email; return $this; } + /** + * Sets the user's email address, and ensures that the email attribute will not be sent back to LaunchDarkly. + */ public function privateEmail($email) { array_push($this->_privateAttributeNames, 'email'); return $this->email($email); } + /** + * Sets the user's full name. + */ public function name($name) { $this->_name = $name; return $this; } + /** + * Sets the user's full name, and ensures that the name attribute will not be sent back to LaunchDarkly. + */ public function privateName($name) { array_push($this->_privateAttributeNames, 'name'); return $this->name($name); } + /** + * Sets the user's avatar. + */ public function avatar($avatar) { $this->_avatar = $avatar; return $this; } + /** + * Sets the user's avatar, and ensures that the avatar attribute will not be sent back to LaunchDarkly. + */ public function privateAvatar($avatar) { array_push($this->_privateAttributeNames, 'avatar'); return $this->avatar($avatar); } + /** + * Sets the user's first name. + */ public function firstName($firstName) { $this->_firstName = $firstName; return $this; } + /** + * Sets the user's first name, and ensures that the first name attribute will not be sent back to LaunchDarkly. + */ public function privateFirstName($firstName) { array_push($this->_privateAttributeNames, 'firstName'); return $this->firstName($firstName); } + /** + * Sets the user's last name. + */ public function lastName($lastName) { $this->_lastName = $lastName; return $this; } + /** + * Sets the user's last name, and ensures that the last name attribute will not be sent back to LaunchDarkly. + */ public function privateLastName($lastName) { array_push($this->_privateAttributeNames, 'lastName'); return $this->lastName($lastName); } + /** + * Sets whether this user is anonymous. The default is false. + */ public function anonymous($anonymous) { $this->_anonymous = $anonymous; return $this; } + /** + * Sets any number of custom attributes for the user. + * @param array $custom An associative array of custom attribute names and values. + */ public function custom($custom) { $this->_custom = $custom; return $this; } + /** + * Sets a single custom attribute for the user. + */ public function customAttribute($customKey, $customValue) { $this->_custom[$customKey] = $customValue; return $this; } + /** + * Sets a single custom attribute for the user, and ensures that the attribute will not be sent back to LaunchDarkly. + */ public function privateCustomAttribute($customKey, $customValue) { array_push($this->_privateAttributeNames, $customKey); return $this->customAttribute($customKey, $customValue); From 5dd9a15cc63ffb9e8cc4bfcaedaba4b4d3cfdf7e Mon Sep 17 00:00:00 2001 From: Arun Bhalla Date: Wed, 3 Jan 2018 14:15:36 -0800 Subject: [PATCH 18/30] Update PHP version for Circle's Ubuntu 12.04 machine --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 73fa1cac4..8dee97a50 100644 --- a/circle.yml +++ b/circle.yml @@ -1,6 +1,6 @@ machine: php: - version: 5.6.17 + version: 5.6.14 services: - redis - docker @@ -27,4 +27,4 @@ test: - docker run -it -v `pwd`:/php-client php:7.1-alpine sh -c "curl -s https://getcomposer.org/installer | php && cd /php-client && /composer.phar update --prefer-lowest && vendor/bin/phpunit" - docker run -it -v `pwd`:/php-client nyanpass/php5.5:5.5-alpine sh -c "curl -s https://getcomposer.org/installer | php && cd /php-client && /composer.phar update && vendor/bin/phpunit" - - docker run -it -v `pwd`:/php-client nyanpass/php5.5:5.5-alpine sh -c "curl -s https://getcomposer.org/installer | php && cd /php-client && /composer.phar update --prefer-lowest && vendor/bin/phpunit" \ No newline at end of file + - docker run -it -v `pwd`:/php-client nyanpass/php5.5:5.5-alpine sh -c "curl -s https://getcomposer.org/installer | php && cd /php-client && /composer.phar update --prefer-lowest && vendor/bin/phpunit" From cf1a4cdb24bc592cea3f48a50c04398407145719 Mon Sep 17 00:00:00 2001 From: Arun Bhalla Date: Wed, 3 Jan 2018 14:37:10 -0800 Subject: [PATCH 19/30] Fix CircleCI/APCu build issue --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 8dee97a50..a30789fd4 100644 --- a/circle.yml +++ b/circle.yml @@ -7,8 +7,8 @@ machine: dependencies: pre: - yes '' | pecl install -f apcu-4.0.10 - - echo "extension=apcu.so" | sudo tee -a /opt/circleci/php/$(phpenv global)/etc/php.ini - - echo "apc.enable_cli = 1" | sudo tee -a /opt/circleci/php/$(phpenv global)/etc/php.ini + - echo "extension=apcu.so" >> $(php-config --prefix)/etc/conf.d/apcu.ini + - echo "apc.enable_cli = 1" >> $(php-config --prefix)/etc/conf.d/apcu.ini - docker pull php - docker pull nyanpass/php5.5 From 7533d222fed90c9d5b1d644317778a5d3e4fa0fe Mon Sep 17 00:00:00 2001 From: Andrew Shannon Brown Date: Wed, 10 Jan 2018 13:37:51 -0800 Subject: [PATCH 20/30] Don't return custom attributes as json array. (#14) By not sending the 'custom' attribute when it is empty, we don't have to deal with trying to return an object rather than array. --- src/LaunchDarkly/EventSerializer.php | 4 +++- tests/EventSerializerTest.php | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/LaunchDarkly/EventSerializer.php b/src/LaunchDarkly/EventSerializer.php index 5dc083163..63067b246 100644 --- a/src/LaunchDarkly/EventSerializer.php +++ b/src/LaunchDarkly/EventSerializer.php @@ -70,7 +70,9 @@ private function serializeUser($user) { if (!empty($user->getCustom())) { $customs = array(); $this->filterAttrs($user->getCustom(), $customs, $userPrivateAttrs, $allPrivateAttrs); - $json['custom'] = $customs; + if ($customs) { // if this is empty, we will return a json array for 'custom' instead of an object + $json['custom'] = $customs; + } } if (count($allPrivateAttrs)) { $pa = array_keys($allPrivateAttrs); diff --git a/tests/EventSerializerTest.php b/tests/EventSerializerTest.php index 432273bc0..27f7bc900 100644 --- a/tests/EventSerializerTest.php +++ b/tests/EventSerializerTest.php @@ -32,7 +32,6 @@ private function getFullUserResult() { private function getUserResultWithAllAttrsHidden() { return array( 'key' => 'abc', - 'custom' => array(), 'privateAttrs' => array('bizzle', 'dizzle', 'firstName') ); } @@ -122,7 +121,14 @@ public function testEmptyCustom() { $json = $this->getJsonForUserBySerializingEvent($user); $this->assertFalse(isset($json['custom'])); } - + + public function testEmptyPrivateCustom() { + $builder = new LDUserBuilder("foo@bar.com"); + $user = $builder->privateCustomAttribute("my-key", "my-value")->build(); + $json = $this->getJsonForUserBySerializingEvent($user); + $this->assertFalse(isset($json['custom'])); + } + public function testUserSecondary() { $builder = new LDUserBuilder("foo@bar.com"); $user = $builder->secondary("secondary")->build(); From ecf17dfbde5f734a69e7b3c363cbc403d3874c44 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Tue, 16 Jan 2018 15:41:16 -0800 Subject: [PATCH 21/30] add semantic version operators --- composer.json | 1 + composer.lock | 64 +++++++++++++++++++++++++++++++++- src/LaunchDarkly/Operators.php | 34 +++++++++++++++++- tests/OperatorsTest.php | 13 +++++++ 4 files changed, 110 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 3bd37a5f7..ccac32af3 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ } ], "require": { + "composer/semver": "^1.4", "monolog/monolog": "^1.6", "php": ">=5.5", "psr/log": "^1.0" diff --git a/composer.lock b/composer.lock index 1e40df487..db5d3560f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,70 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "ad2c6c29c2c748655900711de6dba807", + "content-hash": "2e1b4465572ea25199419a5ba8553048", "packages": [ + { + "name": "composer/semver", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", + "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.5 || ^5.0.5", + "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "time": "2016-08-30T16:08:34+00:00" + }, { "name": "monolog/monolog", "version": "1.22.1", diff --git a/src/LaunchDarkly/Operators.php b/src/LaunchDarkly/Operators.php index 1c023ae36..ed0039078 100644 --- a/src/LaunchDarkly/Operators.php +++ b/src/LaunchDarkly/Operators.php @@ -1,11 +1,16 @@ normalize($in); + } catch (Exception $e) { + return null; + } + } } diff --git a/tests/OperatorsTest.php b/tests/OperatorsTest.php index 6611123bd..bc77ca27b 100644 --- a/tests/OperatorsTest.php +++ b/tests/OperatorsTest.php @@ -55,4 +55,17 @@ public function testParseTime() $this->assertEquals(null, Operators::parseTime("NOT A REAL TIMESTAMP")); $this->assertEquals(null, Operators::parseTime([])); } + + public function testSemVer() { + $this->assertTrue(Operators::apply("semVerEqual", "2.0.0", "2.0.0")); + $this->assertTrue(Operators::apply("semVerEqual", "2.0", "2.0.0")); + $this->assertFalse(Operators::apply("semVerEqual", "2.0.0", "2.0.1")); + $this->assertTrue(Operators::apply("semVerLessThan", "2.0.0", "2.0.1")); + $this->assertTrue(Operators::apply("semVerLessThan", "2.0", "2.0.1")); + $this->assertFalse(Operators::apply("semVerLessThan", "2.0.1", "2.0.0")); + $this->assertTrue(Operators::apply("semVerGreaterThan", "2.0.1", "2.0.0")); + $this->assertFalse(Operators::apply("semVerGreaterThan", "2.0.0", "2.0.1")); + $this->assertFalse(Operators::apply("semVerLessThan", "2.0.0", "xbad%ver")); + $this->assertFalse(Operators::apply("semVerGreaterThan", "2.0.0", "xbad%ver")); + } } \ No newline at end of file From 2c0a5cdc9aa632596cc952a09accffe79d99427c Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Thu, 18 Jan 2018 18:21:50 -0800 Subject: [PATCH 22/30] switch to herrera-io/version library --- composer.json | 2 +- composer.lock | 464 +++++++++++++++++---------------- src/LaunchDarkly/Operators.php | 20 +- 3 files changed, 246 insertions(+), 240 deletions(-) diff --git a/composer.json b/composer.json index ccac32af3..5e8d0dd98 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "composer/semver": "^1.4", + "herrera-io/version": "^1.1.1", "monolog/monolog": "^1.6", "php": ">=5.5", "psr/log": "^1.0" diff --git a/composer.lock b/composer.lock index db5d3560f..121187f3c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,38 +4,38 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "2e1b4465572ea25199419a5ba8553048", + "content-hash": "cd500f316e5cb4678769aa44fd67ff5e", "packages": [ { - "name": "composer/semver", - "version": "1.4.2", + "name": "herrera-io/version", + "version": "1.1.1", "source": { "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" + "url": "https://github.com/kherge-abandoned/php-version.git", + "reference": "d39d9642b92a04d8b8a28b871b797a35a2545e85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", + "url": "https://api.github.com/repos/kherge-abandoned/php-version/zipball/d39d9642b92a04d8b8a28b871b797a35a2545e85", + "reference": "d39d9642b92a04d8b8a28b871b797a35a2545e85", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0" + "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "herrera-io/phpunit-test-case": "1.*", + "phpunit/phpunit": "3.7.*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" + "psr-0": { + "Herrera\\Version": "src/lib" } }, "notification-url": "https://packagist.org/downloads/", @@ -44,42 +44,32 @@ ], "authors": [ { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" + "name": "Kevin Herrera", + "email": "kevin@herrera.io", + "homepage": "http://kevin.herrera.io" } ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", + "description": "A library for creating, editing, and comparing semantic versioning numbers.", + "homepage": "http://github.com/herrera-io/php-version", "keywords": [ "semantic", - "semver", - "validation", - "versioning" + "version" ], - "time": "2016-08-30T16:08:34+00:00" + "abandoned": true, + "time": "2014-05-27T05:29:25+00:00" }, { "name": "monolog/monolog", - "version": "1.22.1", + "version": "1.23.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "1e044bc4b34e91743943479f1be7a1d5eb93add0" + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1e044bc4b34e91743943479f1be7a1d5eb93add0", - "reference": "1e044bc4b34e91743943479f1be7a1d5eb93add0", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", "shasum": "" }, "require": { @@ -100,7 +90,7 @@ "phpunit/phpunit-mock-objects": "2.3.0", "ruflin/elastica": ">=0.90 <3.0", "sentry/sentry": "^0.13", - "swiftmailer/swiftmailer": "~5.3" + "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", @@ -144,7 +134,7 @@ "logging", "psr-3" ], - "time": "2017-03-13T07:08:03+00:00" + "time": "2017-06-19T01:22:40+00:00" }, { "name": "psr/log", @@ -346,30 +336,30 @@ }, { "name": "doctrine/annotations", - "version": "v1.4.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" + "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -410,36 +400,36 @@ "docblock", "parser" ], - "time": "2017-02-24T16:22:25+00:00" + "time": "2017-12-06T07:11:42+00:00" }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -464,7 +454,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2017-07-22T11:58:36+00:00" }, { "name": "doctrine/lexer", @@ -522,21 +512,24 @@ }, { "name": "erusev/parsedown", - "version": "1.6.2", + "version": "1.6.4", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", - "reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01" + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/1bf24f7334fe16c88bf9d467863309ceaf285b01", - "reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/fbe3fe878f4fe69048bb8a52783a09802004f548", + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548", "shasum": "" }, "require": { "php": ">=5.3.0" }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, "type": "library", "autoload": { "psr-0": { @@ -560,20 +553,20 @@ "markdown", "parser" ], - "time": "2017-03-29T16:04:15+00:00" + "time": "2017-11-14T20:44:03+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "6.2.3", + "version": "6.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006" + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/8d6c6cc55186db87b7dc5009827429ba4e9dc006", - "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", "shasum": "" }, "require": { @@ -583,9 +576,12 @@ }, "require-dev": { "ext-curl": "*", - "phpunit/phpunit": "^4.0", + "phpunit/phpunit": "^4.0 || ^5.0", "psr/log": "^1.0" }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, "type": "library", "extra": { "branch-alias": { @@ -622,7 +618,7 @@ "rest", "web service" ], - "time": "2017-02-28T22:50:30+00:00" + "time": "2017-06-22T18:50:49+00:00" }, { "name": "guzzlehttp/promises", @@ -947,16 +943,16 @@ }, { "name": "jms/serializer", - "version": "1.6.2", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "b8683d206e7297f54034f67a877f966c14dc12ea" + "reference": "62c7ff6d61f8692eac8be024c542b3d9d0ab8c8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/b8683d206e7297f54034f67a877f966c14dc12ea", - "reference": "b8683d206e7297f54034f67a877f966c14dc12ea", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/62c7ff6d61f8692eac8be024c542b3d9d0ab8c8a", + "reference": "62c7ff6d61f8692eac8be024c542b3d9d0ab8c8a", "shasum": "" }, "require": { @@ -979,6 +975,8 @@ "jackalope/jackalope-doctrine-dbal": "^1.1.5", "phpunit/phpunit": "^4.8|^5.0", "propel/propel1": "~1.7", + "psr/container": "^1.0", + "symfony/dependency-injection": "^2.7|^3.3|^4.0", "symfony/expression-language": "^2.6|^3.0", "symfony/filesystem": "^2.1", "symfony/form": "~2.1|^3.0", @@ -995,7 +993,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.10-dev" } }, "autoload": { @@ -1005,9 +1003,13 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache2" + "Apache-2.0" ], "authors": [ + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + }, { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" @@ -1022,7 +1024,7 @@ "serialization", "xml" ], - "time": "2017-04-17T15:27:46+00:00" + "time": "2017-11-30T18:23:40+00:00" }, { "name": "justinrainbow/json-schema", @@ -1213,37 +1215,40 @@ }, { "name": "myclabs/deep-copy", - "version": "1.6.1", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102" + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102", - "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": "^5.6 || ^7.0" }, "require-dev": { - "doctrine/collections": "1.*", - "phpunit/phpunit": "~4.1" + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.1" }, "type": "library", "autoload": { "psr-4": { "DeepCopy\\": "src/DeepCopy/" - } + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "description": "Create deep copies (clones) of your objects", - "homepage": "https://github.com/myclabs/DeepCopy", "keywords": [ "clone", "copy", @@ -1251,7 +1256,7 @@ "object", "object graph" ], - "time": "2017-04-12T18:52:22+00:00" + "time": "2017-10-19T19:58:43+00:00" }, { "name": "nikic/php-parser", @@ -1575,16 +1580,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "2.0.4", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b", + "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b", "shasum": "" }, "require": { @@ -1620,7 +1625,7 @@ "email": "mike.vanriel@naenius.com" } ], - "time": "2015-02-03T12:10:50+00:00" + "time": "2016-01-25T08:17:30+00:00" }, { "name": "phpoption/phpoption", @@ -1674,33 +1679,33 @@ }, { "name": "phpspec/prophecy", - "version": "v1.7.0", + "version": "1.7.3", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" + "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", - "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", + "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", "sebastian/comparator": "^1.1|^2.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8 || ^5.6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -1733,7 +1738,7 @@ "spy", "stub" ], - "time": "2017-03-02T20:05:34+00:00" + "time": "2017-11-24T13:59:53+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1800,16 +1805,16 @@ }, { "name": "phpunit/php-file-iterator", - "version": "1.4.2", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", "shasum": "" }, "require": { @@ -1843,7 +1848,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" + "time": "2017-11-27T13:52:08+00:00" }, { "name": "phpunit/php-text-template", @@ -1937,16 +1942,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.4.11", + "version": "1.4.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", - "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", "shasum": "" }, "require": { @@ -1982,7 +1987,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-02-27T10:12:30+00:00" + "time": "2017-12-04T08:55:13+00:00" }, { "name": "phpunit/phpunit", @@ -2421,23 +2426,23 @@ }, { "name": "sebastian/diff", - "version": "1.4.1", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", "extra": { @@ -2469,7 +2474,7 @@ "keywords": [ "diff" ], - "time": "2015-12-08T07:14:41+00:00" + "time": "2017-05-22T07:24:03+00:00" }, { "name": "sebastian/environment", @@ -2825,23 +2830,23 @@ }, { "name": "seld/jsonlint", - "version": "1.6.0", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "791f8c594f300d246cdf01c6b3e1e19611e301d8" + "reference": "9b355654ea99460397b89c132b5c1087b6bf4473" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/791f8c594f300d246cdf01c6b3e1e19611e301d8", - "reference": "791f8c594f300d246cdf01c6b3e1e19611e301d8", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9b355654ea99460397b89c132b5c1087b6bf4473", + "reference": "9b355654ea99460397b89c132b5c1087b6bf4473", "shasum": "" }, "require": { "php": "^5.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "bin": [ "bin/jsonlint" @@ -2870,20 +2875,20 @@ "parser", "validator" ], - "time": "2017-03-06T16:42:24+00:00" + "time": "2018-01-03T12:13:57+00:00" }, { "name": "symfony/config", - "version": "v2.8.19", + "version": "v2.8.33", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "35b7dfa089d7605eb1fdd46281b3070fb9f38750" + "reference": "705d1687222c08deabac8993ec2e04ad1a422c52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/35b7dfa089d7605eb1fdd46281b3070fb9f38750", - "reference": "35b7dfa089d7605eb1fdd46281b3070fb9f38750", + "url": "https://api.github.com/repos/symfony/config/zipball/705d1687222c08deabac8993ec2e04ad1a422c52", + "reference": "705d1687222c08deabac8993ec2e04ad1a422c52", "shasum": "" }, "require": { @@ -2926,20 +2931,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-04-04T15:24:26+00:00" + "time": "2018-01-03T07:36:31+00:00" }, { "name": "symfony/console", - "version": "v2.8.19", + "version": "v2.8.33", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "86407ff20855a5eaa2a7219bd815e9c40a88633e" + "reference": "a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/86407ff20855a5eaa2a7219bd815e9c40a88633e", - "reference": "86407ff20855a5eaa2a7219bd815e9c40a88633e", + "url": "https://api.github.com/repos/symfony/console/zipball/a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe", + "reference": "a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe", "shasum": "" }, "require": { @@ -2987,7 +2992,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-04-03T20:37:06+00:00" + "time": "2018-01-03T07:36:31+00:00" }, { "name": "symfony/debug", @@ -3048,16 +3053,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.19", + "version": "v2.8.33", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "88b65f0ac25355090e524aba4ceb066025df8bd2" + "reference": "d64be24fc1eba62f9daace8a8918f797fc8e87cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/88b65f0ac25355090e524aba4ceb066025df8bd2", - "reference": "88b65f0ac25355090e524aba4ceb066025df8bd2", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d64be24fc1eba62f9daace8a8918f797fc8e87cc", + "reference": "d64be24fc1eba62f9daace8a8918f797fc8e87cc", "shasum": "" }, "require": { @@ -3104,7 +3109,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-04-03T20:37:06+00:00" + "time": "2018-01-03T07:36:31+00:00" }, { "name": "symfony/filesystem", @@ -3157,16 +3162,16 @@ }, { "name": "symfony/finder", - "version": "v2.8.19", + "version": "v2.8.33", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "7131327eb95d86d72039fd1216226c28f36fd02a" + "reference": "cb2ce50366dd3168f7b06135ffee0a5e35713ce8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/7131327eb95d86d72039fd1216226c28f36fd02a", - "reference": "7131327eb95d86d72039fd1216226c28f36fd02a", + "url": "https://api.github.com/repos/symfony/finder/zipball/cb2ce50366dd3168f7b06135ffee0a5e35713ce8", + "reference": "cb2ce50366dd3168f7b06135ffee0a5e35713ce8", "shasum": "" }, "require": { @@ -3202,20 +3207,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-03-20T08:46:40+00:00" + "time": "2018-01-03T07:36:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.3.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" + "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", + "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", "shasum": "" }, "require": { @@ -3227,7 +3232,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -3261,20 +3266,20 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/process", - "version": "v2.8.19", + "version": "v2.8.33", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "41336b20b52f5fd5b42a227e394e673c8071118f" + "reference": "ea3226daa3c6789efa39570bfc6e5d55f7561a0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/41336b20b52f5fd5b42a227e394e673c8071118f", - "reference": "41336b20b52f5fd5b42a227e394e673c8071118f", + "url": "https://api.github.com/repos/symfony/process/zipball/ea3226daa3c6789efa39570bfc6e5d55f7561a0a", + "reference": "ea3226daa3c6789efa39570bfc6e5d55f7561a0a", "shasum": "" }, "require": { @@ -3310,20 +3315,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-03-04T12:20:59+00:00" + "time": "2018-01-03T07:36:31+00:00" }, { "name": "symfony/stopwatch", - "version": "v2.8.19", + "version": "v2.8.33", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "9e4369666d02ee9b8830da878b7f6a769eb96f4b" + "reference": "57021208ad9830f8f8390c1a9d7bb390f32be89e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/9e4369666d02ee9b8830da878b7f6a769eb96f4b", - "reference": "9e4369666d02ee9b8830da878b7f6a769eb96f4b", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/57021208ad9830f8f8390c1a9d7bb390f32be89e", + "reference": "57021208ad9830f8f8390c1a9d7bb390f32be89e", "shasum": "" }, "require": { @@ -3359,7 +3364,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2017-02-18T17:06:33+00:00" + "time": "2018-01-03T07:36:31+00:00" }, { "name": "symfony/translation", @@ -3427,16 +3432,16 @@ }, { "name": "symfony/validator", - "version": "v2.8.19", + "version": "v2.8.33", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "43f617ee200af4f4dedbb0782c6c689e06994286" + "reference": "e6da867bf86ba5009381d59718071329359ddbff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/43f617ee200af4f4dedbb0782c6c689e06994286", - "reference": "43f617ee200af4f4dedbb0782c6c689e06994286", + "url": "https://api.github.com/repos/symfony/validator/zipball/e6da867bf86ba5009381d59718071329359ddbff", + "reference": "e6da867bf86ba5009381d59718071329359ddbff", "shasum": "" }, "require": { @@ -3496,24 +3501,24 @@ ], "description": "Symfony Validator Component", "homepage": "https://symfony.com", - "time": "2017-03-23T16:08:03+00:00" + "time": "2018-01-03T17:12:09+00:00" }, { "name": "symfony/yaml", - "version": "v3.2.7", + "version": "v3.3.15", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "62b4cdb99d52cb1ff253c465eb1532a80cebb621" + "reference": "7c80d81b5805589be151b85b0df785f0dc3269cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/62b4cdb99d52cb1ff253c465eb1532a80cebb621", - "reference": "62b4cdb99d52cb1ff253c465eb1532a80cebb621", + "url": "https://api.github.com/repos/symfony/yaml/zipball/7c80d81b5805589be151b85b0df785f0dc3269cf", + "reference": "7c80d81b5805589be151b85b0df785f0dc3269cf", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^5.5.9|>=7.0.8" }, "require-dev": { "symfony/console": "~2.8|~3.0" @@ -3524,7 +3529,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "3.3-dev" } }, "autoload": { @@ -3551,24 +3556,24 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2017-03-20T09:45:15+00:00" + "time": "2018-01-03T07:37:11+00:00" }, { "name": "twig/twig", - "version": "v1.33.2", + "version": "v1.35.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "dd6ca96227917e1e85b41c7c3cc6507b411e0927" + "reference": "daa657073e55b0a78cce8fdd22682fddecc6385f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/dd6ca96227917e1e85b41c7c3cc6507b411e0927", - "reference": "dd6ca96227917e1e85b41c7c3cc6507b411e0927", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/daa657073e55b0a78cce8fdd22682fddecc6385f", + "reference": "daa657073e55b0a78cce8fdd22682fddecc6385f", "shasum": "" }, "require": { - "php": ">=5.2.7" + "php": ">=5.3.3" }, "require-dev": { "psr/container": "^1.0", @@ -3578,12 +3583,15 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.33-dev" + "dev-master": "1.35-dev" } }, "autoload": { "psr-0": { "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3613,7 +3621,7 @@ "keywords": [ "templating" ], - "time": "2017-04-20T17:39:48+00:00" + "time": "2017-09-27T18:06:46+00:00" }, { "name": "zendframework/zend-cache", @@ -3742,16 +3750,16 @@ }, { "name": "zendframework/zend-eventmanager", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-eventmanager.git", - "reference": "c3bce7b7d47c54040b9ae51bc55491c72513b75d" + "reference": "9d72db10ceb6e42fb92350c0cb54460da61bd79c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/c3bce7b7d47c54040b9ae51bc55491c72513b75d", - "reference": "c3bce7b7d47c54040b9ae51bc55491c72513b75d", + "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/9d72db10ceb6e42fb92350c0cb54460da61bd79c", + "reference": "9d72db10ceb6e42fb92350c0cb54460da61bd79c", "shasum": "" }, "require": { @@ -3760,7 +3768,7 @@ "require-dev": { "athletic/athletic": "^0.1", "container-interop/container-interop": "^1.1.0", - "phpunit/phpunit": "^5.6", + "phpunit/phpunit": "^6.0.7 || ^5.7.14", "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-stdlib": "^2.7.3 || ^3.0" }, @@ -3771,8 +3779,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev", - "dev-develop": "3.2-dev" + "dev-master": "3.2-dev", + "dev-develop": "3.3-dev" } }, "autoload": { @@ -3792,20 +3800,20 @@ "events", "zf2" ], - "time": "2016-12-19T21:47:12+00:00" + "time": "2017-07-11T19:17:22+00:00" }, { "name": "zendframework/zend-filter", - "version": "2.7.1", + "version": "2.7.2", "source": { "type": "git", "url": "https://github.com/zendframework/zend-filter.git", - "reference": "84c50246428efb0a1e52868e162dab3e149d5b80" + "reference": "b8d0ff872f126631bf63a932e33aa2d22d467175" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-filter/zipball/84c50246428efb0a1e52868e162dab3e149d5b80", - "reference": "84c50246428efb0a1e52868e162dab3e149d5b80", + "url": "https://api.github.com/repos/zendframework/zend-filter/zipball/b8d0ff872f126631bf63a932e33aa2d22d467175", + "reference": "b8d0ff872f126631bf63a932e33aa2d22d467175", "shasum": "" }, "require": { @@ -3813,10 +3821,10 @@ "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "require-dev": { - "fabpot/php-cs-fixer": "1.7.*", "pear/archive_tar": "^1.4", - "phpunit/phpunit": "~4.0", - "zendframework/zend-crypt": "^2.6", + "phpunit/phpunit": "^6.0.10 || ^5.7.17", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-crypt": "^2.6 || ^3.0", "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", "zendframework/zend-uri": "^2.5" }, @@ -3852,7 +3860,7 @@ "filter", "zf2" ], - "time": "2016-04-18T18:32:43+00:00" + "time": "2017-05-17T20:56:17+00:00" }, { "name": "zendframework/zend-hydrator", @@ -3914,26 +3922,26 @@ }, { "name": "zendframework/zend-i18n", - "version": "2.7.3", + "version": "2.7.4", "source": { "type": "git", "url": "https://github.com/zendframework/zend-i18n.git", - "reference": "b2db0d8246a865c659f93199f90f5fc2cd2f3cd8" + "reference": "d3431e29cc00c2a1c6704e601d4371dbf24f6a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/b2db0d8246a865c659f93199f90f5fc2cd2f3cd8", - "reference": "b2db0d8246a865c659f93199f90f5fc2cd2f3cd8", + "url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/d3431e29cc00c2a1c6704e601d4371dbf24f6a31", + "reference": "d3431e29cc00c2a1c6704e601d4371dbf24f6a31", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", + "php": "^7.0 || ^5.6", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "require-dev": { - "fabpot/php-cs-fixer": "1.7.*", - "phpunit/phpunit": "~4.0", + "phpunit/phpunit": "^6.0.8 || ^5.7.15", "zendframework/zend-cache": "^2.6.1", + "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-config": "^2.6", "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", "zendframework/zend-filter": "^2.6.1", @@ -3977,29 +3985,29 @@ "i18n", "zf2" ], - "time": "2016-06-07T21:08:30+00:00" + "time": "2017-05-17T17:00:12+00:00" }, { "name": "zendframework/zend-json", - "version": "3.0.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-json.git", - "reference": "f42a1588e75c2a3e338cd94c37906231e616daab" + "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-json/zipball/f42a1588e75c2a3e338cd94c37906231e616daab", - "reference": "f42a1588e75c2a3e338cd94c37906231e616daab", + "url": "https://api.github.com/repos/zendframework/zend-json/zipball/4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", + "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0" + "php": "^5.6 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "^2.3", - "zendframework/zend-stdlib": "^2.7 || ^3.0" + "phpunit/phpunit": "^5.7.23 || ^6.4.3", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-stdlib": "^2.7.7 || ^3.1" }, "suggest": { "zendframework/zend-json-server": "For implementing JSON-RPC servers", @@ -4008,8 +4016,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev", - "dev-develop": "3.1-dev" + "dev-master": "3.1.x-dev", + "dev-develop": "3.2.x-dev" } }, "autoload": { @@ -4022,25 +4030,25 @@ "BSD-3-Clause" ], "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP", - "homepage": "https://github.com/zendframework/zend-json", "keywords": [ + "ZendFramework", "json", - "zf2" + "zf" ], - "time": "2016-04-01T02:34:00+00:00" + "time": "2018-01-04T17:51:34+00:00" }, { "name": "zendframework/zend-serializer", - "version": "2.8.0", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-serializer.git", - "reference": "ff74ea020f5f90866eb28365327e9bc765a61a6e" + "reference": "7ac42b9a47e9cb23895173a3096bc3b3fb7ac580" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/ff74ea020f5f90866eb28365327e9bc765a61a6e", - "reference": "ff74ea020f5f90866eb28365327e9bc765a61a6e", + "url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/7ac42b9a47e9cb23895173a3096bc3b3fb7ac580", + "reference": "7ac42b9a47e9cb23895173a3096bc3b3fb7ac580", "shasum": "" }, "require": { @@ -4049,8 +4057,9 @@ "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "require-dev": { - "phpunit/phpunit": "^4.5", - "squizlabs/php_codesniffer": "^2.3.1", + "doctrine/instantiator": "1.0.*", + "phpunit/phpunit": "^5.5", + "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-math": "^2.6", "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" }, @@ -4084,20 +4093,20 @@ "serializer", "zf2" ], - "time": "2016-06-21T17:01:55+00:00" + "time": "2017-11-20T22:21:04+00:00" }, { "name": "zendframework/zend-servicemanager", - "version": "2.7.8", + "version": "2.7.10", "source": { "type": "git", "url": "https://github.com/zendframework/zend-servicemanager.git", - "reference": "2ae3b6e4978ec2e9ff52352e661946714ed989f9" + "reference": "ba7069c94c9af93122be9fa31cddd37f7707d5b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/2ae3b6e4978ec2e9ff52352e661946714ed989f9", - "reference": "2ae3b6e4978ec2e9ff52352e661946714ed989f9", + "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/ba7069c94c9af93122be9fa31cddd37f7707d5b4", + "reference": "ba7069c94c9af93122be9fa31cddd37f7707d5b4", "shasum": "" }, "require": { @@ -4136,7 +4145,7 @@ "servicemanager", "zf2" ], - "time": "2016-12-19T19:14:29+00:00" + "time": "2017-12-05T16:27:36+00:00" }, { "name": "zendframework/zend-stdlib", @@ -4199,19 +4208,20 @@ }, { "name": "zetacomponents/base", - "version": "1.9", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/zetacomponents/Base.git", - "reference": "f20df24e8de3e48b6b69b2503f917e457281e687" + "reference": "489e20235989ddc97fdd793af31ac803972454f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Base/zipball/f20df24e8de3e48b6b69b2503f917e457281e687", - "reference": "f20df24e8de3e48b6b69b2503f917e457281e687", + "url": "https://api.github.com/repos/zetacomponents/Base/zipball/489e20235989ddc97fdd793af31ac803972454f1", + "reference": "489e20235989ddc97fdd793af31ac803972454f1", "shasum": "" }, "require-dev": { + "phpunit/phpunit": "~5.7", "zetacomponents/unit-test": "*" }, "type": "library", @@ -4258,7 +4268,7 @@ ], "description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.", "homepage": "https://github.com/zetacomponents", - "time": "2014-09-19T03:28:34+00:00" + "time": "2017-11-28T11:30:00+00:00" }, { "name": "zetacomponents/document", diff --git a/src/LaunchDarkly/Operators.php b/src/LaunchDarkly/Operators.php index ed0039078..ec915ecdb 100644 --- a/src/LaunchDarkly/Operators.php +++ b/src/LaunchDarkly/Operators.php @@ -1,16 +1,15 @@ 0; } } catch (Exception $ignored) { } @@ -141,12 +140,9 @@ public static function parseTime($in) * @return null|string */ public static function parseSemVer($in) { - if (static::$versionParser == null) { - static::$versionParser = new VersionParser(); - } try { - return static::$versionParser->normalize($in); - } catch (Exception $e) { + return Parser::toVersion($in); + } catch (InvalidStringRepresentationException $e) { return null; } } From fe268d6ed8b287f46c67c094645a00b33d981ee1 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 19 Jan 2018 09:57:17 -0800 Subject: [PATCH 23/30] add normalization of shortened versions --- src/LaunchDarkly/Operators.php | 16 ++++++++++++++++ tests/OperatorsTest.php | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/src/LaunchDarkly/Operators.php b/src/LaunchDarkly/Operators.php index ec915ecdb..4df16bae3 100644 --- a/src/LaunchDarkly/Operators.php +++ b/src/LaunchDarkly/Operators.php @@ -11,6 +11,7 @@ class Operators { const RFC3339 = 'Y-m-d\TH:i:s.uP'; + const VERSION_NUMBERS_REGEX = '/^\\d+(\\.\\d+)?(\\.\\d+)?/'; /** * @param $op string @@ -143,6 +144,21 @@ public static function parseSemVer($in) { try { return Parser::toVersion($in); } catch (InvalidStringRepresentationException $e) { + // If minor or patch version was omitted, or both, normalize the version + // by adding zeroes in their place. + if (preg_match(Operators::VERSION_NUMBERS_REGEX, $in, $matches)) { + $transformed = $matches[0]; + for ($i = 1; $i <= 3; $i++) { + if ($i > count($matches)) { + $transformed .= '.0'; + } + } + $transformed .= substr($in, strlen($matches[0])); + try { + return Parser::toVersion($transformed); + } catch (InvalidStringRepresentationException $e) { + } + } return null; } } diff --git a/tests/OperatorsTest.php b/tests/OperatorsTest.php index bc77ca27b..a66d8e783 100644 --- a/tests/OperatorsTest.php +++ b/tests/OperatorsTest.php @@ -59,12 +59,17 @@ public function testParseTime() public function testSemVer() { $this->assertTrue(Operators::apply("semVerEqual", "2.0.0", "2.0.0")); $this->assertTrue(Operators::apply("semVerEqual", "2.0", "2.0.0")); + $this->assertTrue(Operators::apply("semVerEqual", "2", "2.0.0")); + $this->assertTrue(Operators::apply("semVerEqual", "2-rc1", "2.0.0-rc1")); + $this->assertTrue(Operators::apply("semVerEqual", "2+build2", "2.0.0+build2")); $this->assertFalse(Operators::apply("semVerEqual", "2.0.0", "2.0.1")); $this->assertTrue(Operators::apply("semVerLessThan", "2.0.0", "2.0.1")); $this->assertTrue(Operators::apply("semVerLessThan", "2.0", "2.0.1")); $this->assertFalse(Operators::apply("semVerLessThan", "2.0.1", "2.0.0")); + $this->assertTrue(Operators::apply("semVerLessThan", "2.0.0-rc", "2.0.0-rc.beta")); $this->assertTrue(Operators::apply("semVerGreaterThan", "2.0.1", "2.0.0")); $this->assertFalse(Operators::apply("semVerGreaterThan", "2.0.0", "2.0.1")); + $this->assertTrue(Operators::apply("semVerGreaterThan", "2.0.0-rc.1", "2.0.0-rc.0")); $this->assertFalse(Operators::apply("semVerLessThan", "2.0.0", "xbad%ver")); $this->assertFalse(Operators::apply("semVerGreaterThan", "2.0.0", "xbad%ver")); } From 70b205c0fa4bff7699c8c27c1769cbe8d24bd8ea Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 19 Jan 2018 12:57:05 -0800 Subject: [PATCH 24/30] add prerelease version test --- tests/OperatorsTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/OperatorsTest.php b/tests/OperatorsTest.php index a66d8e783..34157519a 100644 --- a/tests/OperatorsTest.php +++ b/tests/OperatorsTest.php @@ -66,6 +66,7 @@ public function testSemVer() { $this->assertTrue(Operators::apply("semVerLessThan", "2.0.0", "2.0.1")); $this->assertTrue(Operators::apply("semVerLessThan", "2.0", "2.0.1")); $this->assertFalse(Operators::apply("semVerLessThan", "2.0.1", "2.0.0")); + $this->assertTrue(Operators::apply("semVerLessThan", "2.0.0-rc", "2.0.0")); $this->assertTrue(Operators::apply("semVerLessThan", "2.0.0-rc", "2.0.0-rc.beta")); $this->assertTrue(Operators::apply("semVerGreaterThan", "2.0.1", "2.0.0")); $this->assertFalse(Operators::apply("semVerGreaterThan", "2.0.0", "2.0.1")); From 9eea48190bf1cc04d0be11301e7659095f5a5efc Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 19 Jan 2018 13:34:23 -0800 Subject: [PATCH 25/30] fix composer.lock --- composer.lock | 396 +++++++++++++------------------------------------- 1 file changed, 105 insertions(+), 291 deletions(-) diff --git a/composer.lock b/composer.lock index 121187f3c..6e8ca4634 100644 --- a/composer.lock +++ b/composer.lock @@ -336,35 +336,35 @@ }, { "name": "doctrine/annotations", - "version": "v1.6.0", + "version": "v1.2.7", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5" + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", - "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^7.1" + "php": ">=5.3.2" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "4.*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + "psr-0": { + "Doctrine\\Common\\Annotations\\": "lib/" } }, "notification-url": "https://packagist.org/downloads/", @@ -400,36 +400,36 @@ "docblock", "parser" ], - "time": "2017-12-06T07:11:42+00:00" + "time": "2015-08-31T12:32:49+00:00" }, { "name": "doctrine/instantiator", - "version": "1.1.0", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=5.3,<8.0-DEV" }, "require-dev": { "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -454,7 +454,7 @@ "constructor", "instantiate" ], - "time": "2017-07-22T11:58:36+00:00" + "time": "2015-06-14T21:17:01+00:00" }, { "name": "doctrine/lexer", @@ -1213,51 +1213,6 @@ "abandoned": true, "time": "2012-08-16T17:13:03+00:00" }, - { - "name": "myclabs/deep-copy", - "version": "1.7.0", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, - "files": [ - "src/DeepCopy/deep_copy.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "time": "2017-10-19T19:58:43+00:00" - }, { "name": "nikic/php-parser", "version": "v1.4.1", @@ -1742,40 +1697,39 @@ }, { "name": "phpunit/php-code-coverage", - "version": "3.3.3", + "version": "2.2.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "44cd8e3930e431658d1a5de7d282d5cb37837fd5" + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/44cd8e3930e431658d1a5de7d282d5cb37837fd5", - "reference": "44cd8e3930e431658d1a5de7d282d5cb37837fd5", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0", + "php": ">=5.3.3", "phpunit/php-file-iterator": "~1.3", "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "^1.4.2", - "sebastian/code-unit-reverse-lookup": "~1.0", + "phpunit/php-token-stream": "~1.3", "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0|~2.0" + "sebastian/version": "~1.0" }, "require-dev": { "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~5" + "phpunit/phpunit": "~4" }, "suggest": { "ext-dom": "*", - "ext-xdebug": ">=2.4.0", + "ext-xdebug": ">=2.2.1", "ext-xmlwriter": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3.x-dev" + "dev-master": "2.2.x-dev" } }, "autoload": { @@ -1801,7 +1755,7 @@ "testing", "xunit" ], - "time": "2016-05-27T16:24:29+00:00" + "time": "2015-10-06T15:47:00+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1991,16 +1945,16 @@ }, { "name": "phpunit/phpunit", - "version": "5.3.5", + "version": "4.8.36", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "08c513bfcab57f3dd72f5214c1c3940439fae7fe" + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/08c513bfcab57f3dd72f5214c1c3940439fae7fe", - "reference": "08c513bfcab57f3dd72f5214c1c3940439fae7fe", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", "shasum": "" }, "require": { @@ -2009,22 +1963,19 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", - "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", + "php": ">=5.3.3", "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": ">=3.3.0,<4.0.0", + "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": ">=3.1.0,<3.2.0", - "sebastian/comparator": "~1.1", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.2.2", "sebastian/diff": "~1.2", "sebastian/environment": "~1.3", "sebastian/exporter": "~1.2", "sebastian/global-state": "~1.0", - "sebastian/object-enumerator": "~1.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "~1.0|~2.0", + "sebastian/version": "~1.0", "symfony/yaml": "~2.1|~3.0" }, "suggest": { @@ -2036,7 +1987,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "4.8.x-dev" } }, "autoload": { @@ -2062,30 +2013,30 @@ "testing", "xunit" ], - "time": "2016-06-03T09:42:56+00:00" + "time": "2017-06-21T08:07:12+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "3.1.3", + "version": "2.3.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "151c96874bff6fe61a25039df60e776613a61489" + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/151c96874bff6fe61a25039df60e776613a61489", - "reference": "151c96874bff6fe61a25039df60e776613a61489", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", - "php": ">=5.6", + "php": ">=5.3.3", "phpunit/php-text-template": "~1.2", "sebastian/exporter": "~1.2" }, "require-dev": { - "phpunit/phpunit": "~5" + "phpunit/phpunit": "~4.4" }, "suggest": { "ext-soap": "*" @@ -2093,7 +2044,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "2.3.x-dev" } }, "autoload": { @@ -2118,7 +2069,7 @@ "mock", "xunit" ], - "time": "2016-04-20T14:39:26+00:00" + "time": "2015-10-02T06:51:40+00:00" }, { "name": "pimple/pimple", @@ -2315,51 +2266,6 @@ ], "time": "2016-08-06T14:39:51+00:00" }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" - }, { "name": "sebastian/comparator", "version": "1.2.4", @@ -2644,52 +2550,6 @@ ], "time": "2015-10-12T03:26:01+00:00" }, - { - "name": "sebastian/object-enumerator", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", - "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", - "shasum": "" - }, - "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "phpunit/phpunit": "~5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2016-01-28T13:25:10+00:00" - }, { "name": "sebastian/recursion-context", "version": "1.0.5", @@ -2743,71 +2603,21 @@ "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "time": "2016-10-03T07:41:43+00:00" }, - { - "name": "sebastian/resource-operations", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "shasum": "" - }, - "require": { - "php": ">=5.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" - }, { "name": "sebastian/version", - "version": "2.0.1", + "version": "1.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", "shasum": "" }, - "require": { - "php": ">=5.6" - }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "classmap": [ "src/" @@ -2826,7 +2636,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "time": "2015-06-21T13:59:46+00:00" }, { "name": "seld/jsonlint", @@ -3750,26 +3560,26 @@ }, { "name": "zendframework/zend-eventmanager", - "version": "3.2.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-eventmanager.git", - "reference": "9d72db10ceb6e42fb92350c0cb54460da61bd79c" + "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/9d72db10ceb6e42fb92350c0cb54460da61bd79c", - "reference": "9d72db10ceb6e42fb92350c0cb54460da61bd79c", + "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/5c80bdee0e952be112dcec0968bad770082c3a6e", + "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^5.5 || ^7.0" }, "require-dev": { "athletic/athletic": "^0.1", "container-interop/container-interop": "^1.1.0", - "phpunit/phpunit": "^6.0.7 || ^5.7.14", - "zendframework/zend-coding-standard": "~1.0.0", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "^2.0", "zendframework/zend-stdlib": "^2.7.3 || ^3.0" }, "suggest": { @@ -3779,8 +3589,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev", - "dev-develop": "3.3-dev" + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" } }, "autoload": { @@ -3800,7 +3610,7 @@ "events", "zf2" ], - "time": "2017-07-11T19:17:22+00:00" + "time": "2016-02-18T20:53:00+00:00" }, { "name": "zendframework/zend-filter", @@ -3922,26 +3732,26 @@ }, { "name": "zendframework/zend-i18n", - "version": "2.7.4", + "version": "2.7.3", "source": { "type": "git", "url": "https://github.com/zendframework/zend-i18n.git", - "reference": "d3431e29cc00c2a1c6704e601d4371dbf24f6a31" + "reference": "b2db0d8246a865c659f93199f90f5fc2cd2f3cd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/d3431e29cc00c2a1c6704e601d4371dbf24f6a31", - "reference": "d3431e29cc00c2a1c6704e601d4371dbf24f6a31", + "url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/b2db0d8246a865c659f93199f90f5fc2cd2f3cd8", + "reference": "b2db0d8246a865c659f93199f90f5fc2cd2f3cd8", "shasum": "" }, "require": { - "php": "^7.0 || ^5.6", + "php": "^5.5 || ^7.0", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "require-dev": { - "phpunit/phpunit": "^6.0.8 || ^5.7.15", + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", "zendframework/zend-cache": "^2.6.1", - "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-config": "^2.6", "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", "zendframework/zend-filter": "^2.6.1", @@ -3985,39 +3795,44 @@ "i18n", "zf2" ], - "time": "2017-05-17T17:00:12+00:00" + "time": "2016-06-07T21:08:30+00:00" }, { "name": "zendframework/zend-json", - "version": "3.1.0", + "version": "2.6.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-json.git", - "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c" + "reference": "4c8705dbe4ad7d7e51b2876c5b9eea0ef916ba28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-json/zipball/4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", - "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", + "url": "https://api.github.com/repos/zendframework/zend-json/zipball/4c8705dbe4ad7d7e51b2876c5b9eea0ef916ba28", + "reference": "4c8705dbe4ad7d7e51b2876c5b9eea0ef916ba28", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^5.5 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^5.7.23 || ^6.4.3", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-stdlib": "^2.7.7 || ^3.1" + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-http": "^2.5.4", + "zendframework/zend-server": "^2.6.1", + "zendframework/zend-stdlib": "^2.5 || ^3.0", + "zendframework/zendxml": "^1.0.2" }, "suggest": { - "zendframework/zend-json-server": "For implementing JSON-RPC servers", - "zendframework/zend-xml2json": "For converting XML documents to JSON" + "zendframework/zend-http": "Zend\\Http component, required to use Zend\\Json\\Server", + "zendframework/zend-server": "Zend\\Server component, required to use Zend\\Json\\Server", + "zendframework/zend-stdlib": "Zend\\Stdlib component, for use with caching Zend\\Json\\Server responses", + "zendframework/zendxml": "To support Zend\\Json\\Json::fromXml() usage" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev", - "dev-develop": "3.2.x-dev" + "dev-master": "2.6-dev", + "dev-develop": "2.7-dev" } }, "autoload": { @@ -4030,48 +3845,47 @@ "BSD-3-Clause" ], "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP", + "homepage": "https://github.com/zendframework/zend-json", "keywords": [ - "ZendFramework", "json", - "zf" + "zf2" ], - "time": "2018-01-04T17:51:34+00:00" + "time": "2016-02-04T21:20:26+00:00" }, { "name": "zendframework/zend-serializer", - "version": "2.8.1", + "version": "2.7.2", "source": { "type": "git", "url": "https://github.com/zendframework/zend-serializer.git", - "reference": "7ac42b9a47e9cb23895173a3096bc3b3fb7ac580" + "reference": "95385c2342fc335d5164eb95ac3ca230aa51223b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/7ac42b9a47e9cb23895173a3096bc3b3fb7ac580", - "reference": "7ac42b9a47e9cb23895173a3096bc3b3fb7ac580", + "url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/95385c2342fc335d5164eb95ac3ca230aa51223b", + "reference": "95385c2342fc335d5164eb95ac3ca230aa51223b", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0", - "zendframework/zend-json": "^2.5 || ^3.0", + "php": "^5.5 || ^7.0", + "zendframework/zend-json": "^2.5", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "require-dev": { - "doctrine/instantiator": "1.0.*", - "phpunit/phpunit": "^5.5", - "zendframework/zend-coding-standard": "~1.0.0", + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "^4.5", "zendframework/zend-math": "^2.6", "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" }, "suggest": { - "zendframework/zend-math": "(^2.6 || ^3.0) To support Python Pickle serialization", - "zendframework/zend-servicemanager": "(^2.7.5 || ^3.0.3) To support plugin manager support" + "zendframework/zend-math": "(^2.6) To support Python Pickle serialization", + "zendframework/zend-servicemanager": "To support plugin manager support" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev", - "dev-develop": "2.9-dev" + "dev-master": "2.7-dev", + "dev-develop": "2.8-dev" }, "zf": { "component": "Zend\\Serializer", @@ -4093,7 +3907,7 @@ "serializer", "zf2" ], - "time": "2017-11-20T22:21:04+00:00" + "time": "2016-05-11T16:05:56+00:00" }, { "name": "zendframework/zend-servicemanager", From 4727062588bdd0169648873edcd3b628f7931b87 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Tue, 23 Jan 2018 11:53:06 -0800 Subject: [PATCH 26/30] fix 1.0 documentation link --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3ec616bd2..064e6e159 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ Contributing to the LaunchDarkly SDK for PHP ================================================ -We encourage pull-requests and other contributions from the community. We've also published an [SDK contributor's guide](http://docs.launchdarkly.com/v1.0/docs/sdk-contributors-guide) that provides a detailed explanation of how our SDKs work. \ No newline at end of file +We encourage pull-requests and other contributions from the community. We've also published an [SDK contributor's guide](http://docs.launchdarkly.com/docs/sdk-contributors-guide) that provides a detailed explanation of how our SDKs work. \ No newline at end of file From 330d42281d2b31b463f8d062b50df107eb76299a Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 2 Feb 2018 16:09:21 -0800 Subject: [PATCH 27/30] remove 3rd-party semver dependency, substitute our own semver implementation --- composer.json | 1 - composer.lock | 518 +++++++++++++++++---------- src/LaunchDarkly/Operators.php | 28 +- src/LaunchDarkly/SemanticVersion.php | 122 +++++++ tests/SemanticVersionTest.php | 223 ++++++++++++ 5 files changed, 676 insertions(+), 216 deletions(-) create mode 100644 src/LaunchDarkly/SemanticVersion.php create mode 100644 tests/SemanticVersionTest.php diff --git a/composer.json b/composer.json index 5e8d0dd98..3bd37a5f7 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,6 @@ } ], "require": { - "herrera-io/version": "^1.1.1", "monolog/monolog": "^1.6", "php": ">=5.5", "psr/log": "^1.0" diff --git a/composer.lock b/composer.lock index 6e8ca4634..89835076d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,60 +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" ], - "content-hash": "cd500f316e5cb4678769aa44fd67ff5e", + "content-hash": "ad2c6c29c2c748655900711de6dba807", "packages": [ - { - "name": "herrera-io/version", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/kherge-abandoned/php-version.git", - "reference": "d39d9642b92a04d8b8a28b871b797a35a2545e85" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kherge-abandoned/php-version/zipball/d39d9642b92a04d8b8a28b871b797a35a2545e85", - "reference": "d39d9642b92a04d8b8a28b871b797a35a2545e85", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "herrera-io/phpunit-test-case": "1.*", - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-0": { - "Herrera\\Version": "src/lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kevin Herrera", - "email": "kevin@herrera.io", - "homepage": "http://kevin.herrera.io" - } - ], - "description": "A library for creating, editing, and comparing semantic versioning numbers.", - "homepage": "http://github.com/herrera-io/php-version", - "keywords": [ - "semantic", - "version" - ], - "abandoned": true, - "time": "2014-05-27T05:29:25+00:00" - }, { "name": "monolog/monolog", "version": "1.23.0", @@ -336,35 +284,35 @@ }, { "name": "doctrine/annotations", - "version": "v1.2.7", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", - "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": ">=5.3.2" + "php": "^5.6 || ^7.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "4.*" + "phpunit/phpunit": "^5.7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Annotations\\": "lib/" + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" } }, "notification-url": "https://packagist.org/downloads/", @@ -400,7 +348,7 @@ "docblock", "parser" ], - "time": "2015-08-31T12:32:49+00:00" + "time": "2017-02-24T16:22:25+00:00" }, { "name": "doctrine/instantiator", @@ -1213,6 +1161,51 @@ "abandoned": true, "time": "2012-08-16T17:13:03+00:00" }, + { + "name": "myclabs/deep-copy", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-10-19T19:58:43+00:00" + }, { "name": "nikic/php-parser", "version": "v1.4.1", @@ -1697,39 +1690,40 @@ }, { "name": "phpunit/php-code-coverage", - "version": "2.2.4", + "version": "3.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + "reference": "44cd8e3930e431658d1a5de7d282d5cb37837fd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/44cd8e3930e431658d1a5de7d282d5cb37837fd5", + "reference": "44cd8e3930e431658d1a5de7d282d5cb37837fd5", "shasum": "" }, "require": { - "php": ">=5.3.3", + "php": "^5.6 || ^7.0", "phpunit/php-file-iterator": "~1.3", "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", + "phpunit/php-token-stream": "^1.4.2", + "sebastian/code-unit-reverse-lookup": "~1.0", "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" + "sebastian/version": "~1.0|~2.0" }, "require-dev": { "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" + "phpunit/phpunit": "~5" }, "suggest": { "ext-dom": "*", - "ext-xdebug": ">=2.2.1", + "ext-xdebug": ">=2.4.0", "ext-xmlwriter": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2.x-dev" + "dev-master": "3.3.x-dev" } }, "autoload": { @@ -1755,7 +1749,7 @@ "testing", "xunit" ], - "time": "2015-10-06T15:47:00+00:00" + "time": "2016-05-27T16:24:29+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1945,16 +1939,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.8.36", + "version": "5.3.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" + "reference": "08c513bfcab57f3dd72f5214c1c3940439fae7fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/08c513bfcab57f3dd72f5214c1c3940439fae7fe", + "reference": "08c513bfcab57f3dd72f5214c1c3940439fae7fe", "shasum": "" }, "require": { @@ -1963,19 +1957,22 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", - "php": ">=5.3.3", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", + "phpunit/php-code-coverage": ">=3.3.0,<4.0.0", "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.2.2", + "phpunit/phpunit-mock-objects": ">=3.1.0,<3.2.0", + "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", + "sebastian/object-enumerator": "~1.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "~1.0|~2.0", "symfony/yaml": "~2.1|~3.0" }, "suggest": { @@ -1987,7 +1984,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.8.x-dev" + "dev-master": "5.3.x-dev" } }, "autoload": { @@ -2013,30 +2010,30 @@ "testing", "xunit" ], - "time": "2017-06-21T08:07:12+00:00" + "time": "2016-06-03T09:42:56+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", + "version": "3.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + "reference": "151c96874bff6fe61a25039df60e776613a61489" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/151c96874bff6fe61a25039df60e776613a61489", + "reference": "151c96874bff6fe61a25039df60e776613a61489", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", + "php": ">=5.6", "phpunit/php-text-template": "~1.2", "sebastian/exporter": "~1.2" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "~5" }, "suggest": { "ext-soap": "*" @@ -2044,7 +2041,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -2069,7 +2066,7 @@ "mock", "xunit" ], - "time": "2015-10-02T06:51:40+00:00" + "time": "2016-04-20T14:39:26+00:00" }, { "name": "pimple/pimple", @@ -2266,6 +2263,51 @@ ], "time": "2016-08-06T14:39:51+00:00" }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, { "name": "sebastian/comparator", "version": "1.2.4", @@ -2550,6 +2592,52 @@ ], "time": "2015-10-12T03:26:01+00:00" }, + { + "name": "sebastian/object-enumerator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", + "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2016-01-28T13:25:10+00:00" + }, { "name": "sebastian/recursion-context", "version": "1.0.5", @@ -2603,21 +2691,71 @@ "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "time": "2016-10-03T07:41:43+00:00" }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, { "name": "sebastian/version", - "version": "1.0.6", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", "shasum": "" }, + "require": { + "php": ">=5.6" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -2636,20 +2774,20 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21T13:59:46+00:00" + "time": "2016-10-03T07:35:21+00:00" }, { "name": "seld/jsonlint", - "version": "1.7.0", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "9b355654ea99460397b89c132b5c1087b6bf4473" + "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9b355654ea99460397b89c132b5c1087b6bf4473", - "reference": "9b355654ea99460397b89c132b5c1087b6bf4473", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/d15f59a67ff805a44c50ea0516d2341740f81a38", + "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38", "shasum": "" }, "require": { @@ -2685,20 +2823,20 @@ "parser", "validator" ], - "time": "2018-01-03T12:13:57+00:00" + "time": "2018-01-24T12:46:19+00:00" }, { "name": "symfony/config", - "version": "v2.8.33", + "version": "v2.8.34", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "705d1687222c08deabac8993ec2e04ad1a422c52" + "reference": "17605ff58313d9fe94e507620a399721fc347b6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/705d1687222c08deabac8993ec2e04ad1a422c52", - "reference": "705d1687222c08deabac8993ec2e04ad1a422c52", + "url": "https://api.github.com/repos/symfony/config/zipball/17605ff58313d9fe94e507620a399721fc347b6d", + "reference": "17605ff58313d9fe94e507620a399721fc347b6d", "shasum": "" }, "require": { @@ -2741,20 +2879,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:36:31+00:00" + "time": "2018-01-21T19:03:25+00:00" }, { "name": "symfony/console", - "version": "v2.8.33", + "version": "v2.8.34", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe" + "reference": "162ca7d0ea597599967aa63b23418e747da0896b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe", - "reference": "a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe", + "url": "https://api.github.com/repos/symfony/console/zipball/162ca7d0ea597599967aa63b23418e747da0896b", + "reference": "162ca7d0ea597599967aa63b23418e747da0896b", "shasum": "" }, "require": { @@ -2802,7 +2940,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:36:31+00:00" + "time": "2018-01-29T08:54:45+00:00" }, { "name": "symfony/debug", @@ -2863,7 +3001,7 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.33", + "version": "v2.8.34", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -2972,16 +3110,16 @@ }, { "name": "symfony/finder", - "version": "v2.8.33", + "version": "v2.8.34", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "cb2ce50366dd3168f7b06135ffee0a5e35713ce8" + "reference": "9786ccb6a1f94a89ae18fc6a1b68de1f070823ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/cb2ce50366dd3168f7b06135ffee0a5e35713ce8", - "reference": "cb2ce50366dd3168f7b06135ffee0a5e35713ce8", + "url": "https://api.github.com/repos/symfony/finder/zipball/9786ccb6a1f94a89ae18fc6a1b68de1f070823ed", + "reference": "9786ccb6a1f94a89ae18fc6a1b68de1f070823ed", "shasum": "" }, "require": { @@ -3017,20 +3155,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:36:31+00:00" + "time": "2018-01-29T08:54:45+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.6.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", - "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b", + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b", "shasum": "" }, "require": { @@ -3042,7 +3180,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -3076,20 +3214,20 @@ "portable", "shim" ], - "time": "2017-10-11T12:05:26+00:00" + "time": "2018-01-30T19:27:44+00:00" }, { "name": "symfony/process", - "version": "v2.8.33", + "version": "v2.8.34", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "ea3226daa3c6789efa39570bfc6e5d55f7561a0a" + "reference": "905efe90024caa75a2fc93f54e14b26f2a099d96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/ea3226daa3c6789efa39570bfc6e5d55f7561a0a", - "reference": "ea3226daa3c6789efa39570bfc6e5d55f7561a0a", + "url": "https://api.github.com/repos/symfony/process/zipball/905efe90024caa75a2fc93f54e14b26f2a099d96", + "reference": "905efe90024caa75a2fc93f54e14b26f2a099d96", "shasum": "" }, "require": { @@ -3125,11 +3263,11 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:36:31+00:00" + "time": "2018-01-29T08:54:45+00:00" }, { "name": "symfony/stopwatch", - "version": "v2.8.33", + "version": "v2.8.34", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -3242,16 +3380,16 @@ }, { "name": "symfony/validator", - "version": "v2.8.33", + "version": "v2.8.34", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "e6da867bf86ba5009381d59718071329359ddbff" + "reference": "71f4e46ff4ca3c8fee09cc1a3a1b90a06cde5e2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/e6da867bf86ba5009381d59718071329359ddbff", - "reference": "e6da867bf86ba5009381d59718071329359ddbff", + "url": "https://api.github.com/repos/symfony/validator/zipball/71f4e46ff4ca3c8fee09cc1a3a1b90a06cde5e2a", + "reference": "71f4e46ff4ca3c8fee09cc1a3a1b90a06cde5e2a", "shasum": "" }, "require": { @@ -3311,20 +3449,20 @@ ], "description": "Symfony Validator Component", "homepage": "https://symfony.com", - "time": "2018-01-03T17:12:09+00:00" + "time": "2018-01-29T08:54:45+00:00" }, { "name": "symfony/yaml", - "version": "v3.3.15", + "version": "v3.3.16", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "7c80d81b5805589be151b85b0df785f0dc3269cf" + "reference": "af615970e265543a26ee712c958404eb9b7ac93d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/7c80d81b5805589be151b85b0df785f0dc3269cf", - "reference": "7c80d81b5805589be151b85b0df785f0dc3269cf", + "url": "https://api.github.com/repos/symfony/yaml/zipball/af615970e265543a26ee712c958404eb9b7ac93d", + "reference": "af615970e265543a26ee712c958404eb9b7ac93d", "shasum": "" }, "require": { @@ -3366,7 +3504,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:37:11+00:00" + "time": "2018-01-20T15:04:53+00:00" }, { "name": "twig/twig", @@ -3560,26 +3698,26 @@ }, { "name": "zendframework/zend-eventmanager", - "version": "3.0.1", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-eventmanager.git", - "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e" + "reference": "9d72db10ceb6e42fb92350c0cb54460da61bd79c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/5c80bdee0e952be112dcec0968bad770082c3a6e", - "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e", + "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/9d72db10ceb6e42fb92350c0cb54460da61bd79c", + "reference": "9d72db10ceb6e42fb92350c0cb54460da61bd79c", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0" + "php": "^5.6 || ^7.0" }, "require-dev": { "athletic/athletic": "^0.1", "container-interop/container-interop": "^1.1.0", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "^2.0", + "phpunit/phpunit": "^6.0.7 || ^5.7.14", + "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-stdlib": "^2.7.3 || ^3.0" }, "suggest": { @@ -3589,8 +3727,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev", - "dev-develop": "3.1-dev" + "dev-master": "3.2-dev", + "dev-develop": "3.3-dev" } }, "autoload": { @@ -3610,7 +3748,7 @@ "events", "zf2" ], - "time": "2016-02-18T20:53:00+00:00" + "time": "2017-07-11T19:17:22+00:00" }, { "name": "zendframework/zend-filter", @@ -3732,26 +3870,26 @@ }, { "name": "zendframework/zend-i18n", - "version": "2.7.3", + "version": "2.7.4", "source": { "type": "git", "url": "https://github.com/zendframework/zend-i18n.git", - "reference": "b2db0d8246a865c659f93199f90f5fc2cd2f3cd8" + "reference": "d3431e29cc00c2a1c6704e601d4371dbf24f6a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/b2db0d8246a865c659f93199f90f5fc2cd2f3cd8", - "reference": "b2db0d8246a865c659f93199f90f5fc2cd2f3cd8", + "url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/d3431e29cc00c2a1c6704e601d4371dbf24f6a31", + "reference": "d3431e29cc00c2a1c6704e601d4371dbf24f6a31", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", + "php": "^7.0 || ^5.6", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "require-dev": { - "fabpot/php-cs-fixer": "1.7.*", - "phpunit/phpunit": "~4.0", + "phpunit/phpunit": "^6.0.8 || ^5.7.15", "zendframework/zend-cache": "^2.6.1", + "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-config": "^2.6", "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", "zendframework/zend-filter": "^2.6.1", @@ -3795,44 +3933,39 @@ "i18n", "zf2" ], - "time": "2016-06-07T21:08:30+00:00" + "time": "2017-05-17T17:00:12+00:00" }, { "name": "zendframework/zend-json", - "version": "2.6.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-json.git", - "reference": "4c8705dbe4ad7d7e51b2876c5b9eea0ef916ba28" + "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-json/zipball/4c8705dbe4ad7d7e51b2876c5b9eea0ef916ba28", - "reference": "4c8705dbe4ad7d7e51b2876c5b9eea0ef916ba28", + "url": "https://api.github.com/repos/zendframework/zend-json/zipball/4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", + "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0" + "php": "^5.6 || ^7.0" }, "require-dev": { - "fabpot/php-cs-fixer": "1.7.*", - "phpunit/phpunit": "~4.0", - "zendframework/zend-http": "^2.5.4", - "zendframework/zend-server": "^2.6.1", - "zendframework/zend-stdlib": "^2.5 || ^3.0", - "zendframework/zendxml": "^1.0.2" + "phpunit/phpunit": "^5.7.23 || ^6.4.3", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-stdlib": "^2.7.7 || ^3.1" }, "suggest": { - "zendframework/zend-http": "Zend\\Http component, required to use Zend\\Json\\Server", - "zendframework/zend-server": "Zend\\Server component, required to use Zend\\Json\\Server", - "zendframework/zend-stdlib": "Zend\\Stdlib component, for use with caching Zend\\Json\\Server responses", - "zendframework/zendxml": "To support Zend\\Json\\Json::fromXml() usage" + "zendframework/zend-json-server": "For implementing JSON-RPC servers", + "zendframework/zend-xml2json": "For converting XML documents to JSON" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev", - "dev-develop": "2.7-dev" + "dev-master": "3.1.x-dev", + "dev-develop": "3.2.x-dev" } }, "autoload": { @@ -3845,47 +3978,48 @@ "BSD-3-Clause" ], "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP", - "homepage": "https://github.com/zendframework/zend-json", "keywords": [ + "ZendFramework", "json", - "zf2" + "zf" ], - "time": "2016-02-04T21:20:26+00:00" + "time": "2018-01-04T17:51:34+00:00" }, { "name": "zendframework/zend-serializer", - "version": "2.7.2", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-serializer.git", - "reference": "95385c2342fc335d5164eb95ac3ca230aa51223b" + "reference": "7ac42b9a47e9cb23895173a3096bc3b3fb7ac580" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/95385c2342fc335d5164eb95ac3ca230aa51223b", - "reference": "95385c2342fc335d5164eb95ac3ca230aa51223b", + "url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/7ac42b9a47e9cb23895173a3096bc3b3fb7ac580", + "reference": "7ac42b9a47e9cb23895173a3096bc3b3fb7ac580", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "zendframework/zend-json": "^2.5", + "php": "^5.6 || ^7.0", + "zendframework/zend-json": "^2.5 || ^3.0", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "require-dev": { - "fabpot/php-cs-fixer": "1.7.*", - "phpunit/phpunit": "^4.5", + "doctrine/instantiator": "1.0.*", + "phpunit/phpunit": "^5.5", + "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-math": "^2.6", "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" }, "suggest": { - "zendframework/zend-math": "(^2.6) To support Python Pickle serialization", - "zendframework/zend-servicemanager": "To support plugin manager support" + "zendframework/zend-math": "(^2.6 || ^3.0) To support Python Pickle serialization", + "zendframework/zend-servicemanager": "(^2.7.5 || ^3.0.3) To support plugin manager support" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev", - "dev-develop": "2.8-dev" + "dev-master": "2.8-dev", + "dev-develop": "2.9-dev" }, "zf": { "component": "Zend\\Serializer", @@ -3907,7 +4041,7 @@ "serializer", "zf2" ], - "time": "2016-05-11T16:05:56+00:00" + "time": "2017-11-20T22:21:04+00:00" }, { "name": "zendframework/zend-servicemanager", diff --git a/src/LaunchDarkly/Operators.php b/src/LaunchDarkly/Operators.php index 4df16bae3..706af4fed 100644 --- a/src/LaunchDarkly/Operators.php +++ b/src/LaunchDarkly/Operators.php @@ -1,9 +1,6 @@ comparePrecedence($cVer) == 0; case "semVerLessThan": $uVer = self::parseSemVer($u); $cVer = self::parseSemVer($c); - return ($uVer != null) && ($cVer != null) && Comparator::compareTo($uVer, $cVer) < 0; + return ($uVer != null) && ($cVer != null) && $uVer->comparePrecedence($cVer) < 0; case "semVerGreaterThan": $uVer = self::parseSemVer($u); $cVer = self::parseSemVer($c); - return ($uVer != null) && ($cVer != null) && Comparator::compareTo($uVer, $cVer) > 0; + return ($uVer != null) && ($cVer != null) && $uVer->comparePrecedence($cVer) > 0; } } catch (Exception $ignored) { } @@ -142,23 +139,8 @@ public static function parseTime($in) */ public static function parseSemVer($in) { try { - return Parser::toVersion($in); - } catch (InvalidStringRepresentationException $e) { - // If minor or patch version was omitted, or both, normalize the version - // by adding zeroes in their place. - if (preg_match(Operators::VERSION_NUMBERS_REGEX, $in, $matches)) { - $transformed = $matches[0]; - for ($i = 1; $i <= 3; $i++) { - if ($i > count($matches)) { - $transformed .= '.0'; - } - } - $transformed .= substr($in, strlen($matches[0])); - try { - return Parser::toVersion($transformed); - } catch (InvalidStringRepresentationException $e) { - } - } + return SemanticVersion::parse($in, true); + } catch (\InvalidArgumentException $e) { return null; } } diff --git a/src/LaunchDarkly/SemanticVersion.php b/src/LaunchDarkly/SemanticVersion.php new file mode 100644 index 000000000..12583d7fc --- /dev/null +++ b/src/LaunchDarkly/SemanticVersion.php @@ -0,0 +1,122 @@ +0|[1-9]\d*)(\.(?0|[1-9]\d*))?(\.(?0|[1-9]\d*))?' . + '(\-(?[0-9A-Za-z\-\.]+))?(\+(?[0-9A-Za-z\-\.]+))?$/'; + + /** @var int */ + public $major; + /** @var int */ + public $minor; + /** @var int */ + public $patch; + /** @var string */ + public $prerelease; + /** @var string */ + public $build; + + public function __construct($major, $minor, $patch, $prerelease, $build) + { + $this->major = $major; + $this->minor = $minor; + $this->patch = $patch; + $this->prerelease = $prerelease; + $this->build = $build; + } + + /** + * Attempts to parse a string as a semantic version. + * @param $input string the input string + * @param $loose boolean true if minor and patch versions can be omitted + * @return a SemanticVersion object + * @throws InvalidArgumentException if the string is not in an acceptable format + */ + public static function parse($input, $loose = false) + { + if (!preg_match(self::$REGEX, $input, $matches)) { + throw new \InvalidArgumentException("not a valid semantic version"); + } + $major = intval($matches['major']); + if (!$loose && (!array_key_exists('minor', $matches) || !array_key_exists('patch', $matches))) { + throw new \InvalidArgumentException("not a valid semantic version: minor and patch versions are required"); + } + $minor = array_key_exists('minor', $matches) ? intval($matches['minor']) : 0; + $patch = array_key_exists('patch', $matches) ? intval($matches['patch']) : 0; + $prerelease = array_key_exists('prerel', $matches) ? $matches['prerel'] : ''; + $build = array_key_exists('build', $matches) ? $matches['build'] : ''; + return new SemanticVersion($major, $minor, $patch, $prerelease, $build); + } + + /** + * Compares this version to another version using Semantic Versioning precedence rules. + * @param $other a SemanticVersion object + * @return -1 if this version has lower precedence than the other version; 1 if this version + * has higher precedence; zero if the two have equal precedence + */ + public function comparePrecedence($other) + { + if ($this->major != $other->major) { + return ($this->major < $other->major) ? -1 : 1; + } + if ($this->minor != $other->minor) { + return ($this->minor < $other->minor) ? -1 : 1; + } + if ($this->patch != $other->patch) { + return ($this->patch < $other->patch) ? -1 : 1; + } + if ($this->prerelease != $other->prerelease) { + // *no* prerelease component always has a higher precedence than *any* prerelease component + if ($this->prerelease == '') { + return 1; + } + if ($other->prerelease == '') { + return -1; + } + return self::compareIdentifiers(explode('.', $this->prerelease), explode('.', $other->prerelease)); + } + // build metadata is always ignored in precedence comparison + return 0; + } + + private static function compareIdentifiers($ids1, $ids2) + { + for ($i = 0; ; $i++) { + if ($i >= count($ids1)) { + // x.y is always less than x.y.z + return ($i >= count($ids2)) ? 0 : -1; + } + if ($i >= count($ids2)) { + return 1; + } + $v1 = $ids1[$i]; + $v2 = $ids2[$i]; + // each sub-identifier is compared numerically if both are numeric; if both are non-numeric, + // they're compared as strings; otherwise, the numeric one is the lesser one + $isNum1 = is_numeric($v1); + $isNum2 = is_numeric($v2); + if ($isNum1 && $isNum2) { + $n1 = intval($v1); + $n2 = intval($v2); + $d = ($n1 == $n2) ? 0 : (($n1 < $n2) ? -1 : 1); + } else { + if ($isNum1 || $isNum2) { + $d = $isNum1 ? -1 : 1; + } else { + $d = ($v1 == $v2) ? 0 : (($v1 < $v2) ? -1 : 1); + } + } + if ($d != 0) { + return $d; + } + } + } +} diff --git a/tests/SemanticVersionTest.php b/tests/SemanticVersionTest.php new file mode 100644 index 000000000..6712fb496 --- /dev/null +++ b/tests/SemanticVersionTest.php @@ -0,0 +1,223 @@ +assertEquals(2, $sv->major); + $this->assertEquals(3, $sv->minor); + $this->assertEquals(4, $sv->patch); + $this->assertEquals('', $sv->prerelease); + $this->assertEquals('', $sv->build); + } + + public function testCanParseVersionWithPrerelease() + { + $sv = SemanticVersion::parse('2.3.4-beta1.rc2'); + $this->assertEquals(2, $sv->major); + $this->assertEquals(3, $sv->minor); + $this->assertEquals(4, $sv->patch); + $this->assertEquals('beta1.rc2', $sv->prerelease); + $this->assertEquals('', $sv->build); + } + + public function testCanParseVersionWithBuild() + { + $sv = SemanticVersion::parse('2.3.4+build2.4'); + $this->assertEquals(2, $sv->major); + $this->assertEquals(3, $sv->minor); + $this->assertEquals(4, $sv->patch); + $this->assertEquals('', $sv->prerelease); + $this->assertEquals('build2.4', $sv->build); + } + + public function testCanParseVersionWithPrereleaseAndBuild() + { + $sv = SemanticVersion::parse('2.3.4-beta1.rc2+build2.4'); + $this->assertEquals(2, $sv->major); + $this->assertEquals(3, $sv->minor); + $this->assertEquals(4, $sv->patch); + $this->assertEquals('beta1.rc2', $sv->prerelease); + $this->assertEquals('build2.4', $sv->build); + } + + public function testLeadingZeroNotAllowedInMajor() + { + $this->expectException(\InvalidArgumentException::class); + SemanticVersion::parse('02.3.4'); + } + + public function testLeadingZeroNotAllowedInMinor() + { + $this->expectException(\InvalidArgumentException::class); + SemanticVersion::parse('2.03.4'); + } + + public function testLeadingZeroNotAllowedInPatch() + { + $this->expectException(\InvalidArgumentException::class); + SemanticVersion::parse('2.3.04'); + } + + public function testZeroByItselfIsAllowed() + { + $sv = SemanticVersion::parse('0.3.4'); + $this->assertEquals(0, $sv->major); + + $sv = SemanticVersion::parse('2.0.4'); + $this->assertEquals(0, $sv->minor); + + $sv = SemanticVersion::parse('2.3.0'); + $this->assertEquals(0, $sv->patch); + } + + public function testCanParseVersionWithMajorOnlyInLooseMode() + { + $sv = SemanticVersion::parse('2', true); + $this->assertEquals(2, $sv->major); + $this->assertEquals(0, $sv->minor); + $this->assertEquals(0, $sv->patch); + $this->assertEquals('', $sv->prerelease); + $this->assertEquals('', $sv->build); + } + + public function testCanParseVersionWithMajorAndMinorOnlyInLooseMode() + { + $sv = SemanticVersion::parse('2.3', true); + $this->assertEquals(2, $sv->major); + $this->assertEquals(3, $sv->minor); + $this->assertEquals(0, $sv->patch); + $this->assertEquals('', $sv->prerelease); + $this->assertEquals('', $sv->build); + } + + public function testCanParseVersionWithMajorAndPrereleaseOnlyInLooseMode() + { + $sv = SemanticVersion::parse('2-beta1', true); + $this->assertEquals(2, $sv->major); + $this->assertEquals(0, $sv->minor); + $this->assertEquals(0, $sv->patch); + $this->assertEquals('beta1', $sv->prerelease); + $this->assertEquals('', $sv->build); + } + + public function testCanParseVersionWithMajorMinorAndPrereleaseOnlyInLooseMode() + { + $sv = SemanticVersion::parse('2.3-beta1', true); + $this->assertEquals(2, $sv->major); + $this->assertEquals(3, $sv->minor); + $this->assertEquals(0, $sv->patch); + $this->assertEquals('beta1', $sv->prerelease); + $this->assertEquals('', $sv->build); + } + + public function testCanParseVersionWithMajorAndBuildOnlyInLooseMode() + { + $sv = SemanticVersion::parse('2+build1', true); + $this->assertEquals(2, $sv->major); + $this->assertEquals(0, $sv->minor); + $this->assertEquals(0, $sv->patch); + $this->assertEquals('', $sv->prerelease); + $this->assertEquals('build1', $sv->build); + } + + public function testCanParseVersionWithMajorMinorAndBuildOnlyInLooseMode() + { + $sv = SemanticVersion::parse('2.3+build1', true); + $this->assertEquals(2, $sv->major); + $this->assertEquals(3, $sv->minor); + $this->assertEquals(0, $sv->patch); + $this->assertEquals('', $sv->prerelease); + $this->assertEquals('build1', $sv->build); + } + + public function testCannotParseVersionWithMajorOnlyByDefault() + { + $this->expectException(\InvalidArgumentException::class); + SemanticVersion::parse('2'); + } + + public function testCannotParseVersionWithMajorAndMinorOnlyByDefault() + { + $this->expectException(\InvalidArgumentException::class); + SemanticVersion::parse('2.3'); + } + + public function testEqualVersionsHaveEqualPrecedence() + { + $sv1 = SemanticVersion::parse('2.3.4-beta1'); + $sv2 = SemanticVersion::parse('2.3.4-beta1'); + $this->assertEquals(0, $sv1->comparePrecedence($sv2)); + $this->assertEquals(0, $sv2->comparePrecedence($sv1)); + } + + public function testLowerMajorVersionHasLowerPrecedence() + { + $sv1 = SemanticVersion::parse('1.3.4-beta1'); + $sv2 = SemanticVersion::parse('2.3.4-beta1'); + $this->assertEquals(-1, $sv1->comparePrecedence($sv2)); + $this->assertEquals(1, $sv2->comparePrecedence($sv1)); + } + + public function testLowerMinorVersionHasLowerPrecedence() + { + $sv1 = SemanticVersion::parse('2.2.4-beta1'); + $sv2 = SemanticVersion::parse('2.3.4-beta1'); + $this->assertEquals(-1, $sv1->comparePrecedence($sv2)); + $this->assertEquals(1, $sv2->comparePrecedence($sv1)); + } + + public function testLowerPatchVersionHasLowerPrecedence() + { + $sv1 = SemanticVersion::parse('2.3.3-beta1'); + $sv2 = SemanticVersion::parse('2.3.4-beta1'); + $this->assertEquals(-1, $sv1->comparePrecedence($sv2)); + $this->assertEquals(1, $sv2->comparePrecedence($sv1)); + } + + public function testPrereleaseVersionHasLowerPrecedenceThanRelease() + { + $sv1 = SemanticVersion::parse('2.3.4-beta1'); + $sv2 = SemanticVersion::parse('2.3.4'); + $this->assertEquals(-1, $sv1->comparePrecedence($sv2)); + $this->assertEquals(1, $sv2->comparePrecedence($sv1)); + } + + public function testShorterSubsetOfPrereleaseIdentifiersHasLowerPrecedence() + { + $sv1 = SemanticVersion::parse('2.3.4-beta1'); + $sv2 = SemanticVersion::parse('2.3.4-beta1.rc1'); + $this->assertEquals(-1, $sv1->comparePrecedence($sv2)); + $this->assertEquals(1, $sv2->comparePrecedence($sv1)); + } + + public function testNumericPrereleaseIdentifiersAreSortedNumerically() + { + $sv1 = SemanticVersion::parse('2.3.4-beta1.3'); + $sv2 = SemanticVersion::parse('2.3.4-beta1.23'); + $this->assertEquals(-1, $sv1->comparePrecedence($sv2)); + $this->assertEquals(1, $sv2->comparePrecedence($sv1)); + } + + public function testNonNumericPrereleaseIdentifiersAreSortedAsStrings() + { + $sv1 = SemanticVersion::parse('2.3.4-beta1.x3'); + $sv2 = SemanticVersion::parse('2.3.4-beta1.x23'); + $this->assertEquals(1, $sv1->comparePrecedence($sv2)); + $this->assertEquals(-1, $sv2->comparePrecedence($sv1)); + } + + public function testBuildIdentifierDoesNotAffectPrecedence() + { + $sv1 = SemanticVersion::parse('2.3.4-beta1+build1'); + $sv2 = SemanticVersion::parse('2.3.4-beta1+build2'); + $this->assertEquals(0, $sv1->comparePrecedence($sv2)); + $this->assertEquals(0, $sv2->comparePrecedence($sv1)); + } +} From 0cabb1bef38c19da997d56db0c23d5aeaa49ce59 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 2 Feb 2018 17:02:41 -0800 Subject: [PATCH 28/30] remove newer PHPUnit usage --- tests/SemanticVersionTest.php | 36 +++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/tests/SemanticVersionTest.php b/tests/SemanticVersionTest.php index 6712fb496..073169197 100644 --- a/tests/SemanticVersionTest.php +++ b/tests/SemanticVersionTest.php @@ -49,20 +49,30 @@ public function testCanParseVersionWithPrereleaseAndBuild() public function testLeadingZeroNotAllowedInMajor() { - $this->expectException(\InvalidArgumentException::class); - SemanticVersion::parse('02.3.4'); + try { + SemanticVersion::parse('02.3.4'); + $this->assertTrue(false, 'expected exception'); + // can't use expectException method because we must support older PHPUnit + } catch (\InvalidArgumentException $e) { + } } public function testLeadingZeroNotAllowedInMinor() { - $this->expectException(\InvalidArgumentException::class); - SemanticVersion::parse('2.03.4'); + try { + SemanticVersion::parse('2.03.4'); + $this->assertTrue(false, 'expected exception'); + } catch (\InvalidArgumentException $e) { + } } public function testLeadingZeroNotAllowedInPatch() { - $this->expectException(\InvalidArgumentException::class); - SemanticVersion::parse('2.3.04'); + try { + SemanticVersion::parse('2.3.04'); + $this->assertTrue(false, 'expected exception'); + } catch (\InvalidArgumentException $e) { + } } public function testZeroByItselfIsAllowed() @@ -139,14 +149,20 @@ public function testCanParseVersionWithMajorMinorAndBuildOnlyInLooseMode() public function testCannotParseVersionWithMajorOnlyByDefault() { - $this->expectException(\InvalidArgumentException::class); - SemanticVersion::parse('2'); + try { + SemanticVersion::parse('2'); + $this->assertTrue(false, 'expected exception'); + } catch (\InvalidArgumentException $e) { + } } public function testCannotParseVersionWithMajorAndMinorOnlyByDefault() { - $this->expectException(\InvalidArgumentException::class); - SemanticVersion::parse('2.3'); + try { + SemanticVersion::parse('2.3'); + $this->assertTrue(false, 'expected exception'); + } catch (\InvalidArgumentException $e) { + } } public function testEqualVersionsHaveEqualPrecedence() From ae300f506efa3f104c348d6b9a2bcd8abf32ade4 Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Fri, 2 Feb 2018 17:13:04 -0800 Subject: [PATCH 29/30] can't do computed property in older PHP --- src/LaunchDarkly/SemanticVersion.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LaunchDarkly/SemanticVersion.php b/src/LaunchDarkly/SemanticVersion.php index 12583d7fc..c828cccfc 100644 --- a/src/LaunchDarkly/SemanticVersion.php +++ b/src/LaunchDarkly/SemanticVersion.php @@ -10,8 +10,7 @@ */ class SemanticVersion { - private static $REGEX = '/^(?0|[1-9]\d*)(\.(?0|[1-9]\d*))?(\.(?0|[1-9]\d*))?' . - '(\-(?[0-9A-Za-z\-\.]+))?(\+(?[0-9A-Za-z\-\.]+))?$/'; + private static $REGEX = '/^(?0|[1-9]\d*)(\.(?0|[1-9]\d*))?(\.(?0|[1-9]\d*))?(\-(?[0-9A-Za-z\-\.]+))?(\+(?[0-9A-Za-z\-\.]+))?$/'; /** @var int */ public $major; From 95dea40cd79b30abab1e1bade37db9e14e5f961d Mon Sep 17 00:00:00 2001 From: Eli Bishop Date: Tue, 13 Feb 2018 11:42:29 -0800 Subject: [PATCH 30/30] version 2.5.0 --- CHANGELOG.md | 4 ++++ VERSION | 2 +- src/LaunchDarkly/LDClient.php | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4180a4f1c..8785f9d51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to the LaunchDarkly PHP SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org). +## [2.5.0] - 2018-02-13 +### Added +- Adds support for a future LaunchDarkly feature, coming soon: semantic version user attributes. + ## [2.4.0] - 2018-01-04 ### Added - Support for [private user attributes](https://docs.launchdarkly.com/docs/private-user-attributes). diff --git a/VERSION b/VERSION index 197c4d5c2..437459cd9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.0 +2.5.0 diff --git a/src/LaunchDarkly/LDClient.php b/src/LaunchDarkly/LDClient.php index 0902d271b..84bbe3354 100644 --- a/src/LaunchDarkly/LDClient.php +++ b/src/LaunchDarkly/LDClient.php @@ -19,7 +19,7 @@ class LDClient { const DEFAULT_BASE_URI = 'https://app.launchdarkly.com'; const DEFAULT_EVENTS_URI = 'https://events.launchdarkly.com'; - const VERSION = '2.4.0'; + const VERSION = '2.5.0'; /** @var string */ protected $_sdkKey;