├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── apigen.neon ├── composer.json ├── composer.lock ├── phpunit.xml ├── src └── Filter │ ├── Facades │ └── Filter.php │ ├── Filter.php │ ├── FilterInterface.php │ ├── FilterServiceProvider.php │ └── HasFilters.php └── tests ├── Filter ├── FilterServiceProviderTest.php ├── FilterTest.php └── HasFiltersTest.php └── bootstrap.php /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | vendor/ 3 | composer.phar 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | 7 | before_script: 8 | - composer install --dev 9 | - mkdir -p build/logs 10 | 11 | script: phpunit --coverage-clover build/logs/clover.xml 12 | 13 | after_script: 14 | - php vendor/bin/coveralls -v 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Ross Masters 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 13 | all 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 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Filter [![Latest Stable Version](https://poser.pugx.org/rmasters/filter/v/stable.png)](https://packagist.org/packages/rmasters/filter) [![master](https://travis-ci.org/rmasters/filter.png?branch=master)](https://travis-ci.org/rmasters/filter) [![Coverage Status](https://coveralls.io/repos/rmasters/filter/badge.png)](https://coveralls.io/r/rmasters/filter) [![versioneye dependencies](https://www.versioneye.com/user/projects/5217bad8632bac775003b749/badge.png)](https://www.versioneye.com/user/projects/5217bad8632bac775003b749) 2 | 3 | Aims to help make filtering input to your Eloquent models easier. 4 | 5 | Simplifies code like this: 6 | 7 | class Address extends Model { 8 | public function setPostcodeAttribute($value) { 9 | $this->attributes['postcode'] = strtoupper(trim($value)); 10 | } 11 | 12 | public function setCityAttribute($value) { 13 | $this->attributes['city'] = trim($value); 14 | } 15 | 16 | public function getCityAttribute($value) { 17 | return strtoupper($value); 18 | } 19 | } 20 | 21 | Into this: 22 | 23 | class Address extends Model { 24 | use Filter\HasFilters 25 | 26 | protected $input = [ 27 | 'postcode' => 'uppercase|trim', 28 | 'city' => 'trim' 29 | ]; 30 | 31 | protected $output = [ 32 | 'city' => 'uppercase' 33 | ]; 34 | } 35 | 36 | Can also be used standalone: 37 | 38 | $clean = Filter::filter(['city' => 'London'], ['city' => 'trim|uppercase']); 39 | 40 | ## Installation 41 | 42 | Installable via composer: 43 | 44 | "rmasters/filter": "dev-master", 45 | 46 | ### Laravel 4 47 | 48 | To use the model trait and service for Laravel 4, add the following lines to 49 | `config/app.php`: 50 | 51 | 'providers' => array( 52 | // ... 53 | 'Filter\FilterServiceProvider', 54 | 55 | 'aliases' => array( 56 | // ... 57 | 'Filter' => 'Filter\Facades\Filter', 58 | 59 | ## Usage 60 | 61 | > Examples below use the Facade style (`Filter::filter()`) for brevity - 62 | standalone users should expand this to `$filter->filter()`. 63 | 64 | The standalone class is similar to Laravel's validator component: 65 | 66 | $filtered = Filter::filter(['name' => 'Ross'], ['name' => 'trim']); 67 | $value = Filter::filterOne('Ross', 'trim'); 68 | 69 | Rules are also constructed similarly to Validator: 70 | 71 | Filter::filterOne('test', 'trim|upper'); 72 | Filter::filterOne('test...', 'rtrim:.'); 73 | Filter::filterOne('test', ['trim', 'upper']); 74 | 75 | Filters are run sequentially from left to right. Arguments are parsed by 76 | [`str_getcsv`](http://php.net/str_getcsv) - e.g. to trim commas use `trim:","`. 77 | 78 | ### Registering filters 79 | 80 | A filter is a callable that accepts the input string and an array of arguments: 81 | 82 | Filter::register('slugify', function($str, array $args) { 83 | return preg_replace('/[^a-z0-9]+/', '-', strtolower($str)); 84 | }); 85 | 86 | Other callable values are classes that define an `__invoke` method and function 87 | names. For example, Zend Framework's filters all implement `__invoke`, so 88 | `'Zend\I18n\Filter\Alnum'` is a valid callable. 89 | 90 | Filters can be unregistered using `Filter::unregister('slugify')`. 91 | 92 | #### Default filters 93 | 94 | By default the following filters are registered: 95 | 96 | trim trim($str) 97 | trim:|,/ trim($str, '|/'); 98 | ltrim ltrim($str) 99 | ltrim:|,/ ltrim($str, '|/'); 100 | rtrim rtrim($str) 101 | rtrim:|,/ rtrim($str, '|/'); 102 | upper strtoupper($str) 103 | lower strtolower($str) 104 | capfirst ucfirst($str) 105 | lowerfirst lcfirst($str) 106 | 107 | ### Laravel 4 108 | 109 | A trait, `HasFilters` is available that modifies `getAttribute` (accessor) and 110 | `setAttribute` (mutator) to apply filters to the input or output value. 111 | 112 | These filter rules are specified in properties on the model, `$input` and 113 | `$output` for mutators and accessors respectively. 114 | 115 | class Address extends Model { 116 | use HasFilters; 117 | 118 | public $fillable = ['line1', 'line2', 'line3', 'city', 'postcode']; 119 | public $input = [ 120 | 'line1' => 'trim', 121 | 'line2' => 'trim', 122 | 'line3' => 'trim', 123 | 'city' => 'trim', 124 | 'postcode' => 'uppercase|trim', 125 | ]; 126 | public $output = [ 127 | 'city' => 'uppercase', // Uppercase only for display 128 | ]; 129 | } 130 | 131 | The filter instance is available using `App::make('filter')`, or via the facade 132 | `Filter` depending on your setup in `config/app.php`. 133 | 134 | #### Call chain 135 | 136 | You can still write your own accessors or mutators which will be applied as well 137 | as any filters that have been set. The following chains happen: 138 | 139 | * Mutator: `$model->name = 'Ross'` (filters applied **before** your mutator) 140 | 1. `Filter\HasFilters::setAttribute` 141 | 2. `Eloquent\Model::setAttribute` 142 | 3. `Your\Model::setNameAttribute` (if defined) 143 | * Accessor: `echo $model->name` (filters applied **after** your accessor) 144 | 1. `Eloquent\Model::getAttribute` 145 | 2. `Your\Model::getNameAttribute` 146 | 3. `Filter\HasFilters::getAttribute` 147 | 148 | You should not need to modify your mutators (they should still store the value 149 | in `$this->attributes[$name]`. 150 | 151 | ## License 152 | 153 | Released under the MIT license. 154 | -------------------------------------------------------------------------------- /apigen.neon: -------------------------------------------------------------------------------- 1 | source: 2 | - src/ 3 | destination: build/api 4 | exclude: 5 | - "*/vendor/*" 6 | - "*/test/*" 7 | title: Filter 8 | groups: auto 9 | autocomplete: 10 | - classes 11 | - constants 12 | - functions 13 | accessLevels: 14 | - public 15 | - protected 16 | - private 17 | internal: yes 18 | php: no 19 | tree: yes 20 | deprecated: yes 21 | todo: yes 22 | sourceCode: yes 23 | report: build/api/apigen.log 24 | wipeout: yes 25 | quiet: no 26 | progressbar: no 27 | colors: no 28 | debug: no 29 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rmasters/filter", 3 | "description": "Makes input and output filtering Eloquent models easy", 4 | "keywords": ["laravel", "filter", "eloquent"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Ross Masters", 9 | "email":"ross@rossmasters.com" 10 | } 11 | ], 12 | "homepage": "https://github.com/rmasters/filter", 13 | "support": { 14 | "issues": "https://github.com/rmasters/filter/issues", 15 | "wiki": "https://github.com/rmasters/filter/wiki" 16 | }, 17 | "require": { 18 | "php": ">=5.4.0", 19 | "illuminate/support": "4.*", 20 | "illuminate/container": "4.*" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "3.7.*", 24 | "satooshi/php-coveralls": "dev-master", 25 | "mockery/mockery": "dev-master@dev", 26 | "illuminate/database": "4.*" 27 | }, 28 | "autoload": { 29 | "psr-0": { 30 | "Filter": "src/" 31 | } 32 | }, 33 | "minimum-stability": "dev", 34 | "config": { 35 | "preferred-install": "dist" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" 5 | ], 6 | "hash": "ce3461855912777e6497b314b5227f4f", 7 | "packages": [ 8 | { 9 | "name": "illuminate/container", 10 | "version": "dev-master", 11 | "target-dir": "Illuminate/Container", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/illuminate/container.git", 15 | "reference": "0088363d30b4d6be452bfb8ca4ee1aa67ca72a33" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/illuminate/container/zipball/0088363d30b4d6be452bfb8ca4ee1aa67ca72a33", 20 | "reference": "0088363d30b4d6be452bfb8ca4ee1aa67ca72a33", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.3.0" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": "3.7.*" 28 | }, 29 | "type": "library", 30 | "extra": { 31 | "branch-alias": { 32 | "dev-master": "4.1-dev" 33 | } 34 | }, 35 | "autoload": { 36 | "psr-0": { 37 | "Illuminate\\Container": "" 38 | } 39 | }, 40 | "notification-url": "https://packagist.org/downloads/", 41 | "license": [ 42 | "MIT" 43 | ], 44 | "authors": [ 45 | { 46 | "name": "Taylor Otwell", 47 | "email": "taylorotwell@gmail.com", 48 | "homepage": "https://github.com/taylorotwell", 49 | "role": "Developer" 50 | } 51 | ], 52 | "time": "2013-10-29 15:32:59" 53 | }, 54 | { 55 | "name": "illuminate/support", 56 | "version": "dev-master", 57 | "target-dir": "Illuminate/Support", 58 | "source": { 59 | "type": "git", 60 | "url": "https://github.com/illuminate/support.git", 61 | "reference": "65433f77ac57329461fd568ae41c733f64e08bf3" 62 | }, 63 | "dist": { 64 | "type": "zip", 65 | "url": "https://api.github.com/repos/illuminate/support/zipball/65433f77ac57329461fd568ae41c733f64e08bf3", 66 | "reference": "65433f77ac57329461fd568ae41c733f64e08bf3", 67 | "shasum": "" 68 | }, 69 | "require": { 70 | "php": ">=5.3.0" 71 | }, 72 | "require-dev": { 73 | "mockery/mockery": "0.7.2", 74 | "patchwork/utf8": "1.1.*", 75 | "phpunit/phpunit": "3.7.*" 76 | }, 77 | "type": "library", 78 | "extra": { 79 | "branch-alias": { 80 | "dev-master": "4.1-dev" 81 | } 82 | }, 83 | "autoload": { 84 | "psr-0": { 85 | "Illuminate\\Support": "" 86 | }, 87 | "files": [ 88 | "Illuminate/Support/helpers.php" 89 | ] 90 | }, 91 | "notification-url": "https://packagist.org/downloads/", 92 | "license": [ 93 | "MIT" 94 | ], 95 | "authors": [ 96 | { 97 | "name": "Taylor Otwell", 98 | "email": "taylorotwell@gmail.com", 99 | "homepage": "https://github.com/taylorotwell", 100 | "role": "Developer" 101 | } 102 | ], 103 | "time": "2013-10-29 16:55:37" 104 | } 105 | ], 106 | "packages-dev": [ 107 | { 108 | "name": "guzzle/guzzle", 109 | "version": "dev-master", 110 | "source": { 111 | "type": "git", 112 | "url": "https://github.com/guzzle/guzzle.git", 113 | "reference": "57e96c16fecc32f07736dc9645fdfe1b0160a07c" 114 | }, 115 | "dist": { 116 | "type": "zip", 117 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/57e96c16fecc32f07736dc9645fdfe1b0160a07c", 118 | "reference": "57e96c16fecc32f07736dc9645fdfe1b0160a07c", 119 | "shasum": "" 120 | }, 121 | "require": { 122 | "ext-curl": "*", 123 | "php": ">=5.3.3", 124 | "symfony/event-dispatcher": ">=2.1" 125 | }, 126 | "replace": { 127 | "guzzle/batch": "self.version", 128 | "guzzle/cache": "self.version", 129 | "guzzle/common": "self.version", 130 | "guzzle/http": "self.version", 131 | "guzzle/inflection": "self.version", 132 | "guzzle/iterator": "self.version", 133 | "guzzle/log": "self.version", 134 | "guzzle/parser": "self.version", 135 | "guzzle/plugin": "self.version", 136 | "guzzle/plugin-async": "self.version", 137 | "guzzle/plugin-backoff": "self.version", 138 | "guzzle/plugin-cache": "self.version", 139 | "guzzle/plugin-cookie": "self.version", 140 | "guzzle/plugin-curlauth": "self.version", 141 | "guzzle/plugin-error-response": "self.version", 142 | "guzzle/plugin-history": "self.version", 143 | "guzzle/plugin-log": "self.version", 144 | "guzzle/plugin-md5": "self.version", 145 | "guzzle/plugin-mock": "self.version", 146 | "guzzle/plugin-oauth": "self.version", 147 | "guzzle/service": "self.version", 148 | "guzzle/stream": "self.version" 149 | }, 150 | "require-dev": { 151 | "doctrine/cache": "*", 152 | "monolog/monolog": "1.*", 153 | "phpunit/phpunit": "3.7.*", 154 | "psr/log": "1.0.*", 155 | "symfony/class-loader": "*", 156 | "zendframework/zend-cache": "2.0.*", 157 | "zendframework/zend-log": "2.0.*" 158 | }, 159 | "type": "library", 160 | "extra": { 161 | "branch-alias": { 162 | "dev-master": "3.7-dev" 163 | } 164 | }, 165 | "autoload": { 166 | "psr-0": { 167 | "Guzzle\\Tests": "tests/", 168 | "Guzzle": "src/" 169 | } 170 | }, 171 | "notification-url": "https://packagist.org/downloads/", 172 | "license": [ 173 | "MIT" 174 | ], 175 | "authors": [ 176 | { 177 | "name": "Michael Dowling", 178 | "email": "mtdowling@gmail.com", 179 | "homepage": "https://github.com/mtdowling" 180 | }, 181 | { 182 | "name": "Guzzle Community", 183 | "homepage": "https://github.com/guzzle/guzzle/contributors" 184 | } 185 | ], 186 | "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", 187 | "homepage": "http://guzzlephp.org/", 188 | "keywords": [ 189 | "client", 190 | "curl", 191 | "framework", 192 | "http", 193 | "http client", 194 | "rest", 195 | "web service" 196 | ], 197 | "time": "2013-10-30 02:57:15" 198 | }, 199 | { 200 | "name": "illuminate/database", 201 | "version": "dev-master", 202 | "target-dir": "Illuminate/Database", 203 | "source": { 204 | "type": "git", 205 | "url": "https://github.com/illuminate/database.git", 206 | "reference": "51bfe2ba02d3e327627f3d8fcabd96eabcf06565" 207 | }, 208 | "dist": { 209 | "type": "zip", 210 | "url": "https://api.github.com/repos/illuminate/database/zipball/51bfe2ba02d3e327627f3d8fcabd96eabcf06565", 211 | "reference": "51bfe2ba02d3e327627f3d8fcabd96eabcf06565", 212 | "shasum": "" 213 | }, 214 | "require": { 215 | "illuminate/container": "4.1.x", 216 | "illuminate/events": "4.1.x", 217 | "illuminate/support": "4.1.x", 218 | "nesbot/carbon": "1.*", 219 | "php": ">=5.3.0" 220 | }, 221 | "require-dev": { 222 | "illuminate/cache": "4.1.x", 223 | "illuminate/console": "4.1.x", 224 | "illuminate/filesystem": "4.1.x", 225 | "illuminate/pagination": "4.1.x", 226 | "illuminate/support": "4.1.x", 227 | "mockery/mockery": "0.7.2", 228 | "phpunit/phpunit": "3.7.*" 229 | }, 230 | "type": "library", 231 | "extra": { 232 | "branch-alias": { 233 | "dev-master": "4.1-dev" 234 | } 235 | }, 236 | "autoload": { 237 | "psr-0": { 238 | "Illuminate\\Database": "" 239 | } 240 | }, 241 | "notification-url": "https://packagist.org/downloads/", 242 | "license": [ 243 | "MIT" 244 | ], 245 | "authors": [ 246 | { 247 | "name": "Taylor Otwell", 248 | "email": "taylorotwell@gmail.com", 249 | "homepage": "https://github.com/taylorotwell", 250 | "role": "Developer" 251 | } 252 | ], 253 | "keywords": [ 254 | "database", 255 | "laravel", 256 | "orm", 257 | "sql" 258 | ], 259 | "time": "2013-10-29 18:37:25" 260 | }, 261 | { 262 | "name": "illuminate/events", 263 | "version": "dev-master", 264 | "target-dir": "Illuminate/Events", 265 | "source": { 266 | "type": "git", 267 | "url": "https://github.com/illuminate/events.git", 268 | "reference": "7a658e96e9631c4ae541a205563984a80af7dc01" 269 | }, 270 | "dist": { 271 | "type": "zip", 272 | "url": "https://api.github.com/repos/illuminate/events/zipball/7a658e96e9631c4ae541a205563984a80af7dc01", 273 | "reference": "7a658e96e9631c4ae541a205563984a80af7dc01", 274 | "shasum": "" 275 | }, 276 | "require": { 277 | "illuminate/container": "4.1.x", 278 | "illuminate/support": "4.1.x", 279 | "php": ">=5.3.0" 280 | }, 281 | "require-dev": { 282 | "mockery/mockery": "0.7.2", 283 | "phpunit/phpunit": "3.7.*" 284 | }, 285 | "type": "library", 286 | "extra": { 287 | "branch-alias": { 288 | "dev-master": "4.1-dev" 289 | } 290 | }, 291 | "autoload": { 292 | "psr-0": { 293 | "Illuminate\\Events": "" 294 | } 295 | }, 296 | "notification-url": "https://packagist.org/downloads/", 297 | "license": [ 298 | "MIT" 299 | ], 300 | "authors": [ 301 | { 302 | "name": "Taylor Otwell", 303 | "email": "taylorotwell@gmail.com", 304 | "homepage": "https://github.com/taylorotwell", 305 | "role": "Developer" 306 | } 307 | ], 308 | "time": "2013-10-29 12:20:27" 309 | }, 310 | { 311 | "name": "mockery/mockery", 312 | "version": "dev-master", 313 | "source": { 314 | "type": "git", 315 | "url": "https://github.com/padraic/mockery.git", 316 | "reference": "09ab879a09def2a658d6e8030f88432cc479f5a8" 317 | }, 318 | "dist": { 319 | "type": "zip", 320 | "url": "https://api.github.com/repos/padraic/mockery/zipball/09ab879a09def2a658d6e8030f88432cc479f5a8", 321 | "reference": "09ab879a09def2a658d6e8030f88432cc479f5a8", 322 | "shasum": "" 323 | }, 324 | "require": { 325 | "lib-pcre": ">=7.0", 326 | "php": ">=5.3.2" 327 | }, 328 | "require-dev": { 329 | "hamcrest/hamcrest": "1.1.0" 330 | }, 331 | "type": "library", 332 | "autoload": { 333 | "psr-0": { 334 | "Mockery": "library/" 335 | } 336 | }, 337 | "notification-url": "https://packagist.org/downloads/", 338 | "license": [ 339 | "BSD-3-Clause" 340 | ], 341 | "authors": [ 342 | { 343 | "name": "Pádraic Brady", 344 | "email": "padraic.brady@gmail.com", 345 | "homepage": "http://blog.astrumfutura.com" 346 | } 347 | ], 348 | "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succint API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", 349 | "homepage": "http://github.com/padraic/mockery", 350 | "keywords": [ 351 | "BDD", 352 | "TDD", 353 | "library", 354 | "mock", 355 | "mock objects", 356 | "mockery", 357 | "stub", 358 | "test", 359 | "test double", 360 | "testing" 361 | ], 362 | "time": "2013-10-18 15:18:30" 363 | }, 364 | { 365 | "name": "nesbot/carbon", 366 | "version": "1.4.0", 367 | "source": { 368 | "type": "git", 369 | "url": "https://github.com/briannesbitt/Carbon.git", 370 | "reference": "06f0b8a99a90c5392ceccb09b75b74ff6c08ec07" 371 | }, 372 | "dist": { 373 | "type": "zip", 374 | "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/06f0b8a99a90c5392ceccb09b75b74ff6c08ec07", 375 | "reference": "06f0b8a99a90c5392ceccb09b75b74ff6c08ec07", 376 | "shasum": "" 377 | }, 378 | "require": { 379 | "php": ">=5.3.0" 380 | }, 381 | "type": "library", 382 | "autoload": { 383 | "psr-0": { 384 | "Carbon": "src" 385 | } 386 | }, 387 | "notification-url": "https://packagist.org/downloads/", 388 | "license": [ 389 | "MIT" 390 | ], 391 | "authors": [ 392 | { 393 | "name": "Brian Nesbitt", 394 | "email": "brian@nesbot.com", 395 | "homepage": "http://nesbot.com" 396 | } 397 | ], 398 | "description": "A simple API extension for DateTime.", 399 | "homepage": "https://github.com/briannesbitt/Carbon", 400 | "keywords": [ 401 | "date", 402 | "datetime", 403 | "time" 404 | ], 405 | "time": "2013-09-09 02:39:19" 406 | }, 407 | { 408 | "name": "phpunit/php-code-coverage", 409 | "version": "1.2.x-dev", 410 | "source": { 411 | "type": "git", 412 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 413 | "reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94" 414 | }, 415 | "dist": { 416 | "type": "zip", 417 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/466e7cd2554b4e264c9e3f31216d25ac0e5f3d94", 418 | "reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94", 419 | "shasum": "" 420 | }, 421 | "require": { 422 | "php": ">=5.3.3", 423 | "phpunit/php-file-iterator": ">=1.3.0@stable", 424 | "phpunit/php-text-template": ">=1.1.1@stable", 425 | "phpunit/php-token-stream": ">=1.1.3@stable" 426 | }, 427 | "require-dev": { 428 | "phpunit/phpunit": "3.7.*@dev" 429 | }, 430 | "suggest": { 431 | "ext-dom": "*", 432 | "ext-xdebug": ">=2.0.5" 433 | }, 434 | "type": "library", 435 | "extra": { 436 | "branch-alias": { 437 | "dev-master": "1.2.x-dev" 438 | } 439 | }, 440 | "autoload": { 441 | "classmap": [ 442 | "PHP/" 443 | ] 444 | }, 445 | "notification-url": "https://packagist.org/downloads/", 446 | "include-path": [ 447 | "" 448 | ], 449 | "license": [ 450 | "BSD-3-Clause" 451 | ], 452 | "authors": [ 453 | { 454 | "name": "Sebastian Bergmann", 455 | "email": "sb@sebastian-bergmann.de", 456 | "role": "lead" 457 | } 458 | ], 459 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 460 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 461 | "keywords": [ 462 | "coverage", 463 | "testing", 464 | "xunit" 465 | ], 466 | "time": "2013-09-10 08:14:32" 467 | }, 468 | { 469 | "name": "phpunit/php-file-iterator", 470 | "version": "dev-master", 471 | "source": { 472 | "type": "git", 473 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 474 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" 475 | }, 476 | "dist": { 477 | "type": "zip", 478 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", 479 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", 480 | "shasum": "" 481 | }, 482 | "require": { 483 | "php": ">=5.3.3" 484 | }, 485 | "type": "library", 486 | "autoload": { 487 | "classmap": [ 488 | "File/" 489 | ] 490 | }, 491 | "notification-url": "https://packagist.org/downloads/", 492 | "include-path": [ 493 | "" 494 | ], 495 | "license": [ 496 | "BSD-3-Clause" 497 | ], 498 | "authors": [ 499 | { 500 | "name": "Sebastian Bergmann", 501 | "email": "sb@sebastian-bergmann.de", 502 | "role": "lead" 503 | } 504 | ], 505 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 506 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 507 | "keywords": [ 508 | "filesystem", 509 | "iterator" 510 | ], 511 | "time": "2013-10-10 15:34:57" 512 | }, 513 | { 514 | "name": "phpunit/php-text-template", 515 | "version": "dev-master", 516 | "source": { 517 | "type": "git", 518 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 519 | "reference": "1eeef106193d2f8c539728e566bb4793071a9e18" 520 | }, 521 | "dist": { 522 | "type": "zip", 523 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/1eeef106193d2f8c539728e566bb4793071a9e18", 524 | "reference": "1eeef106193d2f8c539728e566bb4793071a9e18", 525 | "shasum": "" 526 | }, 527 | "require": { 528 | "php": ">=5.3.3" 529 | }, 530 | "type": "library", 531 | "autoload": { 532 | "classmap": [ 533 | "Text/" 534 | ] 535 | }, 536 | "notification-url": "https://packagist.org/downloads/", 537 | "include-path": [ 538 | "" 539 | ], 540 | "license": [ 541 | "BSD-3-Clause" 542 | ], 543 | "authors": [ 544 | { 545 | "name": "Sebastian Bergmann", 546 | "email": "sb@sebastian-bergmann.de", 547 | "role": "lead" 548 | } 549 | ], 550 | "description": "Simple template engine.", 551 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 552 | "keywords": [ 553 | "template" 554 | ], 555 | "time": "2013-01-07 10:56:17" 556 | }, 557 | { 558 | "name": "phpunit/php-timer", 559 | "version": "dev-master", 560 | "source": { 561 | "type": "git", 562 | "url": "https://github.com/sebastianbergmann/php-timer.git", 563 | "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" 564 | }, 565 | "dist": { 566 | "type": "zip", 567 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", 568 | "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", 569 | "shasum": "" 570 | }, 571 | "require": { 572 | "php": ">=5.3.3" 573 | }, 574 | "type": "library", 575 | "autoload": { 576 | "classmap": [ 577 | "PHP/" 578 | ] 579 | }, 580 | "notification-url": "https://packagist.org/downloads/", 581 | "include-path": [ 582 | "" 583 | ], 584 | "license": [ 585 | "BSD-3-Clause" 586 | ], 587 | "authors": [ 588 | { 589 | "name": "Sebastian Bergmann", 590 | "email": "sb@sebastian-bergmann.de", 591 | "role": "lead" 592 | } 593 | ], 594 | "description": "Utility class for timing", 595 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 596 | "keywords": [ 597 | "timer" 598 | ], 599 | "time": "2013-08-02 07:42:54" 600 | }, 601 | { 602 | "name": "phpunit/php-token-stream", 603 | "version": "dev-master", 604 | "source": { 605 | "type": "git", 606 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 607 | "reference": "292f4d5772dad5a12775be69f4a8dd663b20f103" 608 | }, 609 | "dist": { 610 | "type": "zip", 611 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/292f4d5772dad5a12775be69f4a8dd663b20f103", 612 | "reference": "292f4d5772dad5a12775be69f4a8dd663b20f103", 613 | "shasum": "" 614 | }, 615 | "require": { 616 | "ext-tokenizer": "*", 617 | "php": ">=5.3.3" 618 | }, 619 | "type": "library", 620 | "extra": { 621 | "branch-alias": { 622 | "dev-master": "1.2-dev" 623 | } 624 | }, 625 | "autoload": { 626 | "classmap": [ 627 | "PHP/" 628 | ] 629 | }, 630 | "notification-url": "https://packagist.org/downloads/", 631 | "include-path": [ 632 | "" 633 | ], 634 | "license": [ 635 | "BSD-3-Clause" 636 | ], 637 | "authors": [ 638 | { 639 | "name": "Sebastian Bergmann", 640 | "email": "sb@sebastian-bergmann.de", 641 | "role": "lead" 642 | } 643 | ], 644 | "description": "Wrapper around PHP's tokenizer extension.", 645 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 646 | "keywords": [ 647 | "tokenizer" 648 | ], 649 | "time": "2013-10-21 14:03:39" 650 | }, 651 | { 652 | "name": "phpunit/phpunit", 653 | "version": "3.7.x-dev", 654 | "source": { 655 | "type": "git", 656 | "url": "https://github.com/sebastianbergmann/phpunit.git", 657 | "reference": "598a467a7d234dd78788cd72d5fd58105a1dfd0e" 658 | }, 659 | "dist": { 660 | "type": "zip", 661 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/598a467a7d234dd78788cd72d5fd58105a1dfd0e", 662 | "reference": "598a467a7d234dd78788cd72d5fd58105a1dfd0e", 663 | "shasum": "" 664 | }, 665 | "require": { 666 | "ext-dom": "*", 667 | "ext-pcre": "*", 668 | "ext-reflection": "*", 669 | "ext-spl": "*", 670 | "php": ">=5.3.3", 671 | "phpunit/php-code-coverage": "~1.2.1", 672 | "phpunit/php-file-iterator": ">=1.3.1", 673 | "phpunit/php-text-template": ">=1.1.1", 674 | "phpunit/php-timer": ">=1.0.4", 675 | "phpunit/phpunit-mock-objects": "~1.2.0", 676 | "symfony/yaml": "~2.0" 677 | }, 678 | "require-dev": { 679 | "pear-pear/pear": "1.9.4" 680 | }, 681 | "suggest": { 682 | "ext-json": "*", 683 | "ext-simplexml": "*", 684 | "ext-tokenizer": "*", 685 | "phpunit/php-invoker": ">=1.1.0,<1.2.0" 686 | }, 687 | "bin": [ 688 | "composer/bin/phpunit" 689 | ], 690 | "type": "library", 691 | "extra": { 692 | "branch-alias": { 693 | "dev-master": "3.7.x-dev" 694 | } 695 | }, 696 | "autoload": { 697 | "classmap": [ 698 | "PHPUnit/" 699 | ] 700 | }, 701 | "notification-url": "https://packagist.org/downloads/", 702 | "include-path": [ 703 | "", 704 | "../../symfony/yaml/" 705 | ], 706 | "license": [ 707 | "BSD-3-Clause" 708 | ], 709 | "authors": [ 710 | { 711 | "name": "Sebastian Bergmann", 712 | "email": "sebastian@phpunit.de", 713 | "role": "lead" 714 | } 715 | ], 716 | "description": "The PHP Unit Testing framework.", 717 | "homepage": "http://www.phpunit.de/", 718 | "keywords": [ 719 | "phpunit", 720 | "testing", 721 | "xunit" 722 | ], 723 | "time": "2013-10-17 23:32:19" 724 | }, 725 | { 726 | "name": "phpunit/phpunit-mock-objects", 727 | "version": "1.2.x-dev", 728 | "source": { 729 | "type": "git", 730 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 731 | "reference": "3e40f3b3f18c044a24688fe406440d7fd537744a" 732 | }, 733 | "dist": { 734 | "type": "zip", 735 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3e40f3b3f18c044a24688fe406440d7fd537744a", 736 | "reference": "3e40f3b3f18c044a24688fe406440d7fd537744a", 737 | "shasum": "" 738 | }, 739 | "require": { 740 | "php": ">=5.3.3", 741 | "phpunit/php-text-template": ">=1.1.1@stable" 742 | }, 743 | "require-dev": { 744 | "pear-pear/pear": "1.9.4", 745 | "phpunit/phpunit": "3.7.*@dev" 746 | }, 747 | "suggest": { 748 | "ext-soap": "*" 749 | }, 750 | "type": "library", 751 | "extra": { 752 | "branch-alias": { 753 | "dev-master": "1.2.x-dev" 754 | } 755 | }, 756 | "autoload": { 757 | "classmap": [ 758 | "PHPUnit/" 759 | ] 760 | }, 761 | "notification-url": "https://packagist.org/downloads/", 762 | "include-path": [ 763 | "" 764 | ], 765 | "license": [ 766 | "BSD-3-Clause" 767 | ], 768 | "authors": [ 769 | { 770 | "name": "Sebastian Bergmann", 771 | "email": "sb@sebastian-bergmann.de", 772 | "role": "lead" 773 | } 774 | ], 775 | "description": "Mock Object library for PHPUnit", 776 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 777 | "keywords": [ 778 | "mock", 779 | "xunit" 780 | ], 781 | "time": "2013-07-23 04:42:59" 782 | }, 783 | { 784 | "name": "psr/log", 785 | "version": "1.0.0", 786 | "source": { 787 | "type": "git", 788 | "url": "https://github.com/php-fig/log.git", 789 | "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" 790 | }, 791 | "dist": { 792 | "type": "zip", 793 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", 794 | "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", 795 | "shasum": "" 796 | }, 797 | "type": "library", 798 | "autoload": { 799 | "psr-0": { 800 | "Psr\\Log\\": "" 801 | } 802 | }, 803 | "notification-url": "https://packagist.org/downloads/", 804 | "license": [ 805 | "MIT" 806 | ], 807 | "authors": [ 808 | { 809 | "name": "PHP-FIG", 810 | "homepage": "http://www.php-fig.org/" 811 | } 812 | ], 813 | "description": "Common interface for logging libraries", 814 | "keywords": [ 815 | "log", 816 | "psr", 817 | "psr-3" 818 | ], 819 | "time": "2012-12-21 11:40:51" 820 | }, 821 | { 822 | "name": "satooshi/php-coveralls", 823 | "version": "dev-master", 824 | "source": { 825 | "type": "git", 826 | "url": "https://github.com/satooshi/php-coveralls.git", 827 | "reference": "c95c07e971e4b687718f54fc3447a260fb989e16" 828 | }, 829 | "dist": { 830 | "type": "zip", 831 | "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/c95c07e971e4b687718f54fc3447a260fb989e16", 832 | "reference": "c95c07e971e4b687718f54fc3447a260fb989e16", 833 | "shasum": "" 834 | }, 835 | "require": { 836 | "ext-json": "*", 837 | "ext-simplexml": "*", 838 | "guzzle/guzzle": ">=3.0", 839 | "php": ">=5.3", 840 | "psr/log": "1.0.0", 841 | "symfony/config": ">=2.0", 842 | "symfony/console": ">=2.0", 843 | "symfony/stopwatch": ">=2.2", 844 | "symfony/yaml": ">=2.0" 845 | }, 846 | "require-dev": { 847 | "apigen/apigen": "2.8.*@stable", 848 | "pdepend/pdepend": "dev-master", 849 | "phpmd/phpmd": "dev-master", 850 | "phpunit/php-invoker": ">=1.1.0,<1.2.0", 851 | "phpunit/phpunit": "3.7.*@stable", 852 | "sebastian/finder-facade": "dev-master", 853 | "sebastian/phpcpd": "1.4.*@stable", 854 | "squizlabs/php_codesniffer": "1.4.*@stable", 855 | "theseer/fdomdocument": "dev-master" 856 | }, 857 | "suggest": { 858 | "symfony/http-kernel": "Allows Symfony integration" 859 | }, 860 | "bin": [ 861 | "composer/bin/coveralls" 862 | ], 863 | "type": "library", 864 | "autoload": { 865 | "psr-0": { 866 | "Satooshi\\Component": "src/", 867 | "Satooshi\\Bundle": "src/" 868 | } 869 | }, 870 | "notification-url": "https://packagist.org/downloads/", 871 | "license": [ 872 | "MIT" 873 | ], 874 | "authors": [ 875 | { 876 | "name": "Kitamura Satoshi", 877 | "email": "with.no.parachute@gmail.com", 878 | "homepage": "https://www.facebook.com/satooshi.jp" 879 | } 880 | ], 881 | "description": "PHP client library for Coveralls API", 882 | "homepage": "https://github.com/satooshi/php-coveralls", 883 | "keywords": [ 884 | "ci", 885 | "coverage", 886 | "github", 887 | "test" 888 | ], 889 | "time": "2013-07-25 11:22:39" 890 | }, 891 | { 892 | "name": "symfony/config", 893 | "version": "dev-master", 894 | "target-dir": "Symfony/Component/Config", 895 | "source": { 896 | "type": "git", 897 | "url": "https://github.com/symfony/Config.git", 898 | "reference": "9a3c831697349cf6e9b5302b7beb0b97e6cdac41" 899 | }, 900 | "dist": { 901 | "type": "zip", 902 | "url": "https://api.github.com/repos/symfony/Config/zipball/9a3c831697349cf6e9b5302b7beb0b97e6cdac41", 903 | "reference": "9a3c831697349cf6e9b5302b7beb0b97e6cdac41", 904 | "shasum": "" 905 | }, 906 | "require": { 907 | "php": ">=5.3.3", 908 | "symfony/filesystem": "~2.3" 909 | }, 910 | "type": "library", 911 | "extra": { 912 | "branch-alias": { 913 | "dev-master": "2.4-dev" 914 | } 915 | }, 916 | "autoload": { 917 | "psr-0": { 918 | "Symfony\\Component\\Config\\": "" 919 | } 920 | }, 921 | "notification-url": "https://packagist.org/downloads/", 922 | "license": [ 923 | "MIT" 924 | ], 925 | "authors": [ 926 | { 927 | "name": "Fabien Potencier", 928 | "email": "fabien@symfony.com" 929 | }, 930 | { 931 | "name": "Symfony Community", 932 | "homepage": "http://symfony.com/contributors" 933 | } 934 | ], 935 | "description": "Symfony Config Component", 936 | "homepage": "http://symfony.com", 937 | "time": "2013-09-19 09:47:34" 938 | }, 939 | { 940 | "name": "symfony/console", 941 | "version": "dev-master", 942 | "target-dir": "Symfony/Component/Console", 943 | "source": { 944 | "type": "git", 945 | "url": "https://github.com/symfony/Console.git", 946 | "reference": "eca72b22138f66f4244a3eddc18c7261cfcd130c" 947 | }, 948 | "dist": { 949 | "type": "zip", 950 | "url": "https://api.github.com/repos/symfony/Console/zipball/eca72b22138f66f4244a3eddc18c7261cfcd130c", 951 | "reference": "eca72b22138f66f4244a3eddc18c7261cfcd130c", 952 | "shasum": "" 953 | }, 954 | "require": { 955 | "php": ">=5.3.3" 956 | }, 957 | "require-dev": { 958 | "symfony/event-dispatcher": "~2.1" 959 | }, 960 | "suggest": { 961 | "symfony/event-dispatcher": "" 962 | }, 963 | "type": "library", 964 | "extra": { 965 | "branch-alias": { 966 | "dev-master": "2.4-dev" 967 | } 968 | }, 969 | "autoload": { 970 | "psr-0": { 971 | "Symfony\\Component\\Console\\": "" 972 | } 973 | }, 974 | "notification-url": "https://packagist.org/downloads/", 975 | "license": [ 976 | "MIT" 977 | ], 978 | "authors": [ 979 | { 980 | "name": "Fabien Potencier", 981 | "email": "fabien@symfony.com" 982 | }, 983 | { 984 | "name": "Symfony Community", 985 | "homepage": "http://symfony.com/contributors" 986 | } 987 | ], 988 | "description": "Symfony Console Component", 989 | "homepage": "http://symfony.com", 990 | "time": "2013-10-30 08:33:58" 991 | }, 992 | { 993 | "name": "symfony/event-dispatcher", 994 | "version": "dev-master", 995 | "target-dir": "Symfony/Component/EventDispatcher", 996 | "source": { 997 | "type": "git", 998 | "url": "https://github.com/symfony/EventDispatcher.git", 999 | "reference": "d51d78b34c1d9dcc384ba48155105fe99284dd67" 1000 | }, 1001 | "dist": { 1002 | "type": "zip", 1003 | "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/d51d78b34c1d9dcc384ba48155105fe99284dd67", 1004 | "reference": "d51d78b34c1d9dcc384ba48155105fe99284dd67", 1005 | "shasum": "" 1006 | }, 1007 | "require": { 1008 | "php": ">=5.3.3" 1009 | }, 1010 | "require-dev": { 1011 | "symfony/dependency-injection": "~2.0" 1012 | }, 1013 | "suggest": { 1014 | "symfony/dependency-injection": "", 1015 | "symfony/http-kernel": "" 1016 | }, 1017 | "type": "library", 1018 | "extra": { 1019 | "branch-alias": { 1020 | "dev-master": "2.4-dev" 1021 | } 1022 | }, 1023 | "autoload": { 1024 | "psr-0": { 1025 | "Symfony\\Component\\EventDispatcher\\": "" 1026 | } 1027 | }, 1028 | "notification-url": "https://packagist.org/downloads/", 1029 | "license": [ 1030 | "MIT" 1031 | ], 1032 | "authors": [ 1033 | { 1034 | "name": "Fabien Potencier", 1035 | "email": "fabien@symfony.com" 1036 | }, 1037 | { 1038 | "name": "Symfony Community", 1039 | "homepage": "http://symfony.com/contributors" 1040 | } 1041 | ], 1042 | "description": "Symfony EventDispatcher Component", 1043 | "homepage": "http://symfony.com", 1044 | "time": "2013-10-17 11:48:11" 1045 | }, 1046 | { 1047 | "name": "symfony/filesystem", 1048 | "version": "dev-master", 1049 | "target-dir": "Symfony/Component/Filesystem", 1050 | "source": { 1051 | "type": "git", 1052 | "url": "https://github.com/symfony/Filesystem.git", 1053 | "reference": "e558fd5d593ebe083dca199f52aed5374ab7b57a" 1054 | }, 1055 | "dist": { 1056 | "type": "zip", 1057 | "url": "https://api.github.com/repos/symfony/Filesystem/zipball/e558fd5d593ebe083dca199f52aed5374ab7b57a", 1058 | "reference": "e558fd5d593ebe083dca199f52aed5374ab7b57a", 1059 | "shasum": "" 1060 | }, 1061 | "require": { 1062 | "php": ">=5.3.3" 1063 | }, 1064 | "type": "library", 1065 | "extra": { 1066 | "branch-alias": { 1067 | "dev-master": "2.4-dev" 1068 | } 1069 | }, 1070 | "autoload": { 1071 | "psr-0": { 1072 | "Symfony\\Component\\Filesystem\\": "" 1073 | } 1074 | }, 1075 | "notification-url": "https://packagist.org/downloads/", 1076 | "license": [ 1077 | "MIT" 1078 | ], 1079 | "authors": [ 1080 | { 1081 | "name": "Fabien Potencier", 1082 | "email": "fabien@symfony.com" 1083 | }, 1084 | { 1085 | "name": "Symfony Community", 1086 | "homepage": "http://symfony.com/contributors" 1087 | } 1088 | ], 1089 | "description": "Symfony Filesystem Component", 1090 | "homepage": "http://symfony.com", 1091 | "time": "2013-09-27 14:57:51" 1092 | }, 1093 | { 1094 | "name": "symfony/stopwatch", 1095 | "version": "dev-master", 1096 | "target-dir": "Symfony/Component/Stopwatch", 1097 | "source": { 1098 | "type": "git", 1099 | "url": "https://github.com/symfony/Stopwatch.git", 1100 | "reference": "0e5f6c61dd5bc6e7ebd810a86ed5f516e99a01a0" 1101 | }, 1102 | "dist": { 1103 | "type": "zip", 1104 | "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/0e5f6c61dd5bc6e7ebd810a86ed5f516e99a01a0", 1105 | "reference": "0e5f6c61dd5bc6e7ebd810a86ed5f516e99a01a0", 1106 | "shasum": "" 1107 | }, 1108 | "require": { 1109 | "php": ">=5.3.3" 1110 | }, 1111 | "type": "library", 1112 | "extra": { 1113 | "branch-alias": { 1114 | "dev-master": "2.4-dev" 1115 | } 1116 | }, 1117 | "autoload": { 1118 | "psr-0": { 1119 | "Symfony\\Component\\Stopwatch\\": "" 1120 | } 1121 | }, 1122 | "notification-url": "https://packagist.org/downloads/", 1123 | "license": [ 1124 | "MIT" 1125 | ], 1126 | "authors": [ 1127 | { 1128 | "name": "Fabien Potencier", 1129 | "email": "fabien@symfony.com" 1130 | }, 1131 | { 1132 | "name": "Symfony Community", 1133 | "homepage": "http://symfony.com/contributors" 1134 | } 1135 | ], 1136 | "description": "Symfony Stopwatch Component", 1137 | "homepage": "http://symfony.com", 1138 | "time": "2013-10-17 11:48:11" 1139 | }, 1140 | { 1141 | "name": "symfony/yaml", 1142 | "version": "dev-master", 1143 | "target-dir": "Symfony/Component/Yaml", 1144 | "source": { 1145 | "type": "git", 1146 | "url": "https://github.com/symfony/Yaml.git", 1147 | "reference": "1f7cabb841e62ec49615bd965ac780fd994b3f64" 1148 | }, 1149 | "dist": { 1150 | "type": "zip", 1151 | "url": "https://api.github.com/repos/symfony/Yaml/zipball/1f7cabb841e62ec49615bd965ac780fd994b3f64", 1152 | "reference": "1f7cabb841e62ec49615bd965ac780fd994b3f64", 1153 | "shasum": "" 1154 | }, 1155 | "require": { 1156 | "php": ">=5.3.3" 1157 | }, 1158 | "type": "library", 1159 | "extra": { 1160 | "branch-alias": { 1161 | "dev-master": "2.4-dev" 1162 | } 1163 | }, 1164 | "autoload": { 1165 | "psr-0": { 1166 | "Symfony\\Component\\Yaml\\": "" 1167 | } 1168 | }, 1169 | "notification-url": "https://packagist.org/downloads/", 1170 | "license": [ 1171 | "MIT" 1172 | ], 1173 | "authors": [ 1174 | { 1175 | "name": "Fabien Potencier", 1176 | "email": "fabien@symfony.com" 1177 | }, 1178 | { 1179 | "name": "Symfony Community", 1180 | "homepage": "http://symfony.com/contributors" 1181 | } 1182 | ], 1183 | "description": "Symfony Yaml Component", 1184 | "homepage": "http://symfony.com", 1185 | "time": "2013-10-17 11:48:11" 1186 | } 1187 | ], 1188 | "aliases": [ 1189 | 1190 | ], 1191 | "minimum-stability": "dev", 1192 | "stability-flags": { 1193 | "satooshi/php-coveralls": 20, 1194 | "mockery/mockery": 20 1195 | }, 1196 | "platform": { 1197 | "php": ">=5.4.0" 1198 | }, 1199 | "platform-dev": [ 1200 | 1201 | ] 1202 | } 1203 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | 20 | src/ 21 | 22 | 23 | vendor/ 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Filter/Facades/Filter.php: -------------------------------------------------------------------------------- 1 | parseRules($rules); 26 | $filtered = array(); 27 | 28 | foreach ($values as $field => $value) { 29 | if (array_key_exists($field, $rules)) { 30 | // Call each filter 31 | foreach ($rules[$field] as $filter => $args) { 32 | $value = $this->callFilter($filter, $value, $args); 33 | } 34 | } 35 | $filtered[$field] = $value; 36 | } 37 | 38 | return $filtered; 39 | } 40 | 41 | /** 42 | * Filter a single value 43 | * @param mixed $value 44 | * @param array|string $rules 45 | * @return mixed Filtered value 46 | */ 47 | public function filterOne($value, $rules) { 48 | return $this->filter(['_' => $rules], ['_' => $value])['_']; 49 | } 50 | 51 | /** 52 | * Register a callback filter 53 | * @param string $name 54 | * @param callable $filter 55 | * @throws Exception If filter already registered 56 | * @throws Exception If filter is not Callable 57 | */ 58 | public function registerFilter($name, $filter) 59 | { 60 | if (array_key_exists($name, $this->filters)) { 61 | throw new \Exception("Filter named '$name' already registered"); 62 | } 63 | 64 | if (is_string($filter)) { 65 | $filter = new $filter; 66 | } 67 | 68 | if (!is_callable($filter)) { 69 | throw new \Exception('Filter should be callable'); 70 | } 71 | 72 | $this->filters[$name] = $filter; 73 | } 74 | 75 | /** 76 | * Unregister a callback filter 77 | * @param string $name 78 | */ 79 | public function unregisterFilter($name) { 80 | if (array_key_exists($name, $this->filters)) { 81 | unset($this->filters[$name]); 82 | } 83 | } 84 | 85 | /** 86 | * Get a list of registered filters 87 | * @return array List of registered filters 88 | */ 89 | public function getFilters() 90 | { 91 | return array_keys($this->filters); 92 | } 93 | 94 | /** 95 | * Call a filter 96 | * @param string $name Filter name 97 | * @param mixed $value Value to filter 98 | * @param array $args Arguments to the filter 99 | * @return mixed Filtered value 100 | */ 101 | protected function callFilter($name, $value, $args=array()) 102 | { 103 | if (!array_key_exists($name, $this->filters)) { 104 | throw new \Exception("No filter named '$name' registered"); 105 | } 106 | 107 | return call_user_func($this->filters[$name], $value, $args); 108 | } 109 | 110 | /** 111 | * Return filter rules for each field 112 | * 113 | * Example input: ['field' => 'strtoupper|lcfirst|ltrim:.,",",_'] 114 | * Output: ['field' => ['strtoupper' => [], ... ltrim' => ['.', ',', '_']]] 115 | * 116 | * Each filter name is separated by a pipe. 117 | * Filters can have arguments, specified after a colon, which are split by 118 | * comma using the same rules as str_getcsv. 119 | * 120 | * @param string $rules 121 | * @return array Parsed rules 122 | */ 123 | protected function parseRules($rules) { 124 | foreach ($rules as $key => &$field_rules) { 125 | $filters = is_string($field_rules) ? explode('|', $field_rules) : $field_rules; 126 | $field_rules = $this->parseFilters($filters); 127 | } 128 | 129 | return $rules; 130 | } 131 | 132 | /** 133 | * Parse a specific filter 134 | * @see Filter::parseRules() for syntax information 135 | * @param array $filters 136 | * @return array Filter rules 137 | */ 138 | protected function parseFilters($filters) { 139 | foreach ($filters as $index => $filter) { 140 | if (strpos($filter, ':') === false) { 141 | $filters[$filter] = []; 142 | } else { 143 | list($name, $args) = explode(':', $filter, 2); 144 | $args = str_getcsv($args); 145 | $filters[$name] = $args; 146 | } 147 | 148 | unset($filters[$index]); 149 | } 150 | 151 | return $filters; 152 | } 153 | 154 | /** 155 | * Register some default filters 156 | */ 157 | public function registerDefaultFilters() 158 | { 159 | $this->registerFilter('trim', function($value, array $args) { 160 | if (count($args) > 0) { 161 | return trim($value, implode($args)); 162 | } else { 163 | return trim($value); 164 | } 165 | }); 166 | 167 | $this->registerFilter('ltrim', function($value, array $args) { 168 | if (count($args) > 0) { 169 | return ltrim($value, implode($args)); 170 | } else { 171 | return ltrim($value); 172 | } 173 | }); 174 | 175 | $this->registerFilter('rtrim', function($value, array $args) { 176 | if (count($args) > 0) { 177 | return rtrim($value, implode($args)); 178 | } else { 179 | return rtrim($value); 180 | } 181 | }); 182 | 183 | $this->registerFilter('upper', function($value, array $args) { 184 | return strtoupper($value); 185 | }); 186 | 187 | $this->registerFilter('lower', function($value, array $args) { 188 | return strtolower($value); 189 | }); 190 | 191 | $this->registerFilter('capfirst', function($value, array $args) { 192 | return ucfirst($value); 193 | }); 194 | 195 | $this->registerFilter('lowerfirst', function($value, array $args) { 196 | return lcfirst($value); 197 | }); 198 | } 199 | } -------------------------------------------------------------------------------- /src/Filter/FilterInterface.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | interface FilterInterface 9 | { 10 | public function __invoke($value); 11 | } -------------------------------------------------------------------------------- /src/Filter/FilterServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton('filter', function ($app) { 26 | $filter = new Filter(); 27 | $filter->registerDefaultFilters(); 28 | return $filter; 29 | }); 30 | } 31 | 32 | /** 33 | * Instances provided by the service 34 | */ 35 | public function provides() 36 | { 37 | return array('filter'); 38 | } 39 | 40 | /** 41 | * Build a new Laravel 4 container, add and boot the service to it 42 | * Used when a Laravel 4 application does not exist from the Facade 43 | * 44 | * @return \Illuminate\Container\Container 45 | */ 46 | public static function make() 47 | { 48 | $app = new \Illuminate\Container\Container; 49 | $service = new self($app); 50 | $service->boot(); 51 | 52 | return $app; 53 | } 54 | } -------------------------------------------------------------------------------- /src/Filter/HasFilters.php: -------------------------------------------------------------------------------- 1 | output) && array_key_exists($key, $this->output)) { 29 | $value = Filter::filterOne($this->output[$key], $value); 30 | } 31 | 32 | return $value; 33 | } 34 | 35 | /** 36 | * Override mutators to add input filters 37 | * 38 | * @param string $key 39 | * @param mixed $value 40 | */ 41 | public function setAttribute($key, $value) 42 | { 43 | if (isset($this->input) && array_key_exists($key, $this->input)) { 44 | $value = Filter::filterOne($this->input[$key], $value); 45 | } 46 | 47 | parent::setAttribute($key, $value); 48 | } 49 | } -------------------------------------------------------------------------------- /tests/Filter/FilterServiceProviderTest.php: -------------------------------------------------------------------------------- 1 | app = m::mock('Illuminate\Support\Container'); 15 | $this->provider = new FilterServiceProvider($this->app); 16 | } 17 | 18 | public function testRegister() 19 | { 20 | $this->provider->register(); 21 | } 22 | 23 | public function testBoot() 24 | { 25 | // Make sure that boot() registers the singleton instance 26 | $this->app 27 | ->shouldReceive('singleton') 28 | ->with('filter', m::on(function($closure) { 29 | // The closure should create an instance of Filter\Filter 30 | return call_user_func($closure, null) instanceof Filter; 31 | })) 32 | ->times(1); 33 | 34 | $this->provider->boot(); 35 | } 36 | 37 | public function testProvides() 38 | { 39 | $this->assertContains('filter', $this->provider->provides()); 40 | } 41 | } -------------------------------------------------------------------------------- /tests/Filter/FilterTest.php: -------------------------------------------------------------------------------- 1 | filter = new Filter; 12 | $this->filter->registerDefaultFilters(); 13 | } 14 | 15 | public function testSingleRule() { 16 | $this->assertEquals('tEST', $this->filter->filterOne('upper|lowerfirst', 'Test')); 17 | } 18 | 19 | public function testNonExistantRule() { 20 | $this->setExpectedException('Exception', "No filter named 'dummy' registered"); 21 | $this->filter->filterOne('dummy', 'test'); 22 | } 23 | 24 | public function testUppercase() { 25 | $this->assertEquals('TEST', $this->filter->filterOne('upper', 'teSt')); 26 | } 27 | 28 | public function testLowercase() { 29 | $this->assertEquals('test', $this->filter->filterOne('lower', 'teSt')); 30 | } 31 | 32 | public function testCapitalize() { 33 | $this->assertEquals('TeSt', $this->filter->filterOne('capfirst', 'teSt')); 34 | } 35 | 36 | public function testUncapfirst() { 37 | $this->assertEquals('tEsT', $this->filter->filterOne('lowerfirst', 'tEsT')); 38 | } 39 | 40 | public function testTrim() { 41 | $this->assertEquals("asdf", $this->filter->filterOne('trim', "\n\t asdf \n\t")); 42 | } 43 | 44 | public function testTrimArgs() { 45 | $this->assertEquals('asdf', $this->filter->filterOne('trim:#,$', '$asdf#')); 46 | $this->assertEquals('asdf', $this->filter->filterOne('trim:.,","', 'asdf..,.')); 47 | } 48 | 49 | public function testLeftTrim() { 50 | $this->assertEquals("asdf \n\t", $this->filter->filterOne('ltrim', "\n\t asdf \n\t")); 51 | } 52 | 53 | public function testLeftTrimArgs() { 54 | $this->assertEquals('asdf#', $this->filter->filterOne('ltrim:#,$', '$asdf#')); 55 | } 56 | 57 | public function testRightTrim() { 58 | $this->assertEquals("\n\t asdf", $this->filter->filterOne('rtrim', "\n\t asdf \n\t")); 59 | } 60 | 61 | public function testRightTrimArgs() { 62 | $this->assertEquals('$asdf', $this->filter->filterOne('rtrim:#,$', '$asdf#')); 63 | } 64 | 65 | public function testOrdering() { 66 | $this->assertEquals('tEST', $this->filter->filterOne('lower|upper|lowerfirst', 'test')); 67 | } 68 | 69 | public function testCustomFilter() { 70 | $this->assertNotContains('reverse', $this->filter->getFilters()); 71 | 72 | $reverse = function($string) { 73 | return strrev($string); 74 | }; 75 | $this->filter->registerFilter('reverse', $reverse); 76 | 77 | $this->assertEquals('dlrow olleh', $this->filter->filterOne('reverse', 'hello world')); 78 | } 79 | 80 | public function testRegisterFilterTwice() { 81 | $this->filter->registerFilter('dummy', function($str) { return $str; }); 82 | $this->setExpectedException('Exception', "Filter named 'dummy' already registered"); 83 | $this->filter->registerFilter('dummy', function($str) { return $str; }); 84 | } 85 | 86 | public function testUnregisterFilter() { 87 | $this->assertContains('trim', $this->filter->getFilters()); 88 | $this->filter->unregisterFilter('trim'); 89 | $this->assertNotContains('trim', $this->filter->getFilters()); 90 | } 91 | 92 | public function testRegisterUncallableFilter() { 93 | $this->setExpectedException('Exception', "Filter should be callable"); 94 | $this->filter->registerFilter('uninvokable', new \stdClass); 95 | } 96 | 97 | public function testRegisterFilterByClassName() { 98 | $this->filter->registerFilter('by_class_name', 'Filter\TestFilter'); 99 | $this->assertEquals('TestFilter', $this->filter->filterOne('by_class_name', 'test')); 100 | } 101 | } 102 | 103 | class TestFilter 104 | { 105 | public function __invoke($str) { 106 | return 'TestFilter'; 107 | } 108 | } -------------------------------------------------------------------------------- /tests/Filter/HasFiltersTest.php: -------------------------------------------------------------------------------- 1 | 'trim', 13 | 'city' => 'trim', 14 | 'postcode' => 'upper|trim', 15 | 'country' => 'trim', 16 | ); 17 | 18 | protected $output = array( 19 | 'city' => 'upper', 20 | 'country' => 'upper', 21 | ); 22 | 23 | /** 24 | * Mutator for Country - should have passed through setAttribute first 25 | * 26 | * @param string $value The filtered input value 27 | */ 28 | public function setCountryAttribute($value) { 29 | $this->attributes['country'] = $value . '_input'; 30 | } 31 | 32 | /** 33 | * Accessor for Country - result should be passed through getAttribute 34 | * 35 | * @param string The unfiltered output value 36 | */ 37 | public function getCountryAttribute($value) { 38 | return $value . '_output'; 39 | } 40 | } 41 | 42 | class HasFiltersTest extends \PHPUnit_Framework_TestCase 43 | { 44 | public function setUp() 45 | { 46 | $this->address = new Address; 47 | } 48 | 49 | public function testInputs() 50 | { 51 | $this->address->line1 = '123 Bank Rd '; 52 | $this->address->city = ' London '; 53 | $this->address->postcode = 'sw1 1aa '; 54 | $this->address->country = ' england '; 55 | 56 | // Get attrs without using the overridden getAttribute() 57 | $raw = $this->address->getAttributes(); 58 | $this->assertEquals('123 Bank Rd', $raw['line1']); 59 | $this->assertEquals('London', $raw['city']); 60 | $this->assertEquals('SW1 1AA', $raw['postcode']); 61 | $this->assertEquals('england_input', $raw['country']); 62 | } 63 | 64 | public function testOutputs() 65 | { 66 | $this->address->setRawAttributes(array( 67 | 'city' => 'London', 68 | 'country' => 'england', 69 | )); 70 | 71 | $this->assertEquals('LONDON', $this->address->city); 72 | $this->assertEquals('ENGLAND_OUTPUT', $this->address->country); 73 | } 74 | 75 | public function testMassAssignmentFill() 76 | { 77 | $this->address->fill(array( 78 | 'country' => ' england ' 79 | )); 80 | 81 | $raw = $this->address->getAttributes(); 82 | $this->assertEquals('england_input', $raw['country']); 83 | } 84 | 85 | public function testMassAssignmentConstructor() 86 | { 87 | $this->address = new Address(array('postcode' => 'sw1 1aa ')); 88 | $raw = $this->address->getAttributes(); 89 | $this->assertEquals('SW1 1AA', $raw['postcode']); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 |