├── .gitignore ├── bin └── phpunit ├── .htaccess ├── src ├── Controller │ ├── ControllerBase.php │ ├── LocaleController.php │ └── TranslationController.php ├── Entity │ ├── EntityAbstract.php │ ├── EntityInterface.php │ └── Translation.php ├── Repository │ ├── Translation.php │ └── RepositoryAbstract.php ├── Service │ └── Translation.php └── Library │ └── MongoDictionary.php ├── .travis.yml ├── tests ├── BaseTest.php └── Service │ └── TranslationServiceTest.php ├── composer.json ├── LICENSE ├── index.php ├── README.md └── composer.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | composer.phar -------------------------------------------------------------------------------- /bin/phpunit: -------------------------------------------------------------------------------- 1 | ../vendor/phpunit/phpunit/phpunit -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteCond %{REQUEST_FILENAME} !-f 3 | RewriteCond %{REQUEST_FILENAME} !-d 4 | RewriteCond %{REQUEST_FILENAME} !-l 5 | RewriteRule .* index.php [L,QSA] -------------------------------------------------------------------------------- /src/Controller/ControllerBase.php: -------------------------------------------------------------------------------- 1 | assertEquals($var, "Hello World"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Entity/EntityInterface.php: -------------------------------------------------------------------------------- 1 | =5.4.0", 18 | "bcosca/fatfree": "dev-master", 19 | "moss/locale": ">=1" 20 | }, 21 | "require-dev": { 22 | "phpunit/phpunit": "4.1.*" 23 | }, 24 | "config": { 25 | "bin-dir": "bin/" 26 | }, 27 | "autoload": { 28 | "psr-4": {"MicroTranslator\\": "src/"} 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Entity/Translation.php: -------------------------------------------------------------------------------- 1 | _id; 26 | } 27 | 28 | /** 29 | * Sets Document's ID 30 | * 31 | * @param $id 32 | * @return EntityInterface 33 | */ 34 | public function setId($id) 35 | { 36 | $this->_id = $id; 37 | } 38 | } -------------------------------------------------------------------------------- /src/Controller/LocaleController.php: -------------------------------------------------------------------------------- 1 | translationService = $translationService; 23 | } 24 | 25 | public function showAllAvailable() 26 | { 27 | $locales = $this->translationService->getAvailableLocales(); 28 | 29 | $count = count($locales); 30 | 31 | $result = [ 32 | 'items' => $locales, 33 | 'count' => $count 34 | ]; 35 | 36 | echo json_encode($result); 37 | 38 | return true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Marco Troisi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /src/Controller/TranslationController.php: -------------------------------------------------------------------------------- 1 | translationService = $translationService; 24 | } 25 | 26 | public function show($locale = "", $term = "") 27 | { 28 | if ($term != "") { 29 | $words = $this->translationService->show($locale, $term); 30 | } else { 31 | $words = $this->translationService->showAll(); 32 | } 33 | 34 | $count = $this->translationService->count($locale, $term); 35 | 36 | $result = [ 37 | 'items' => [$words], 38 | 'total' => $count 39 | ]; 40 | 41 | echo json_encode($result); 42 | 43 | return true; 44 | } 45 | 46 | /** 47 | * @param $word 48 | * @param $locale 49 | * @param $term 50 | * @return $this 51 | */ 52 | public function save($word, $locale, $term) 53 | { 54 | $translation = new Translation(); 55 | $translation->translation = $term; 56 | $translation->word = $word; 57 | $translation->locale = $locale; 58 | 59 | $criteria = [ 60 | 'word' => $word, 61 | 'locale' => $locale 62 | ]; 63 | 64 | $result = $this->translationService->update($criteria, $translation, ['upsert' => true]); 65 | 66 | echo json_encode((bool) $result['ok']); 67 | 68 | return true; 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Repository/RepositoryAbstract.php: -------------------------------------------------------------------------------- 1 | db = $db; 29 | } 30 | 31 | /** 32 | * @param EntityInterface $entity 33 | * @return array|bool 34 | */ 35 | public function save(EntityInterface $entity) 36 | { 37 | $collection = $this->collection; 38 | 39 | if ($entity->getId() == null) { 40 | $entity->setId(new \MongoId()); 41 | } 42 | 43 | return $this->db->$collection->save($entity); 44 | } 45 | 46 | public function update($criteria, EntityInterface $entity, $options) 47 | { 48 | $collection = $this->collection; 49 | 50 | $entityArray = get_object_vars($entity); 51 | unset($entityArray['_id']); 52 | 53 | return $this->db->$collection->update($criteria, $entityArray, $options); 54 | } 55 | 56 | public function find($query, $fields = []) 57 | { 58 | $collection = $this->collection; 59 | 60 | return $this->db->$collection->find($query, $fields); 61 | } 62 | 63 | public function distinct($field) 64 | { 65 | $collection = $this->collection; 66 | 67 | return $this->db->command(['distinct' => $collection, 'key' => $field]); 68 | } 69 | 70 | public function findOne($query, $fields = []) 71 | { 72 | $collection = $this->collection; 73 | 74 | return $this->db->$collection->findOne($query, $fields); 75 | } 76 | 77 | public function count($query) 78 | { 79 | $collection = $this->collection; 80 | 81 | return $this->db->$collection->count($query); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | selectDB('microtranslator'); 16 | 17 | $locale = (isset($_GET['locale'])) ? $_GET['locale'] : 'en_GB'; 18 | $mongoDictionary = new \MicroTranslator\Library\MongoDictionary($locale, $db, 'translations', 'word', 'translation'); 19 | $translator = new \Moss\Locale\Translator\Translator($locale, $mongoDictionary); 20 | 21 | /** 22 | * Translation Service 23 | */ 24 | $translationService = new \MicroTranslator\Service\Translation( 25 | new \MicroTranslator\Repository\Translation($db), 26 | $translator 27 | ); 28 | 29 | /** 30 | * Controllers 31 | */ 32 | $localeController = new \MicroTranslator\Controller\LocaleController($translationService); 33 | $translationController = new \MicroTranslator\Controller\TranslationController($translationService); 34 | 35 | /** 36 | * Routes 37 | */ 38 | 39 | // Home 40 | $f3->route('GET /', 41 | function() use ($translationService) { 42 | echo 'MicroTranslator'; 43 | } 44 | ); 45 | 46 | // Gets All Available Locales 47 | $f3->route('GET /locale', 48 | function() use ($localeController) { 49 | return $localeController->showAllAvailable(); 50 | } 51 | ); 52 | 53 | // Gets All Terms 54 | $f3->route('GET /translation', 55 | function($f3, $params) use ($translationController) { 56 | return $translationController->show(); 57 | } 58 | ); 59 | 60 | // Gets or inserts/updates a Term for a specific Locale 61 | $f3->route('GET|POST /translation/@word', 62 | function($f3, $params) use ($translationController, $locale) { 63 | 64 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 65 | $translation = $f3->get('POST.translation'); 66 | $word = $params['word']; 67 | 68 | return $translationController->save($word, $locale, $translation); 69 | } 70 | 71 | return $translationController->show($locale, $params['word']); 72 | } 73 | ); 74 | 75 | // Gets Untranslated Terms for a specific Locale 76 | 77 | /** 78 | * Run F3 Application 79 | */ 80 | $f3->run(); 81 | -------------------------------------------------------------------------------- /src/Service/Translation.php: -------------------------------------------------------------------------------- 1 | translationRepository = $translationRepository; 34 | $this->translator = $translator; 35 | } 36 | 37 | /** 38 | * @param TranslationEntity $entity 39 | * @return array|bool 40 | */ 41 | public function save(TranslationEntity $entity) 42 | { 43 | return $this->translationRepository->save($entity); 44 | } 45 | 46 | /** 47 | * @param $criteria 48 | * @param TranslationEntity $entity 49 | * @param $options 50 | * @return bool 51 | */ 52 | public function update($criteria, TranslationEntity $entity, $options) 53 | { 54 | return $this->translationRepository->update($criteria, $entity, $options); 55 | } 56 | 57 | /** 58 | * @return array 59 | */ 60 | public function getAvailableLocales() 61 | { 62 | $cursor = $this->translationRepository->distinct('locale'); 63 | 64 | if (!$cursor) { 65 | return $cursor; 66 | } 67 | 68 | $result = []; 69 | 70 | foreach ($cursor['values'] as $res) { 71 | $result[] = $res; 72 | } 73 | 74 | return $result; 75 | } 76 | 77 | /** 78 | * @param $locale 79 | * @param string $word 80 | * @return array 81 | */ 82 | public function show($locale, $word = "") 83 | { 84 | $search['locale'] = $locale; 85 | 86 | $result = [$word => $this->translator->trans($word)]; 87 | 88 | return $result; 89 | } 90 | 91 | /** 92 | * @return array 93 | */ 94 | public function showAll() 95 | { 96 | return $this->translator->dictionary()->getTranslations(); 97 | } 98 | 99 | /** 100 | * @param $locale 101 | * @param string $word 102 | * @return int 103 | */ 104 | public function count($locale = "", $word = "") 105 | { 106 | $search = []; 107 | 108 | if ($locale !== "") { 109 | $search['locale'] = $locale; 110 | } 111 | 112 | if ($word !== "") { 113 | $search['word'] = $word; 114 | } 115 | 116 | return $this->translationRepository->count($search); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /tests/Service/TranslationServiceTest.php: -------------------------------------------------------------------------------- 1 | translationRepository = $this->getMockBuilder('\MicroTranslator\Repository\Translation')->disableOriginalConstructor()->getMock(); 35 | $this->translator = $this->getMockBuilder('\Moss\Locale\Translator\Translator')->disableOriginalConstructor()->getMock(); 36 | 37 | $this->translationService = new Translation($this->translationRepository, $this->translator); 38 | } 39 | 40 | 41 | public function testSave() 42 | { 43 | $translationEntity = $this->getMock('\MicroTranslator\Entity\Translation'); 44 | 45 | $this->translationRepository->expects($this->once())->method('save')->with($translationEntity); 46 | 47 | $this->translationService->save($translationEntity); 48 | } 49 | 50 | public function testUpdate() 51 | { 52 | $translationEntity = $this->getMock('\MicroTranslator\Entity\Translation'); 53 | 54 | $criteria = ['_id' => 1]; 55 | $options = ['upsert' => true]; 56 | 57 | $this->translationRepository->expects($this->once())->method('update')->with($criteria, $translationEntity, $options); 58 | 59 | $this->translationService->update($criteria, $translationEntity, $options); 60 | } 61 | 62 | public function testGetAvailableLocales() 63 | { 64 | $expectedResult = ['de_DE']; 65 | 66 | $mongoResult = [ 67 | 'values' => ['de_DE'], 68 | 'stats' => [ 69 | 'n' => 2, 70 | 'nscanned' => 0, 71 | 'nscannedObjects' => 2, 72 | 'timems' => 0, 73 | 'planSummary' => 'COLLSCAN' 74 | ], 75 | 'ok' => 1 76 | ]; 77 | 78 | $this->translationRepository->expects($this->once())->method('distinct')->with('locale')->willReturn($mongoResult); 79 | 80 | $result = $this->translationService->getAvailableLocales(); 81 | 82 | $this->assertEquals($expectedResult, $result); 83 | } 84 | 85 | public function testShow() 86 | { 87 | $locale = 'de_DE'; 88 | $word = 'Good morning'; 89 | 90 | $this->translator->expects($this->once())->method('trans')->with($word)->willReturn('Guten morgen'); 91 | 92 | $result = $this->translationService->show($locale, $word); 93 | 94 | $this->assertEquals([$word => 'Guten morgen'], $result); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/Library/MongoDictionary.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | */ 9 | 10 | namespace MicroTranslator\Library; 11 | use Moss\Locale\Translator\DictionaryInterface; 12 | 13 | /** 14 | * Basic array dictionary 15 | * 16 | * @package Moss Locale 17 | * @author Michal Wachowski 18 | */ 19 | class MongoDictionary implements DictionaryInterface 20 | { 21 | protected $locale; 22 | protected $translations = []; 23 | /** 24 | * @var \MongoDb 25 | */ 26 | private $db; 27 | /** 28 | * @var string 29 | */ 30 | private $collection; 31 | /** 32 | * @var string 33 | */ 34 | private $wordField; 35 | /** 36 | * @var string 37 | */ 38 | private $translationField; 39 | 40 | /** 41 | * @param string $locale 42 | * @param array $translations 43 | */ 44 | public function __construct($locale, \MongoDB $db, $collection = 'translations', $wordField = 'word', $translationField = 'translation') 45 | { 46 | $this->locale = $locale; 47 | $this->db = $db; 48 | $this->collection = $collection; 49 | $this->wordField = $wordField; 50 | $this->translationField = $translationField; 51 | } 52 | 53 | /** 54 | * Returns current locale 55 | * 56 | * @return string 57 | */ 58 | public function getLocale() 59 | { 60 | return $this->locale; 61 | } 62 | 63 | /** 64 | * Returns translation for set word or if missing - word 65 | * 66 | * @param string $word 67 | * @return string 68 | */ 69 | public function getText($word) 70 | { 71 | $collection = $this->collection; 72 | $result = $this->db->$collection->findOne(['word' => $word]); 73 | 74 | if (!$result) { 75 | return null; 76 | } 77 | 78 | return $result['translation']; 79 | } 80 | 81 | /** 82 | * Adds new or updates entry to dictionary 83 | * 84 | * @param string $word 85 | * @param string $text 86 | * @return $this 87 | */ 88 | public function setText($word, $text) 89 | { 90 | $collection = $this->collection; 91 | $this->db->$collection->insert([ 92 | $this->wordField => $word, 93 | $this->translationField => $text, 94 | 'locale' => $this->locale 95 | ], [], ['upsert' => true]); 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * Gets translations 102 | * 103 | * @return array 104 | */ 105 | public function getTranslations() 106 | { 107 | $collection = $this->collection; 108 | $result = $this->db->$collection->find(); 109 | 110 | foreach ($result as $k => $res) { 111 | $this->translations[$res[$this->wordField]] = $res[$this->translationField]; 112 | } 113 | 114 | return $this->translations; 115 | } 116 | 117 | /** 118 | * Set translations 119 | * 120 | * @param array $translations 121 | * @return $this 122 | */ 123 | public function setTranslations(array $translations) 124 | { 125 | $this->translations = $translations; 126 | 127 | foreach ($translations as $word => $translation) { 128 | $this->setText($word, $translation); 129 | } 130 | 131 | return $this; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MicroTranslator 2 | 3 | _Current Version: **0.0.2**_ 4 | 5 | [![Build Status](https://travis-ci.org/marcotroisi/microtranslator.svg?branch=master)](https://travis-ci.org/marcotroisi/microtranslator) 6 | 7 | A PHP Microservice for managing Translations in your application. You can set it up anywhere in your stack 8 | and use it to *upload* and *download* translations. 9 | 10 | *** 11 | 12 | # Introduction 13 | 14 | MicroTranslator is written in PHP, and currently uses MongoDB as its storage engine. For more details, feel free to head over 15 | the [article on Marco Troisi's blog](http://www.marcotroisi.com/an-example-of-a-microservice/). The source code is being released 16 | under the **MIT Licence**, which means you are free to reuse, modify and even sell your work based on it. If you do any of the above 17 | listed actions, please consider [following its creator on Twitter](http://www.twitter.com/marcotroisi) as a way to say **thanks**! 18 | 19 | # Usage 20 | 21 | ## Show all available locales 22 | 23 | To see all locales available (e.g. en_GB, de_DE, af_ZA, etc.), just fire up the following request: 24 | 25 | GET /locale 26 | 27 | and you will get a nice JSON response that looks like this: 28 | 29 | ```json 30 | {"items": 31 | [{ 32 | "_id":{"$id":"552384e6e02f4fe237c925d0"}, 33 | "locale":"de_DE" 34 | }, 35 | { 36 | "_id":{"$id":"552384e6e02f4fe237c925d1"}, 37 | "locale":"en_GB" 38 | }], 39 | "count":2 40 | } 41 | ``` 42 | 43 | As you can see, the response will normally have an `items` section, with the actual result, and a `count` value, which will always 44 | represent the integer number of results. 45 | 46 | ## Show all terms for a given locale 47 | 48 | In order to see all the terms (available, translated words) for a given locale (e.g. de_DE), just do: 49 | 50 | GET /translation?locale=de_DE 51 | 52 | The result will be something like this: 53 | 54 | ```json 55 | {"items": 56 | [{ 57 | "Good morning":"Guten Tag" 58 | }, 59 | { 60 | "Hello":"Hallo" 61 | }], 62 | "total":2 63 | } 64 | ``` 65 | 66 | At the moment, *en_GB* is the default locale, in case you don't specify your `locale` parameter. 67 | 68 | ## Show a single term for a given locale 69 | 70 | In order to see only one term (e.g. "Good morning") for a given locale (e.g. it_IT), you can call: 71 | 72 | GET /translation/Good+morning?locale=it_IT 73 | 74 | The result will be: 75 | 76 | ```json 77 | {"items": 78 | [{ 79 | "Good morning":"Buongiorno" 80 | }], 81 | "total":1 82 | } 83 | ``` 84 | 85 | ## Insert/Update a term for a given locale 86 | 87 | To insert a new term, or update an existing one, use the following: 88 | 89 | POST /translation/Good+morning?locale=es_ES 90 | 91 | with POST parameter `translation` (e.g. `{ translation: "Buenas Dias"}`) 92 | 93 | The result will be a `true` or `false` value, based on the success of the operation. 94 | 95 | # Future 96 | 97 | As you may have noticed, there is still work necessary in order for MicroTranslator to get where it should. In the future, that's 98 | what it will feature: 99 | 100 | - Authentication 101 | - Docker integration 102 | - A frontend UI for adding/updating terms (on a separate repository) 103 | - Some other interesting things! 104 | 105 | # Questions? 106 | 107 | Please send me an email at hello@marcotroisi.com in order to ask your questions about MicroTranslator. 108 | 109 | # Ideas? Found a bug? 110 | 111 | Feel free to open a Github issue or even to fork and create a Pull Request. 112 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "4cff94fc16ca8e2068133e00ac06b615", 8 | "content-hash": "61d91385177e09df39005438c53bb928", 9 | "packages": [ 10 | { 11 | "name": "bcosca/fatfree", 12 | "version": "dev-master", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/bcosca/fatfree.git", 16 | "reference": "943df693fa3b183f7fec6fb09f9c9f89413228e6" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/bcosca/fatfree/zipball/943df693fa3b183f7fec6fb09f9c9f89413228e6", 21 | "reference": "943df693fa3b183f7fec6fb09f9c9f89413228e6", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": ">=5.3.6" 26 | }, 27 | "type": "library", 28 | "autoload": { 29 | "files": [ 30 | "lib/base.php" 31 | ] 32 | }, 33 | "notification-url": "https://packagist.org/downloads/", 34 | "license": [ 35 | "GPL-3.0" 36 | ], 37 | "description": "A powerful yet easy-to-use PHP micro-framework designed to help you build dynamic and robust Web applications - fast!", 38 | "homepage": "http://fatfreeframework.com/", 39 | "time": "2015-12-31 17:20:37" 40 | }, 41 | { 42 | "name": "moss/locale", 43 | "version": "v2.0", 44 | "source": { 45 | "type": "git", 46 | "url": "https://github.com/mossphp/moss-locale.git", 47 | "reference": "d331628a24fff0c79302e5177ee9313fa86a5b1d" 48 | }, 49 | "dist": { 50 | "type": "zip", 51 | "url": "https://api.github.com/repos/mossphp/moss-locale/zipball/d331628a24fff0c79302e5177ee9313fa86a5b1d", 52 | "reference": "d331628a24fff0c79302e5177ee9313fa86a5b1d", 53 | "shasum": "" 54 | }, 55 | "require": { 56 | "php": ">=5.4" 57 | }, 58 | "require-dev": { 59 | "phpunit/phpunit": ">=3.7" 60 | }, 61 | "type": "i18n", 62 | "autoload": { 63 | "psr-0": { 64 | "Moss\\Locale\\": "" 65 | } 66 | }, 67 | "notification-url": "https://packagist.org/downloads/", 68 | "license": [ 69 | "MIT" 70 | ], 71 | "authors": [ 72 | { 73 | "name": "Michal Wachowski", 74 | "email": "wachowski.michal@gmail.com" 75 | } 76 | ], 77 | "description": "moss locale", 78 | "keywords": [ 79 | "i18n", 80 | "internationalization", 81 | "locale", 82 | "translation" 83 | ], 84 | "time": "2015-03-27 10:10:34" 85 | } 86 | ], 87 | "packages-dev": [ 88 | { 89 | "name": "phpunit/php-code-coverage", 90 | "version": "2.2.4", 91 | "source": { 92 | "type": "git", 93 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 94 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" 95 | }, 96 | "dist": { 97 | "type": "zip", 98 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", 99 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", 100 | "shasum": "" 101 | }, 102 | "require": { 103 | "php": ">=5.3.3", 104 | "phpunit/php-file-iterator": "~1.3", 105 | "phpunit/php-text-template": "~1.2", 106 | "phpunit/php-token-stream": "~1.3", 107 | "sebastian/environment": "^1.3.2", 108 | "sebastian/version": "~1.0" 109 | }, 110 | "require-dev": { 111 | "ext-xdebug": ">=2.1.4", 112 | "phpunit/phpunit": "~4" 113 | }, 114 | "suggest": { 115 | "ext-dom": "*", 116 | "ext-xdebug": ">=2.2.1", 117 | "ext-xmlwriter": "*" 118 | }, 119 | "type": "library", 120 | "extra": { 121 | "branch-alias": { 122 | "dev-master": "2.2.x-dev" 123 | } 124 | }, 125 | "autoload": { 126 | "classmap": [ 127 | "src/" 128 | ] 129 | }, 130 | "notification-url": "https://packagist.org/downloads/", 131 | "license": [ 132 | "BSD-3-Clause" 133 | ], 134 | "authors": [ 135 | { 136 | "name": "Sebastian Bergmann", 137 | "email": "sb@sebastian-bergmann.de", 138 | "role": "lead" 139 | } 140 | ], 141 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 142 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 143 | "keywords": [ 144 | "coverage", 145 | "testing", 146 | "xunit" 147 | ], 148 | "time": "2015-10-06 15:47:00" 149 | }, 150 | { 151 | "name": "phpunit/php-file-iterator", 152 | "version": "1.3.4", 153 | "source": { 154 | "type": "git", 155 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 156 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" 157 | }, 158 | "dist": { 159 | "type": "zip", 160 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", 161 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", 162 | "shasum": "" 163 | }, 164 | "require": { 165 | "php": ">=5.3.3" 166 | }, 167 | "type": "library", 168 | "autoload": { 169 | "classmap": [ 170 | "File/" 171 | ] 172 | }, 173 | "notification-url": "https://packagist.org/downloads/", 174 | "include-path": [ 175 | "" 176 | ], 177 | "license": [ 178 | "BSD-3-Clause" 179 | ], 180 | "authors": [ 181 | { 182 | "name": "Sebastian Bergmann", 183 | "email": "sb@sebastian-bergmann.de", 184 | "role": "lead" 185 | } 186 | ], 187 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 188 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 189 | "keywords": [ 190 | "filesystem", 191 | "iterator" 192 | ], 193 | "time": "2013-10-10 15:34:57" 194 | }, 195 | { 196 | "name": "phpunit/php-text-template", 197 | "version": "1.2.1", 198 | "source": { 199 | "type": "git", 200 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 201 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 202 | }, 203 | "dist": { 204 | "type": "zip", 205 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 206 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 207 | "shasum": "" 208 | }, 209 | "require": { 210 | "php": ">=5.3.3" 211 | }, 212 | "type": "library", 213 | "autoload": { 214 | "classmap": [ 215 | "src/" 216 | ] 217 | }, 218 | "notification-url": "https://packagist.org/downloads/", 219 | "license": [ 220 | "BSD-3-Clause" 221 | ], 222 | "authors": [ 223 | { 224 | "name": "Sebastian Bergmann", 225 | "email": "sebastian@phpunit.de", 226 | "role": "lead" 227 | } 228 | ], 229 | "description": "Simple template engine.", 230 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 231 | "keywords": [ 232 | "template" 233 | ], 234 | "time": "2015-06-21 13:50:34" 235 | }, 236 | { 237 | "name": "phpunit/php-timer", 238 | "version": "1.0.7", 239 | "source": { 240 | "type": "git", 241 | "url": "https://github.com/sebastianbergmann/php-timer.git", 242 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" 243 | }, 244 | "dist": { 245 | "type": "zip", 246 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", 247 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", 248 | "shasum": "" 249 | }, 250 | "require": { 251 | "php": ">=5.3.3" 252 | }, 253 | "type": "library", 254 | "autoload": { 255 | "classmap": [ 256 | "src/" 257 | ] 258 | }, 259 | "notification-url": "https://packagist.org/downloads/", 260 | "license": [ 261 | "BSD-3-Clause" 262 | ], 263 | "authors": [ 264 | { 265 | "name": "Sebastian Bergmann", 266 | "email": "sb@sebastian-bergmann.de", 267 | "role": "lead" 268 | } 269 | ], 270 | "description": "Utility class for timing", 271 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 272 | "keywords": [ 273 | "timer" 274 | ], 275 | "time": "2015-06-21 08:01:12" 276 | }, 277 | { 278 | "name": "phpunit/php-token-stream", 279 | "version": "1.4.8", 280 | "source": { 281 | "type": "git", 282 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 283 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" 284 | }, 285 | "dist": { 286 | "type": "zip", 287 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 288 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 289 | "shasum": "" 290 | }, 291 | "require": { 292 | "ext-tokenizer": "*", 293 | "php": ">=5.3.3" 294 | }, 295 | "require-dev": { 296 | "phpunit/phpunit": "~4.2" 297 | }, 298 | "type": "library", 299 | "extra": { 300 | "branch-alias": { 301 | "dev-master": "1.4-dev" 302 | } 303 | }, 304 | "autoload": { 305 | "classmap": [ 306 | "src/" 307 | ] 308 | }, 309 | "notification-url": "https://packagist.org/downloads/", 310 | "license": [ 311 | "BSD-3-Clause" 312 | ], 313 | "authors": [ 314 | { 315 | "name": "Sebastian Bergmann", 316 | "email": "sebastian@phpunit.de" 317 | } 318 | ], 319 | "description": "Wrapper around PHP's tokenizer extension.", 320 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 321 | "keywords": [ 322 | "tokenizer" 323 | ], 324 | "time": "2015-09-15 10:49:45" 325 | }, 326 | { 327 | "name": "phpunit/phpunit", 328 | "version": "4.1.6", 329 | "source": { 330 | "type": "git", 331 | "url": "https://github.com/sebastianbergmann/phpunit.git", 332 | "reference": "241116219bb7e3b8111a36ffd8f37546888738d6" 333 | }, 334 | "dist": { 335 | "type": "zip", 336 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/241116219bb7e3b8111a36ffd8f37546888738d6", 337 | "reference": "241116219bb7e3b8111a36ffd8f37546888738d6", 338 | "shasum": "" 339 | }, 340 | "require": { 341 | "ext-dom": "*", 342 | "ext-json": "*", 343 | "ext-pcre": "*", 344 | "ext-reflection": "*", 345 | "ext-spl": "*", 346 | "php": ">=5.3.3", 347 | "phpunit/php-code-coverage": "~2.0", 348 | "phpunit/php-file-iterator": "~1.3.1", 349 | "phpunit/php-text-template": "~1.2", 350 | "phpunit/php-timer": "~1.0.2", 351 | "phpunit/phpunit-mock-objects": "2.1.5", 352 | "sebastian/comparator": "~1.0", 353 | "sebastian/diff": "~1.1", 354 | "sebastian/environment": "~1.0", 355 | "sebastian/exporter": "~1.0", 356 | "sebastian/version": "~1.0", 357 | "symfony/yaml": "~2.0" 358 | }, 359 | "suggest": { 360 | "phpunit/php-invoker": "~1.1" 361 | }, 362 | "bin": [ 363 | "phpunit" 364 | ], 365 | "type": "library", 366 | "extra": { 367 | "branch-alias": { 368 | "dev-master": "4.1.x-dev" 369 | } 370 | }, 371 | "autoload": { 372 | "classmap": [ 373 | "src/" 374 | ] 375 | }, 376 | "notification-url": "https://packagist.org/downloads/", 377 | "include-path": [ 378 | "", 379 | "../../symfony/yaml/" 380 | ], 381 | "license": [ 382 | "BSD-3-Clause" 383 | ], 384 | "authors": [ 385 | { 386 | "name": "Sebastian Bergmann", 387 | "email": "sebastian@phpunit.de", 388 | "role": "lead" 389 | } 390 | ], 391 | "description": "The PHP Unit Testing framework.", 392 | "homepage": "http://www.phpunit.de/", 393 | "keywords": [ 394 | "phpunit", 395 | "testing", 396 | "xunit" 397 | ], 398 | "time": "2014-08-17 08:07:02" 399 | }, 400 | { 401 | "name": "phpunit/phpunit-mock-objects", 402 | "version": "2.1.5", 403 | "source": { 404 | "type": "git", 405 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 406 | "reference": "7878b9c41edb3afab92b85edf5f0981014a2713a" 407 | }, 408 | "dist": { 409 | "type": "zip", 410 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/7878b9c41edb3afab92b85edf5f0981014a2713a", 411 | "reference": "7878b9c41edb3afab92b85edf5f0981014a2713a", 412 | "shasum": "" 413 | }, 414 | "require": { 415 | "php": ">=5.3.3", 416 | "phpunit/php-text-template": "~1.2" 417 | }, 418 | "require-dev": { 419 | "phpunit/phpunit": "~4.1" 420 | }, 421 | "suggest": { 422 | "ext-soap": "*" 423 | }, 424 | "type": "library", 425 | "extra": { 426 | "branch-alias": { 427 | "dev-master": "2.1.x-dev" 428 | } 429 | }, 430 | "autoload": { 431 | "classmap": [ 432 | "src/" 433 | ] 434 | }, 435 | "notification-url": "https://packagist.org/downloads/", 436 | "include-path": [ 437 | "" 438 | ], 439 | "license": [ 440 | "BSD-3-Clause" 441 | ], 442 | "authors": [ 443 | { 444 | "name": "Sebastian Bergmann", 445 | "email": "sb@sebastian-bergmann.de", 446 | "role": "lead" 447 | } 448 | ], 449 | "description": "Mock Object library for PHPUnit", 450 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 451 | "keywords": [ 452 | "mock", 453 | "xunit" 454 | ], 455 | "time": "2014-06-12 07:22:15" 456 | }, 457 | { 458 | "name": "sebastian/comparator", 459 | "version": "1.2.0", 460 | "source": { 461 | "type": "git", 462 | "url": "https://github.com/sebastianbergmann/comparator.git", 463 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" 464 | }, 465 | "dist": { 466 | "type": "zip", 467 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", 468 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", 469 | "shasum": "" 470 | }, 471 | "require": { 472 | "php": ">=5.3.3", 473 | "sebastian/diff": "~1.2", 474 | "sebastian/exporter": "~1.2" 475 | }, 476 | "require-dev": { 477 | "phpunit/phpunit": "~4.4" 478 | }, 479 | "type": "library", 480 | "extra": { 481 | "branch-alias": { 482 | "dev-master": "1.2.x-dev" 483 | } 484 | }, 485 | "autoload": { 486 | "classmap": [ 487 | "src/" 488 | ] 489 | }, 490 | "notification-url": "https://packagist.org/downloads/", 491 | "license": [ 492 | "BSD-3-Clause" 493 | ], 494 | "authors": [ 495 | { 496 | "name": "Jeff Welch", 497 | "email": "whatthejeff@gmail.com" 498 | }, 499 | { 500 | "name": "Volker Dusch", 501 | "email": "github@wallbash.com" 502 | }, 503 | { 504 | "name": "Bernhard Schussek", 505 | "email": "bschussek@2bepublished.at" 506 | }, 507 | { 508 | "name": "Sebastian Bergmann", 509 | "email": "sebastian@phpunit.de" 510 | } 511 | ], 512 | "description": "Provides the functionality to compare PHP values for equality", 513 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 514 | "keywords": [ 515 | "comparator", 516 | "compare", 517 | "equality" 518 | ], 519 | "time": "2015-07-26 15:48:44" 520 | }, 521 | { 522 | "name": "sebastian/diff", 523 | "version": "1.4.1", 524 | "source": { 525 | "type": "git", 526 | "url": "https://github.com/sebastianbergmann/diff.git", 527 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" 528 | }, 529 | "dist": { 530 | "type": "zip", 531 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", 532 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", 533 | "shasum": "" 534 | }, 535 | "require": { 536 | "php": ">=5.3.3" 537 | }, 538 | "require-dev": { 539 | "phpunit/phpunit": "~4.8" 540 | }, 541 | "type": "library", 542 | "extra": { 543 | "branch-alias": { 544 | "dev-master": "1.4-dev" 545 | } 546 | }, 547 | "autoload": { 548 | "classmap": [ 549 | "src/" 550 | ] 551 | }, 552 | "notification-url": "https://packagist.org/downloads/", 553 | "license": [ 554 | "BSD-3-Clause" 555 | ], 556 | "authors": [ 557 | { 558 | "name": "Kore Nordmann", 559 | "email": "mail@kore-nordmann.de" 560 | }, 561 | { 562 | "name": "Sebastian Bergmann", 563 | "email": "sebastian@phpunit.de" 564 | } 565 | ], 566 | "description": "Diff implementation", 567 | "homepage": "https://github.com/sebastianbergmann/diff", 568 | "keywords": [ 569 | "diff" 570 | ], 571 | "time": "2015-12-08 07:14:41" 572 | }, 573 | { 574 | "name": "sebastian/environment", 575 | "version": "1.3.5", 576 | "source": { 577 | "type": "git", 578 | "url": "https://github.com/sebastianbergmann/environment.git", 579 | "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf" 580 | }, 581 | "dist": { 582 | "type": "zip", 583 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", 584 | "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", 585 | "shasum": "" 586 | }, 587 | "require": { 588 | "php": ">=5.3.3" 589 | }, 590 | "require-dev": { 591 | "phpunit/phpunit": "~4.4" 592 | }, 593 | "type": "library", 594 | "extra": { 595 | "branch-alias": { 596 | "dev-master": "1.3.x-dev" 597 | } 598 | }, 599 | "autoload": { 600 | "classmap": [ 601 | "src/" 602 | ] 603 | }, 604 | "notification-url": "https://packagist.org/downloads/", 605 | "license": [ 606 | "BSD-3-Clause" 607 | ], 608 | "authors": [ 609 | { 610 | "name": "Sebastian Bergmann", 611 | "email": "sebastian@phpunit.de" 612 | } 613 | ], 614 | "description": "Provides functionality to handle HHVM/PHP environments", 615 | "homepage": "http://www.github.com/sebastianbergmann/environment", 616 | "keywords": [ 617 | "Xdebug", 618 | "environment", 619 | "hhvm" 620 | ], 621 | "time": "2016-02-26 18:40:46" 622 | }, 623 | { 624 | "name": "sebastian/exporter", 625 | "version": "1.2.1", 626 | "source": { 627 | "type": "git", 628 | "url": "https://github.com/sebastianbergmann/exporter.git", 629 | "reference": "7ae5513327cb536431847bcc0c10edba2701064e" 630 | }, 631 | "dist": { 632 | "type": "zip", 633 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", 634 | "reference": "7ae5513327cb536431847bcc0c10edba2701064e", 635 | "shasum": "" 636 | }, 637 | "require": { 638 | "php": ">=5.3.3", 639 | "sebastian/recursion-context": "~1.0" 640 | }, 641 | "require-dev": { 642 | "phpunit/phpunit": "~4.4" 643 | }, 644 | "type": "library", 645 | "extra": { 646 | "branch-alias": { 647 | "dev-master": "1.2.x-dev" 648 | } 649 | }, 650 | "autoload": { 651 | "classmap": [ 652 | "src/" 653 | ] 654 | }, 655 | "notification-url": "https://packagist.org/downloads/", 656 | "license": [ 657 | "BSD-3-Clause" 658 | ], 659 | "authors": [ 660 | { 661 | "name": "Jeff Welch", 662 | "email": "whatthejeff@gmail.com" 663 | }, 664 | { 665 | "name": "Volker Dusch", 666 | "email": "github@wallbash.com" 667 | }, 668 | { 669 | "name": "Bernhard Schussek", 670 | "email": "bschussek@2bepublished.at" 671 | }, 672 | { 673 | "name": "Sebastian Bergmann", 674 | "email": "sebastian@phpunit.de" 675 | }, 676 | { 677 | "name": "Adam Harvey", 678 | "email": "aharvey@php.net" 679 | } 680 | ], 681 | "description": "Provides the functionality to export PHP variables for visualization", 682 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 683 | "keywords": [ 684 | "export", 685 | "exporter" 686 | ], 687 | "time": "2015-06-21 07:55:53" 688 | }, 689 | { 690 | "name": "sebastian/recursion-context", 691 | "version": "1.0.2", 692 | "source": { 693 | "type": "git", 694 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 695 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791" 696 | }, 697 | "dist": { 698 | "type": "zip", 699 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", 700 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791", 701 | "shasum": "" 702 | }, 703 | "require": { 704 | "php": ">=5.3.3" 705 | }, 706 | "require-dev": { 707 | "phpunit/phpunit": "~4.4" 708 | }, 709 | "type": "library", 710 | "extra": { 711 | "branch-alias": { 712 | "dev-master": "1.0.x-dev" 713 | } 714 | }, 715 | "autoload": { 716 | "classmap": [ 717 | "src/" 718 | ] 719 | }, 720 | "notification-url": "https://packagist.org/downloads/", 721 | "license": [ 722 | "BSD-3-Clause" 723 | ], 724 | "authors": [ 725 | { 726 | "name": "Jeff Welch", 727 | "email": "whatthejeff@gmail.com" 728 | }, 729 | { 730 | "name": "Sebastian Bergmann", 731 | "email": "sebastian@phpunit.de" 732 | }, 733 | { 734 | "name": "Adam Harvey", 735 | "email": "aharvey@php.net" 736 | } 737 | ], 738 | "description": "Provides functionality to recursively process PHP variables", 739 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 740 | "time": "2015-11-11 19:50:13" 741 | }, 742 | { 743 | "name": "sebastian/version", 744 | "version": "1.0.6", 745 | "source": { 746 | "type": "git", 747 | "url": "https://github.com/sebastianbergmann/version.git", 748 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" 749 | }, 750 | "dist": { 751 | "type": "zip", 752 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 753 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 754 | "shasum": "" 755 | }, 756 | "type": "library", 757 | "autoload": { 758 | "classmap": [ 759 | "src/" 760 | ] 761 | }, 762 | "notification-url": "https://packagist.org/downloads/", 763 | "license": [ 764 | "BSD-3-Clause" 765 | ], 766 | "authors": [ 767 | { 768 | "name": "Sebastian Bergmann", 769 | "email": "sebastian@phpunit.de", 770 | "role": "lead" 771 | } 772 | ], 773 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 774 | "homepage": "https://github.com/sebastianbergmann/version", 775 | "time": "2015-06-21 13:59:46" 776 | }, 777 | { 778 | "name": "symfony/yaml", 779 | "version": "v2.8.4", 780 | "source": { 781 | "type": "git", 782 | "url": "https://github.com/symfony/yaml.git", 783 | "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb" 784 | }, 785 | "dist": { 786 | "type": "zip", 787 | "url": "https://api.github.com/repos/symfony/yaml/zipball/584e52cb8f788a887553ba82db6caacb1d6260bb", 788 | "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb", 789 | "shasum": "" 790 | }, 791 | "require": { 792 | "php": ">=5.3.9" 793 | }, 794 | "type": "library", 795 | "extra": { 796 | "branch-alias": { 797 | "dev-master": "2.8-dev" 798 | } 799 | }, 800 | "autoload": { 801 | "psr-4": { 802 | "Symfony\\Component\\Yaml\\": "" 803 | }, 804 | "exclude-from-classmap": [ 805 | "/Tests/" 806 | ] 807 | }, 808 | "notification-url": "https://packagist.org/downloads/", 809 | "license": [ 810 | "MIT" 811 | ], 812 | "authors": [ 813 | { 814 | "name": "Fabien Potencier", 815 | "email": "fabien@symfony.com" 816 | }, 817 | { 818 | "name": "Symfony Community", 819 | "homepage": "https://symfony.com/contributors" 820 | } 821 | ], 822 | "description": "Symfony Yaml Component", 823 | "homepage": "https://symfony.com", 824 | "time": "2016-03-04 07:54:35" 825 | } 826 | ], 827 | "aliases": [], 828 | "minimum-stability": "dev", 829 | "stability-flags": { 830 | "bcosca/fatfree": 20 831 | }, 832 | "prefer-stable": true, 833 | "prefer-lowest": false, 834 | "platform": { 835 | "php": ">=5.4.0" 836 | }, 837 | "platform-dev": [] 838 | } 839 | --------------------------------------------------------------------------------