├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── FbBotApp.php ├── LICENSE.txt ├── Menu ├── LocalizedMenu.php └── MenuItem.php ├── Messages ├── AccountLink.php ├── Address.php ├── Adjustment.php ├── Attachment.php ├── AudioMessage.php ├── FileMessage.php ├── ImageMessage.php ├── Message.php ├── MessageButton.php ├── MessageDefaultAction.php ├── MessageElement.php ├── MessageMediaElement.php ├── MessageReceiptElement.php ├── QuickReply.php ├── QuickReplyButton.php ├── SenderAction.php ├── StructuredMessage.php ├── Summary.php └── VideoMessage.php ├── README.md ├── UserProfile.php ├── composer.json ├── composer.lock ├── phpunit.xml.dist └── tests ├── Mocks ├── Menu │ ├── LocalizedMenu │ │ ├── default.json │ │ └── default_no_items.json │ └── MenuItem │ │ ├── nested.json │ │ ├── postback.json │ │ └── web.json ├── Messages │ ├── AccountLink │ │ ├── link.json │ │ └── unlink.json │ └── SenderAction │ │ ├── mark_seen.json │ │ ├── typing_off.json │ │ └── typing_on.json └── Response │ └── User │ └── user.json └── TestCase ├── AbstractTestCase.php ├── Menu ├── LocalizedMenuTest.php └── MenuItemTest.php ├── Messages ├── AccountLinkTest.php └── SenderActionTest.php └── UserProfile └── UserProfileTest.php /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Would you like assistance or advice? 2 | 3 | Issue description 4 | 5 | Steps to reproduce 6 | 7 | Traceback or other info 8 | 9 | * fb-messenger-php version: x.x.x / master@commit 10 | * PHP version: x.x.x 11 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Fixes #[include a number of issue this PR is fixing]. 2 | 3 | Summary of changes proposed in this Pull Request: 4 | - 5 | - 6 | - 7 | 8 | PR checklist: 9 | - [ ] Updated relevant documentation 10 | - [ ] Updated CHANGELOG.md 11 | - [ ] Added tests for my change -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### OSX template 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | 21 | # Directories potentially created on remote AFP share 22 | .AppleDB 23 | .AppleDesktop 24 | Network Trash Folder 25 | Temporary Items 26 | .apdisk 27 | ### JetBrains template 28 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 29 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 30 | 31 | # User-specific stuff: 32 | .idea/workspace.xml 33 | .idea/tasks.xml 34 | .idea/dictionaries 35 | .idea/vcs.xml 36 | .idea/jsLibraryMappings.xml 37 | 38 | # Sensitive or high-churn files: 39 | .idea/dataSources.ids 40 | .idea/dataSources.xml 41 | .idea/dataSources.local.xml 42 | .idea/sqlDataSources.xml 43 | .idea/dynamic.xml 44 | .idea/uiDesigner.xml 45 | 46 | # Gradle: 47 | .idea/gradle.xml 48 | .idea/libraries 49 | 50 | # Mongo Explorer plugin: 51 | .idea/mongoSettings.xml 52 | 53 | ## File-based project format: 54 | *.iws 55 | 56 | ## Plugin-specific files: 57 | 58 | # IntelliJ 59 | /out/ 60 | 61 | # mpeltonen/sbt-idea plugin 62 | .idea_modules/ 63 | 64 | # JIRA plugin 65 | atlassian-ide-plugin.xml 66 | 67 | # Crashlytics plugin (for Android Studio and IntelliJ) 68 | com_crashlytics_export_strings.xml 69 | crashlytics.properties 70 | crashlytics-build.properties 71 | fabric.properties 72 | 73 | # composer 74 | /vendor/ 75 | composer.phar 76 | 77 | # Project 78 | phpunit.phar 79 | .phpunit.result.cache 80 | phpunit.xml 81 | /build/ 82 | .env 83 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | php: 6 | - 7.1 7 | - 7.2 8 | - 7.3 9 | 10 | branches: 11 | only: 12 | - master 13 | - fb-travis-ci 14 | 15 | before_script: 16 | - travis_retry composer self-update 17 | - travis_retry composer install --no-interaction --prefer-source 18 | 19 | script: 20 | - vendor/bin/phpunit 21 | 22 | after_success: 23 | - bash <(curl -s https://codecov.io/bash) 24 | 25 | cache: 26 | directories: 27 | - $HOME/.composer/cache 28 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v1.2.3 (in development) 2 | 3 | ### New features & improvements: 4 | - Update required php version to 7.1.3 (https://www.php.net/supported-versions.php) 5 | - Add descriptions 6 | - Add tests 7 | 8 | ### Bug fixes: 9 | - Add missing ";" 10 | 11 | ## v1.2.2 (release date: 13th April 2019) 12 | 13 | ### New features & improvements: 14 | - Add appsecret_proof support 15 | 16 | ### Bug fixes: 17 | - Hotfixes in class FbBotApp 18 | 19 | ## v1.2.1 (release date: 04th April 2019) 20 | 21 | ### Bug fixes: 22 | - Add missing ";" to $apiVersion declaration in class FbBotApp 23 | 24 | 25 | ## v1.2 (release date: 02th April 2019) 26 | 27 | ### New features & improvements: 28 | - Add user_phone_number & user_email to QuickReplyButton.php 29 | - Add api version selection in the constructor of the class FbBotApp 30 | 31 | 32 | ## v1.1.1 (release date: 15th November 2018) 33 | 34 | ### Bug fixes: 35 | - removing last_ad_referral & is_payment_enabled from profile fields 36 | 37 | ## v1.1 (release date: 9th November 2018) 38 | 39 | ### Bug fixes: 40 | - Change NON_PROMOTIONAL_SUBSCRIPTION from type to tag 41 | 42 | 43 | ## v1.0 (release date: 12th May 2016) 44 | 45 | ### New features & improvements: 46 | - First stable version 47 | -------------------------------------------------------------------------------- /FbBotApp.php: -------------------------------------------------------------------------------- 1 | token = $token; 71 | 72 | if (is_null($version)) { 73 | $version = $this->apiVersion; 74 | } 75 | 76 | if (!is_null($app_secret)) { 77 | $this->appsecret_proof = hash_hmac('sha256', $this->token, $app_secret); 78 | } 79 | 80 | $this->apiUrl = $this->baseApiUrl . $version . "/"; 81 | } 82 | 83 | /** 84 | * Send Message 85 | * 86 | * @param Message $message 87 | * @return array 88 | */ 89 | public function send($message) 90 | { 91 | return $this->call('me/messages', $message->getData()); 92 | } 93 | 94 | public function batch($messages) 95 | { 96 | //Max 50 Requests per batch send 97 | $max_batch_count = 50; 98 | $count = 0; 99 | $data = []; 100 | $response = []; 101 | 102 | foreach ($messages as $message) { 103 | 104 | $message_data = $message->getData(); 105 | 106 | $data['batch'][] = [ 107 | "method" => "POST", 108 | "relative_url" => "me/messages", 109 | "body" => http_build_query($message_data) 110 | ]; 111 | 112 | $count++; 113 | 114 | 115 | if ( $count === $max_batch_count ) { 116 | $data['batch'] = json_encode($data['batch']); 117 | $response = array_merge($response, $this->call('/', $data)); 118 | $data['batch'] = []; 119 | $count = 0; 120 | } 121 | 122 | } 123 | 124 | //send out last batch 125 | if ( !empty($data['batch']) ) { 126 | $data['batch'] = json_encode($data['batch']); 127 | $response = array_merge($response, $this->call('me/messages', $data)); 128 | } 129 | 130 | return $response; 131 | } 132 | 133 | public function batchIds($fb_ids, $message) 134 | { 135 | //Less resource intensive version 136 | 137 | //Max 50 Requests per batch send 138 | $max_batch_count = 50; 139 | $count = 0; 140 | $data = []; 141 | $response = []; 142 | $message_data = $message->getData(); 143 | 144 | foreach ($fb_ids as $fb_id) { 145 | 146 | $message_data['recipient']['id'] = $fb_id; 147 | 148 | $data['batch'][] = [ 149 | "method" => "POST", 150 | "relative_url" => "me/messages", 151 | "body" => http_build_query($message_data) 152 | ]; 153 | 154 | $count++; 155 | 156 | if ( $count === $max_batch_count ) { 157 | $data['batch'] = json_encode($data['batch']); 158 | $response = array_merge($response, $this->call('/', $data)); 159 | $data['batch'] = []; 160 | $count = 0; 161 | } 162 | } 163 | 164 | //send out last batch 165 | if ( !empty($data['batch']) ) { 166 | $data['batch'] = json_encode($data['batch']); 167 | $response = array_merge($response, $this->call('me/messages', $data)); 168 | } 169 | 170 | return $response; 171 | } 172 | 173 | /** 174 | * Debugging Tool - Can accept an object, array, string, number 175 | * 176 | * @param Message $message 177 | * @return array 178 | */ 179 | public function debug($fb_id, $message) 180 | { 181 | 182 | $responses = []; 183 | 184 | $maxlength = 2000; 185 | 186 | $length = strlen(json_encode( $message, JSON_UNESCAPED_SLASHES ) ); 187 | 188 | $pages = ceil($length/$maxlength); 189 | 190 | for ($x=0; $x<$pages; $x++) { 191 | 192 | $responses[] = $this->send( new Message($fb_id,substr( json_encode( $message, JSON_UNESCAPED_SLASHES ), $x*$maxlength, $maxlength), false, "ISSUE_RESOLUTION", "REGULAR", "MESSAGE_TAG" ) ); 193 | 194 | } 195 | 196 | return $responses; 197 | 198 | } 199 | 200 | /** 201 | * Upload File (image, audio, video, file) 202 | * 203 | * @see Attachment Reuse on https://developers.facebook.com/docs/messenger-platform/send-api-reference 204 | * @param Messages\Attachment $attachment 205 | * @return array contains attachment_id (if successfully uploaded). 206 | */ 207 | public function upload($attachment) 208 | { 209 | $data = $attachment->getData(); 210 | $data['attachment']['payload']['is_reusable'] = true; 211 | return $this->call('me/message_attachments',[ 212 | 'message' => $data 213 | ], self::TYPE_POST); 214 | } 215 | 216 | /** 217 | * Get User Profile Info 218 | * 219 | * @param int $id 220 | * @param string $fields 221 | * @return UserProfile 222 | */ 223 | public function userProfile($id, $fields = 'first_name,last_name,profile_pic,locale,timezone,gender') 224 | { 225 | return new UserProfile($this->call($id, [ 226 | 'fields' => $fields 227 | ], self::TYPE_GET)); 228 | } 229 | 230 | /** 231 | * Set Get Started Button 232 | * 233 | * @see https://developers.facebook.com/docs/messenger-platform/thread-settings/get-started-button 234 | * @param string $payload 235 | * @return array 236 | */ 237 | public function setGetStartedButton($payload) 238 | { 239 | return $this->call('me/messenger_profile', [ 240 | 'get_started' => ['payload' => $payload] 241 | ], self::TYPE_POST); 242 | } 243 | 244 | /** 245 | * Delete Get Started Button 246 | * 247 | * @see https://developers.facebook.com/docs/messenger-platform/thread-settings/get-started-button 248 | * @return array 249 | */ 250 | public function deleteGetStartedButton() 251 | { 252 | return $this->call('me/messenger_profile', [ 253 | 'fields' => ['get_started'], 254 | ], self::TYPE_DELETE); 255 | } 256 | 257 | 258 | /** 259 | * Set Greeting Message 260 | * 261 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/greeting-text 262 | * @param array $localizedGreetings 263 | * @return array 264 | */ 265 | public function setGreetingText($localizedGreetings){ 266 | return $this->call('me/messenger_profile', [ 267 | 'greeting' => $localizedGreetings 268 | ], self::TYPE_POST); 269 | } 270 | 271 | 272 | /** 273 | * Delete Greeting Text 274 | * 275 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/greeting-text 276 | * @return array 277 | */ 278 | public function deleteGreetingText() 279 | { 280 | return $this->call('me/messenger_profile', [ 281 | 'fields' => ['greeting'], 282 | ], self::TYPE_DELETE); 283 | } 284 | 285 | /** 286 | * Get Greeting Text 287 | * 288 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/greeting-text 289 | * @return array 290 | */ 291 | public function getGreetingText(){ 292 | return $this->call('me/messenger_profile', [ 293 | 'fields' => 'greeting', 294 | ], self::TYPE_GET); 295 | } 296 | 297 | /** 298 | * Set Target Audience 299 | * 300 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/target-audience 301 | * @param string $audience_type ("all", "custom", "none") 302 | * @param string $list_type ("whitelist", "blacklist") 303 | * @param array $countries_array 304 | * @return array 305 | */ 306 | public function setTargetAudience($audience_type, $list_type=null, $countries_array=null){ 307 | 308 | if ($audience_type === "custom") { 309 | return $this->call('me/messenger_profile', [ 310 | 'target_audience' => [ 311 | 'audience_type' => $audience_type, 312 | 'countries' => [ 313 | $list_type => $countries_array 314 | ] 315 | ] 316 | ], self::TYPE_POST); 317 | } else { 318 | return $this->call('me/messenger_profile', [ 319 | 'target_audience' => [ 320 | 'audience_type' => $audience_type 321 | ] 322 | ], self::TYPE_POST); 323 | } 324 | } 325 | 326 | /** 327 | * Delete Target Audience 328 | * 329 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/target-audience 330 | * @return array 331 | */ 332 | public function deleteTargetAudience() 333 | { 334 | return $this->call('me/messenger_profile', [ 335 | 'fields' => ['target_audience'], 336 | ], self::TYPE_DELETE); 337 | } 338 | 339 | /** 340 | * Get Target Audience 341 | * 342 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/target-audience 343 | * @return array 344 | */ 345 | public function getTargetAudience(){ 346 | return $this->call('me/messenger_profile', [ 347 | 'fields' => 'target_audience', 348 | ], self::TYPE_GET); 349 | } 350 | 351 | /** 352 | * Set Domain Whitelisting 353 | * 354 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/domain-whitelisting 355 | * @param array|string $domains 356 | * @return array 357 | */ 358 | public function setDomainWhitelist($domains){ 359 | 360 | if(!is_array($domains)) 361 | $domains = array($domains); 362 | 363 | return $this->call('me/messenger_profile', [ 364 | 'whitelisted_domains' => $domains 365 | ], self::TYPE_POST); 366 | } 367 | 368 | /** 369 | * Delete Domain Whitelisting 370 | * 371 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/domain-whitelisting 372 | * @return array 373 | */ 374 | public function deleteDomainWhitelist() 375 | { 376 | return $this->call('me/messenger_profile', [ 377 | 'fields' => ['whitelisted_domains'], 378 | ], self::TYPE_DELETE); 379 | } 380 | 381 | /** 382 | * Get Domain Whitelisting 383 | * 384 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/domain-whitelisting 385 | * @return array 386 | */ 387 | public function getDomainWhitelist(){ 388 | return $this->call('me/messenger_profile', [ 389 | 'fields' => 'whitelisted_domains', 390 | ], self::TYPE_GET); 391 | } 392 | 393 | /** 394 | * Set Chat Extension Home URL 395 | * 396 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/home-url/ 397 | * @param string $url 398 | * @param string $webview_height_ratio 399 | * @param string $webview_share_button 400 | * @param boolean $in_test 401 | * @return array 402 | */ 403 | public function setHomeUrl($url, $webview_height_ratio = 'tall', $webview_share_button = 'hide', $in_test = false){ 404 | return $this->call('me/messenger_profile', [ 405 | 'home_url' => [ 406 | 'url' => $url, 407 | 'webview_height_ratio' => $webview_height_ratio, 408 | 'webview_share_button' => $webview_share_button, 409 | 'in_test' => $in_test 410 | ] 411 | ], self::TYPE_POST); 412 | } 413 | 414 | /** 415 | * Delete Chat Extension Home Url 416 | * 417 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/home-url/ 418 | * @return array 419 | */ 420 | public function deleteHomeUrl() 421 | { 422 | return $this->call('me/messenger_profile', [ 423 | 'fields' => ['home_url'], 424 | ], self::TYPE_DELETE); 425 | } 426 | 427 | /** 428 | * Get Chat Extension Home Url 429 | * 430 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/home-url/ 431 | * @return array 432 | */ 433 | public function getHomeUrl(){ 434 | return $this->call('me/messenger_profile', [ 435 | 'fields' => 'home_url', 436 | ], self::TYPE_GET); 437 | } 438 | 439 | /** 440 | * Set Nested Menu 441 | * 442 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/persistent-menu 443 | * @params $localizedMenu 444 | * @return array 445 | */ 446 | public function setPersistentMenu($localizedMenu) 447 | { 448 | $elements = []; 449 | 450 | foreach ($localizedMenu as $menu) { 451 | $elements[] = $menu->getData(); 452 | } 453 | 454 | return $this->call('me/messenger_profile', [ 455 | 'persistent_menu' => $elements 456 | ], self::TYPE_POST); 457 | } 458 | 459 | /** 460 | * Get Nested Menu 461 | * 462 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/persistent-menu 463 | * @return array 464 | */ 465 | public function getPersistentMenu() 466 | { 467 | return $this->call('me/messenger_profile', [ 468 | 'fields' => 'persistent_menu', 469 | ], self::TYPE_GET); 470 | } 471 | 472 | /** 473 | * Remove Persistent Menu 474 | * 475 | * @see https://developers.facebook.com/docs/messenger-platform/messenger-profile/persistent-menu 476 | * @return array 477 | */ 478 | public function deletePersistentMenu() 479 | { 480 | return $this->call('me/messenger_profile', [ 481 | 'fields' => ['persistent_menu'], 482 | ], self::TYPE_DELETE); 483 | } 484 | 485 | 486 | /** 487 | * Set NLP Settings 488 | * 489 | * @see https://developers.facebook.com/docs/messenger-platform/built-in-nlp 490 | * @return array 491 | */ 492 | public function setNLP($nlp_enabled = true, $model = 'ENGLISH', $custom_token = null, $verbose = false, $n_best = 1){ 493 | return $this->call('me/nlp_configs', [ 494 | 'nlp_enabled' => $nlp_enabled, 495 | 'model' => $model, 496 | 'custom_token' => $custom_token, 497 | 'verbose' => $verbose, 498 | 'n_best' => $n_best 499 | ], self::TYPE_POST); 500 | } 501 | 502 | 503 | /** 504 | * Messaging Insights API 505 | * Metrics = page_messages_active_threads_unique, page_messages_blocked_conversations_unique, page_messages_reported_conversations_unique 506 | * page_messages_reported_conversations_by_report_type_unique, page_messages_feedback_by_action_unique, 507 | * 508 | * @see https://developers.facebook.com/docs/messenger-platform/analytics#insights 509 | * @return array 510 | */ 511 | public function getInsights($metric = 'page_messages_active_threads_unique'){ 512 | return $this->call('me/insights', [ 513 | 'metric' => $metric 514 | ], self::TYPE_GET); 515 | } 516 | 517 | /** 518 | * Request to API 519 | * 520 | * @access public 521 | * @param string $url 522 | * @param array $data 523 | * @param string $type Type of request (GET|POST|DELETE) 524 | * @return array 525 | */ 526 | public function call($url, $data, $type = self::TYPE_POST) 527 | { 528 | $data['access_token'] = $this->token; 529 | 530 | if (!is_null($this->appsecret_proof)){ 531 | $data['appsecret_proof'] = $this->appsecret_proof; 532 | } 533 | 534 | $headers = [ 535 | 'Content-Type: application/json', 536 | ]; 537 | 538 | if ($type == self::TYPE_GET) { 539 | $url .= '?'.http_build_query($data); 540 | } 541 | 542 | $process = curl_init($this->apiUrl.$url); 543 | curl_setopt($process, CURLOPT_HTTPHEADER, $headers); 544 | curl_setopt($process, CURLOPT_HEADER, false); 545 | curl_setopt($process, CURLOPT_TIMEOUT, 30); 546 | 547 | if($type == self::TYPE_POST || $type == self::TYPE_DELETE) { 548 | curl_setopt($process, CURLOPT_POST, 1); 549 | curl_setopt($process, CURLOPT_POSTFIELDS, json_encode($data)); 550 | } 551 | 552 | if ($type == self::TYPE_DELETE) { 553 | curl_setopt($process, CURLOPT_CUSTOMREQUEST, "DELETE"); 554 | } 555 | 556 | curl_setopt($process, CURLOPT_RETURNTRANSFER, true); 557 | $return = curl_exec($process); 558 | 559 | /** 560 | * Check for cURL Errors and, if found display the error code 561 | * 562 | * @see http://php.net/manual/en/function.curl-error.php 563 | */ 564 | $curl_error = curl_error($process); 565 | if ($curl_error) { 566 | $this->curl_error = $curl_error; 567 | } 568 | 569 | curl_close($process); 570 | 571 | return json_decode($return, true); 572 | } 573 | 574 | /** 575 | * Get the last cURL error if encountered 576 | * 577 | * @return null|string 578 | */ 579 | public function getCurlError() 580 | { 581 | return $this->curl_error; 582 | } 583 | } 584 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Menu/LocalizedMenu.php: -------------------------------------------------------------------------------- 1 | locale = $locale; 27 | $this->composer_input_disabled = $composer_input_disabled; 28 | $this->menuItems = $menuItems; 29 | } 30 | 31 | public function getData(){ 32 | $result = [ 33 | 'locale' => $this->locale, 34 | 'composer_input_disabled' => $this->composer_input_disabled 35 | ]; 36 | 37 | if(isset($this->menuItems)){ 38 | foreach ($this->menuItems as $menuItem){ 39 | $result['call_to_actions'][] = $menuItem->getData(); 40 | } 41 | } 42 | return $result; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Menu/MenuItem.php: -------------------------------------------------------------------------------- 1 | type = $type; 85 | $this->title = $title; 86 | $this->data = $data; 87 | 88 | $this->webview_height_ratio = $webview_height_ratio; 89 | $this->messenger_extensions = $messenger_extensions; 90 | $this->fallback_url = $fallback_url; 91 | $this->webview_share_button = $webview_share_button; 92 | 93 | } 94 | 95 | /** 96 | * Get Button data 97 | * 98 | * @return array 99 | */ 100 | public function getData() 101 | { 102 | $result['type'] = $this->type; 103 | $result['title'] = $this->title; 104 | 105 | switch($this->type) 106 | { 107 | case self::TYPE_POSTBACK: 108 | $result['payload'] = $this->data; 109 | break; 110 | 111 | case self::TYPE_WEB: 112 | $result['url'] = $this->data; 113 | 114 | if ($this->webview_height_ratio) { 115 | $result['webview_height_ratio'] = $this->webview_height_ratio; 116 | } 117 | 118 | if ($this->messenger_extensions){ 119 | $result['messenger_extensions'] = $this->messenger_extensions; 120 | $result['fallback_url'] = $this->fallback_url; 121 | } 122 | 123 | if($this->webview_share_button){ 124 | $result['webview_share_button'] = $this->webview_share_button; 125 | } 126 | break; 127 | 128 | case self::TYPE_NESTED: 129 | foreach ($this->data as $item) { 130 | $result['call_to_actions'][] = $item->getData(); 131 | } 132 | break; 133 | } 134 | return $result; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Messages/AccountLink.php: -------------------------------------------------------------------------------- 1 | title = $title; 56 | $this->subtitle = $subtitle; 57 | $this->url = $url; 58 | $this->image_url = $image_url; 59 | $this->logout = $logout; 60 | } 61 | 62 | /** 63 | * Get AccountLink data 64 | * 65 | * @return array 66 | */ 67 | public function getData() 68 | { 69 | if($this->logout) 70 | { 71 | $buttons = new MessageButton(MessageButton::TYPE_ACCOUNT_UNLINK, ''); 72 | } 73 | else 74 | { 75 | $buttons = new MessageButton(MessageButton::TYPE_ACCOUNT_LINK, '', $this->url); 76 | } 77 | 78 | $result = [ 79 | 'title' => $this->title, 80 | 'subtitle' => $this->subtitle, 81 | 'image_url' => $this->image_url, 82 | 'buttons' => [$buttons->getData()] 83 | ]; 84 | 85 | return $result; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Messages/Address.php: -------------------------------------------------------------------------------- 1 | data = $data; 25 | } 26 | 27 | /** 28 | * Get Data 29 | * 30 | * @return array 31 | */ 32 | public function getData() 33 | { 34 | return $this->data; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Messages/Adjustment.php: -------------------------------------------------------------------------------- 1 | data = $data; 25 | } 26 | 27 | /** 28 | * Get Data 29 | * 30 | * @return array 31 | */ 32 | public function getData() 33 | { 34 | return $this->data; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Messages/Attachment.php: -------------------------------------------------------------------------------- 1 | type = $type; 44 | $this->payload = $payload; 45 | $this->quick_replies = $quick_replies; 46 | } 47 | 48 | /** 49 | * @return string 50 | */ 51 | public function getType() 52 | { 53 | return $this->type; 54 | } 55 | 56 | /** 57 | * @param string $type 58 | */ 59 | public function setType($type) 60 | { 61 | $this->type = $type; 62 | } 63 | 64 | /** 65 | * @return array 66 | */ 67 | public function getPayload() 68 | { 69 | return $this->payload; 70 | } 71 | 72 | /** 73 | * @param array $payload 74 | */ 75 | public function setPayload($payload) 76 | { 77 | $this->payload = $payload; 78 | } 79 | 80 | /** 81 | * @return string 82 | */ 83 | public function getFileData() 84 | { 85 | return $this->fileData; 86 | } 87 | 88 | /** 89 | * @param string $fileData 90 | */ 91 | public function setFileData($fileData) 92 | { 93 | $this->fileData = $fileData; 94 | } 95 | 96 | /** 97 | * @return array 98 | */ 99 | public function getData() 100 | { 101 | $data = [ 102 | 'attachment' => [ 103 | 'type' => $this->type, 104 | 'payload' => $this->payload 105 | ] 106 | ]; 107 | 108 | foreach ($this->quick_replies as $qr) { 109 | $data['quick_replies'][] = $qr->getData(); 110 | } 111 | 112 | if (!empty($this->fileData)) { 113 | $data['filedata'] = $this->fileData; 114 | } 115 | return $data; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Messages/AudioMessage.php: -------------------------------------------------------------------------------- 1 | recipient = $recipient; 35 | $this->text = $file; 36 | $this->quick_replies = $quick_replies; 37 | $this->notification_type = $notification_type; 38 | $this->messaging_type = $messaging_type; 39 | } 40 | 41 | /** 42 | * Get message data 43 | * 44 | * @return array 45 | */ 46 | public function getData() 47 | { 48 | $res = [ 49 | 'recipient' => [ 50 | 'id' => $this->recipient 51 | ], 52 | 'notification_type'=> $this->notification_type, 53 | 'messaging_type' => $this->messaging_type 54 | ]; 55 | 56 | $attachment = new Attachment(Attachment::TYPE_AUDIO, [], $this->quick_replies); 57 | 58 | if (strcmp(intval($this->text), $this->text) === 0) { 59 | $attachment->setPayload(array('attachment_id' => $this->text)); 60 | } elseif (strpos($this->text, 'http://') === 0 || strpos($this->text, 'https://') === 0) { 61 | $attachment->setPayload(array('url' => $this->text)); 62 | } else { 63 | $attachment->setFileData($this->getCurlValue($this->text, mime_content_type($this->text), basename($this->text))); 64 | } 65 | 66 | $res['message'] = $attachment->getData(); 67 | 68 | return $res; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Messages/FileMessage.php: -------------------------------------------------------------------------------- 1 | recipient = $recipient; 35 | $this->text = $file; 36 | $this->quick_replies = $quick_replies; 37 | $this->notification_type = $notification_type; 38 | $this->messaging_type = $messaging_type; 39 | } 40 | 41 | /** 42 | * Get message data 43 | * 44 | * @return array 45 | */ 46 | public function getData() 47 | { 48 | $res = [ 49 | 'recipient' => [ 50 | 'id' => $this->recipient 51 | ], 52 | 'notification_type'=> $this->notification_type, 53 | 'messaging_type' => $this->messaging_type 54 | ]; 55 | 56 | $attachment = new Attachment(Attachment::TYPE_FILE, [], $this->quick_replies); 57 | 58 | if (strcmp(intval($this->text), $this->text) === 0) { 59 | $attachment->setPayload(array('attachment_id' => $this->text)); 60 | } elseif (strpos($this->text, 'http://') === 0 || strpos($this->text, 'https://') === 0) { 61 | $attachment->setPayload(array('url' => $this->text)); 62 | } else { 63 | $attachment->setFileData($this->getCurlValue($this->text, mime_content_type($this->text), basename($this->text))); 64 | } 65 | 66 | $res['message'] = $attachment->getData(); 67 | 68 | return $res; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Messages/ImageMessage.php: -------------------------------------------------------------------------------- 1 | recipient = $recipient; 41 | $this->text = $file; 42 | $this->quick_replies = $quick_replies; 43 | $this->notification_type = $notification_type; 44 | $this->messaging_type = $messaging_type; 45 | } 46 | 47 | /** 48 | * Get message data 49 | * 50 | * @return array 51 | */ 52 | public function getData() 53 | { 54 | $res = [ 55 | 'recipient' => [ 56 | 'id' => $this->recipient 57 | ], 58 | 'notification_type'=> $this->notification_type, 59 | 'messaging_type' => $this->messaging_type 60 | ]; 61 | 62 | $attachment = new Attachment(Attachment::TYPE_IMAGE, [], $this->quick_replies); 63 | 64 | if (strcmp(intval($this->text), $this->text) === 0) { 65 | $attachment->setPayload(array('attachment_id' => $this->text)); 66 | $res['message'] = $attachment->getData(); 67 | } elseif (strpos($this->text, 'http://') === 0 || strpos($this->text, 'https://') === 0) { 68 | $attachment->setPayload(array('url' => $this->text)); 69 | $res['message'] = $attachment->getData(); 70 | } else { 71 | $attachment->setPayload(array('url' => basename($this->text))); 72 | $attachment->setFileData($this->getCurlValue($this->text, mime_content_type($this->text), basename($this->text))); 73 | $res['message'] = $attachment->getData(); 74 | $res['filedata'] = $res['message']['filedata']; 75 | unset($res['message']['filedata']); 76 | } 77 | 78 | return $res; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Messages/Message.php: -------------------------------------------------------------------------------- 1 | recipient = $recipient; 96 | $this->text = $text; 97 | $this->user_ref = $user_ref; 98 | $this->tag = $tag; 99 | $this->notification_type = $notification_type; 100 | $this->messaging_type = $messaging_type; 101 | $this->messaging_type = $messaging_type; 102 | } 103 | 104 | public function setTag($tag) { 105 | $this->tag = $tag; 106 | } 107 | /** 108 | * Get message data 109 | * 110 | * @return array 111 | */ 112 | public function getData() 113 | { 114 | return [ 115 | 'recipient' => $this->user_ref ? ['user_ref' => $this->recipient] : ['id' => $this->recipient], 116 | 'message' => [ 117 | 'text' => $this->text 118 | ], 119 | 'tag'=> $this->tag, 120 | 'notification_type'=> $this->notification_type, 121 | 'messaging_type' => $this->messaging_type 122 | ]; 123 | } 124 | 125 | /** 126 | * @param string $filename 127 | * @param string $contentType 128 | * @param string $postname 129 | * @return \CURLFile|string 130 | */ 131 | protected function getCurlValue($filename, $contentType, $postname) 132 | { 133 | // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax 134 | // See: https://wiki.php.net/rfc/curl-file-upload 135 | if (function_exists('curl_file_create')) { 136 | return curl_file_create($filename, $contentType, $postname); 137 | } 138 | 139 | // Use the old style if using an older version of PHP 140 | $value = "@{$this->filename};filename=" . $postname; 141 | if ($contentType) { 142 | $value .= ';type=' . $contentType; 143 | } 144 | 145 | return $value; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /Messages/MessageButton.php: -------------------------------------------------------------------------------- 1 | type = $type; 112 | $this->title = $title; 113 | 114 | $this->webview_height_ratio = $webview_height_ratio; 115 | $this->messenger_extensions = $messenger_extensions; 116 | $this->fallback_url = $fallback_url; 117 | $this->share_contents = $share_contents; 118 | $this->webview_share_button = $webview_share_button; 119 | 120 | if (!$url) { 121 | $url = $title; 122 | } 123 | 124 | $this->url = $url; 125 | } 126 | 127 | /** 128 | * Get Button data 129 | * 130 | * @return array 131 | */ 132 | public function getData() 133 | { 134 | $result = [ 135 | 'type' => $this->type 136 | ]; 137 | 138 | switch($this->type) 139 | { 140 | case self::TYPE_POSTBACK: 141 | $result['title'] = $this->title; 142 | $result['payload'] = $this->url; 143 | break; 144 | 145 | case self::TYPE_CALL: 146 | $result['title'] = $this->title; 147 | $result['payload'] = $this->url; 148 | break; 149 | 150 | case self::TYPE_WEB: 151 | $result['title'] = $this->title; 152 | $result['url'] = $this->url; 153 | 154 | if ($this->webview_height_ratio) { 155 | $result['webview_height_ratio'] = $this->webview_height_ratio; 156 | } 157 | 158 | if ($this->messenger_extensions){ 159 | $result['messenger_extensions'] = $this->messenger_extensions; 160 | $result['fallback_url'] = $this->fallback_url; 161 | } 162 | 163 | if($this->webview_share_button){ 164 | $result['webview_share_button'] = $this->webview_share_button; 165 | } 166 | break; 167 | 168 | case self::TYPE_SHARE: 169 | //only share_contents needed 170 | if ($this->share_contents) 171 | $result['share_contents'] = $this->share_contents->getData(); 172 | break; 173 | 174 | case self::TYPE_ACCOUNT_LINK: 175 | $result['url'] = $this->url; 176 | break; 177 | 178 | case self::TYPE_ACCOUNT_UNLINK: 179 | //only type needed 180 | break; 181 | } 182 | 183 | return $result; 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /Messages/MessageDefaultAction.php: -------------------------------------------------------------------------------- 1 | type = self::TYPE_WEB; 60 | 61 | $this->webview_height_ratio = $webview_height_ratio; 62 | $this->messenger_extensions = $messenger_extensions; 63 | $this->fallback_url = $fallback_url; 64 | $this->url = $url; 65 | } 66 | 67 | /** 68 | * Get Button data 69 | * 70 | * @return array 71 | */ 72 | public function getData() 73 | { 74 | $result = [ 75 | 'type' => $this->type 76 | ]; 77 | 78 | switch($this->type) 79 | { 80 | 81 | case self::TYPE_WEB: 82 | $result['url'] = $this->url; 83 | 84 | if ($this->webview_height_ratio) { 85 | $result['webview_height_ratio'] = $this->webview_height_ratio; 86 | } 87 | 88 | if ($this->messenger_extensions){ 89 | $result['messenger_extensions'] = $this->messenger_extensions; 90 | $result['fallback_url'] = $this->fallback_url; 91 | } 92 | break; 93 | 94 | } 95 | 96 | return $result; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Messages/MessageElement.php: -------------------------------------------------------------------------------- 1 | title = $title; 66 | $this->subtitle = $subtitle; 67 | $this->url = $url; 68 | $this->image_url = $image_url; 69 | $this->buttons = $buttons; 70 | if (!empty($default_action)) { 71 | $this->default_action = $default_action; 72 | } 73 | } 74 | 75 | /** 76 | * Get Element data 77 | * 78 | * @return array 79 | */ 80 | public function getData() 81 | { 82 | $result = [ 83 | 'title' => $this->title, 84 | 'subtitle' => $this->subtitle, 85 | 'item_url' => $this->url, 86 | 'image_url' => $this->image_url, 87 | ]; 88 | 89 | if (!empty($this->default_action)) { 90 | $result['default_action'] = $this->default_action; 91 | } 92 | 93 | if (!empty($this->buttons)) { 94 | $result['buttons'] = []; 95 | 96 | foreach ($this->buttons as $btn) { 97 | $result['buttons'][] = $btn->getData(); 98 | } 99 | } 100 | 101 | return $result; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Messages/MessageMediaElement.php: -------------------------------------------------------------------------------- 1 | type = $type; 60 | $this->url = $url; 61 | $this->attachment_id = $attachment_id; 62 | $this->buttons = $buttons; 63 | } 64 | 65 | /** 66 | * Get Element data 67 | * 68 | * @return array 69 | */ 70 | public function getData() 71 | { 72 | $result = [ 73 | 'type' => $this->type, 74 | ]; 75 | 76 | if (!empty($this->url)) { 77 | $result['url'] = $this->url; 78 | } 79 | 80 | if (!empty($this->attachment_id)) { 81 | $result['attachment_id'] = $this->attachment_id; 82 | } 83 | 84 | if (!empty($this->buttons)) { 85 | $result['buttons'] = []; 86 | 87 | foreach ($this->buttons as $btn) { 88 | $result['buttons'][] = $btn->getData(); 89 | } 90 | } 91 | 92 | return $result; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Messages/MessageReceiptElement.php: -------------------------------------------------------------------------------- 1 | title = $title; 41 | $this->subtitle = $subtitle; 42 | $this->image_url = $image_url; 43 | $this->quantity = $quantity; 44 | $this->price = $price; 45 | $this->currency = $currency; 46 | } 47 | 48 | /** 49 | * @return array 50 | */ 51 | public function getData() 52 | { 53 | return [ 54 | 'title' => $this->title, 55 | 'subtitle' => $this->subtitle, 56 | 'image_url' => $this->image_url, 57 | 'quantity' => $this->quantity, 58 | 'price' => $this->price, 59 | 'currency' => $this->currency 60 | ]; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Messages/QuickReply.php: -------------------------------------------------------------------------------- 1 | recipient = $recipient; 26 | $this->text = $text; 27 | $this->quick_replies = $quick_replies; 28 | $this->tag = $tag; 29 | $this->notification_type = $notification_type; 30 | $this->messaging_type = $messaging_type; 31 | } 32 | 33 | public function getData() { 34 | $result = [ 35 | 'recipient' => [ 36 | 'id' => $this->recipient 37 | ], 38 | 'message' => [ 39 | 'text' => $this->text 40 | ], 41 | 'tag'=> $this->tag, 42 | 'notification_type'=> $this->notification_type, 43 | 'messaging_type' => $this->messaging_type 44 | ]; 45 | 46 | foreach ($this->quick_replies as $qr) { 47 | if($qr instanceof QuickReplyButton){ 48 | $result['message']['quick_replies'][] = $qr->getData(); 49 | } else { 50 | $result['message']['quick_replies'][] = $qr; 51 | } 52 | } 53 | 54 | return $result; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Messages/QuickReplyButton.php: -------------------------------------------------------------------------------- 1 | type = $type; 69 | $this->title = $title; 70 | $this->payload = $payload; 71 | $this->image_url = $image_url; 72 | 73 | } 74 | 75 | /** 76 | * Get Button data 77 | * 78 | * @return array 79 | */ 80 | public function getData() 81 | { 82 | $result = [ 83 | 'content_type' => $this->type 84 | ]; 85 | 86 | switch($this->type) 87 | { 88 | case self::TYPE_LOCATION: 89 | $result['image_url'] = $this->image_url; 90 | break; 91 | 92 | case self::TYPE_TEXT: 93 | $result['payload'] = $this->payload; 94 | $result['title'] = $this->title; 95 | $result['image_url'] = $this->image_url; 96 | break; 97 | 98 | case self::TYPE_USER_PHONE_NUMBER: 99 | $result['payload'] = $this->payload; 100 | break; 101 | 102 | case self::TYPE_USER_EMAIL: 103 | $result['payload'] = $this->payload; 104 | break; 105 | } 106 | 107 | return $result; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Messages/SenderAction.php: -------------------------------------------------------------------------------- 1 | recipient = $recipient; 40 | $this->action = $action; 41 | 42 | } 43 | 44 | /** 45 | * Get message data 46 | * 47 | * @return array 48 | */ 49 | public function getData() 50 | { 51 | return [ 52 | 'recipient' => [ 53 | 'id' => $this->recipient 54 | ], 55 | 'sender_action' => $this->action 56 | ]; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Messages/StructuredMessage.php: -------------------------------------------------------------------------------- 1 | recipient = $recipient; 147 | $this->type = $type; 148 | $this->quick_replies = $quick_replies; 149 | $this->tag = $tag; 150 | $this->notification_type = $notification_type; 151 | $this->messaging_type = $messaging_type; 152 | 153 | switch ($type) 154 | { 155 | case self::TYPE_BUTTON: 156 | $this->title = $data['text']; 157 | $this->buttons = $data['buttons']; 158 | break; 159 | 160 | case self::TYPE_GENERIC: 161 | $this->elements = $data['elements']; 162 | //aspect ratio used to render images specified by image_url in element objects 163 | //default is horizontal 164 | if(isset($data['image_aspect_ratio'])) { 165 | $this->image_aspect_ratio = $data['image_aspect_ratio']; 166 | } 167 | break; 168 | 169 | case self::TYPE_MEDIA: 170 | $this->elements = $data['elements']; 171 | break; 172 | 173 | case self::TYPE_LIST: 174 | $this->elements = $data['elements']; 175 | //allowed is a sinle button for the whole list 176 | if(isset($data['buttons'])){ 177 | $this->buttons = $data['buttons']; 178 | } 179 | //the top_element_style indicate if the first item is featured or not. 180 | //default is large 181 | if(isset($data['top_element_style'])){ 182 | $this->top_element_style = $data['top_element_style']; 183 | } 184 | //if the top_element_style is large the first element image_url MUST be set. 185 | if($this->top_element_style == 'large' && (!isset($data['elements'][0]->getData()['image_url']) || $data['elements'][0]->getData()['image_url'] == '')){ 186 | $message = 'Facbook require the image_url to be set for the first element if the top_element_style is large. set the image_url or change the top_element_style to compact.'; 187 | throw new \Exception($message); 188 | } 189 | break; 190 | 191 | case self::TYPE_RECEIPT: 192 | $this->recipient_name = $data['recipient_name']; 193 | $this->order_number = $data['order_number']; 194 | $this->currency = $data['currency']; 195 | $this->payment_method = $data['payment_method']; 196 | $this->order_url = $data['order_url']; 197 | $this->timestamp = $data['timestamp']; 198 | $this->elements = $data['elements']; 199 | $this->address = $data['address']; 200 | $this->summary = $data['summary']; 201 | $this->adjustments = $data['adjustments']; 202 | break; 203 | } 204 | } 205 | 206 | /** 207 | * Get Data 208 | * 209 | * @return array 210 | */ 211 | public function getData() 212 | { 213 | 214 | $result = [ 215 | 'attachment' => [ 216 | 'type' => 'template', 217 | 'payload' => [ 218 | 'template_type' => $this->type 219 | ] 220 | ] 221 | ]; 222 | 223 | if (is_array($this->quick_replies)) { 224 | foreach ($this->quick_replies as $qr) { 225 | if ($qr instanceof QuickReplyButton) { 226 | $result['quick_replies'][] = $qr->getData(); 227 | } 228 | } 229 | } 230 | 231 | switch ($this->type) 232 | { 233 | case self::TYPE_BUTTON: 234 | $result['attachment']['payload']['text'] = $this->title; 235 | $result['attachment']['payload']['buttons'] = []; 236 | 237 | foreach ($this->buttons as $btn) { 238 | $result['attachment']['payload']['buttons'][] = $btn->getData(); 239 | } 240 | 241 | break; 242 | 243 | case self::TYPE_GENERIC: 244 | $result['attachment']['payload']['elements'] = []; 245 | $result['attachment']['payload']['image_aspect_ratio'] = $this->image_aspect_ratio; 246 | 247 | foreach ($this->elements as $btn) { 248 | $result['attachment']['payload']['elements'][] = $btn->getData(); 249 | } 250 | break; 251 | 252 | case self::TYPE_LIST: 253 | $result['attachment']['payload']['elements'] = []; 254 | $result['attachment']['payload']['top_element_style'] = $this->top_element_style; 255 | //list items button 256 | foreach ($this->elements as $btn) { 257 | $result['attachment']['payload']['elements'][] = $btn->getData(); 258 | } 259 | //the whole list button 260 | foreach ($this->buttons as $btn) { 261 | $result['attachment']['payload']['buttons'][] = $btn->getData(); 262 | } 263 | break; 264 | 265 | case self::TYPE_RECEIPT: 266 | $result['attachment']['payload']['recipient_name'] = $this->recipient_name; 267 | $result['attachment']['payload']['order_number'] = $this->order_number; 268 | $result['attachment']['payload']['currency'] = $this->currency; 269 | $result['attachment']['payload']['payment_method'] = $this->payment_method; 270 | $result['attachment']['payload']['order_url'] = $this->order_url; 271 | $result['attachment']['payload']['timestamp'] = $this->timestamp; 272 | $result['attachment']['payload']['elements'] = []; 273 | 274 | foreach ($this->elements as $btn) { 275 | $result['attachment']['payload']['elements'][] = $btn->getData(); 276 | } 277 | 278 | $result['attachment']['payload']['address'] = $this->address->getData(); 279 | $result['attachment']['payload']['summary'] = $this->summary->getData(); 280 | $result['attachment']['payload']['adjustments'] = []; 281 | 282 | foreach ($this->adjustments as $btn) { 283 | $result['attachment']['payload']['adjustments'][] = $btn->getData(); 284 | } 285 | break; 286 | } 287 | 288 | 289 | if ($this->recipient) { 290 | return [ 291 | 'recipient' => [ 292 | 'id' => $this->recipient 293 | ], 294 | 'message' => $result, 295 | 'tag' => $this->tag, 296 | 'notification_type'=> $this->notification_type, 297 | 'messaging_type' => $this->messaging_type 298 | ]; 299 | } else { 300 | //share_contents only 301 | return [ 302 | 'attachment' => $result['attachment'] 303 | ]; 304 | } 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /Messages/Summary.php: -------------------------------------------------------------------------------- 1 | data = $data; 25 | } 26 | 27 | /** 28 | * Get Data 29 | * 30 | * @return array 31 | */ 32 | public function getData() 33 | { 34 | return $this->data; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Messages/VideoMessage.php: -------------------------------------------------------------------------------- 1 | recipient = $recipient; 35 | $this->text = $file; 36 | $this->quick_replies = $quick_replies; 37 | $this->notification_type = $notification_type; 38 | $this->messaging_type = $messaging_type; 39 | } 40 | 41 | /** 42 | * Get message data 43 | * 44 | * @return array 45 | */ 46 | public function getData() 47 | { 48 | $res = [ 49 | 'recipient' => [ 50 | 'id' => $this->recipient 51 | ], 52 | 'notification_type'=> $this->notification_type, 53 | 'messaging_type' => $this->messaging_type 54 | ]; 55 | 56 | $attachment = new Attachment(Attachment::TYPE_VIDEO, [], $this->quick_replies); 57 | 58 | if (strcmp(intval($this->text), $this->text) === 0) { 59 | $attachment->setPayload(array('attachment_id' => $this->text)); 60 | } elseif (strpos($this->text, 'http://') === 0 || strpos($this->text, 'https://') === 0) { 61 | $attachment->setPayload(array('url' => $this->text)); 62 | } else { 63 | $attachment->setFileData($this->getCurlValue($this->text, mime_content_type($this->text), basename($this->text))); 64 | } 65 | 66 | $res['message'] = $attachment->getData(); 67 | 68 | return $res; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/pimax/fb-messenger-php.svg?branch=master)](https://travis-ci.com/pimax/fb-messenger-php) 2 | [![Coverage badge](https://codecov.io/gh/pimax/fb-messenger-php/branch/master/graphs/badge.svg)](https://codecov.io/gh/pimax/fb-messenger-php) 3 | 4 | FB Messenger Bot PHP API 5 | ======================== 6 | 7 | This is a PHP implementation for Facebook Messenger Bot API. 8 | 9 | REQUIREMENTS 10 | ------------ 11 | The minimum requirement is that your Web server supports PHP 5.4. 12 | 13 | INSTALLATION 14 | ------------ 15 | 16 | Version 1.2.2 is the last with PHP ">=5.4.0" support. 17 | **As of version 2.0, PHP 7.1.3 is required.** 18 | 19 | ``` 20 | composer require "pimax/fb-messenger-php" "dev-master" 21 | composer require "pimax/fb-messenger-php" "" 22 | ``` 23 | 24 | BASIC USAGE 25 | ------------ 26 | See this repo - [https://github.com/pimax/fb-messenger-php-example](https://github.com/pimax/fb-messenger-php-example) 27 | -------------------------------------------------------------------------------- /UserProfile.php: -------------------------------------------------------------------------------- 1 | data = $data; 12 | } 13 | 14 | public function getFirstName() 15 | { 16 | return isset($this->data['first_name']) ? $this->data['first_name'] : null; 17 | } 18 | 19 | public function getLastName() 20 | { 21 | return isset($this->data['last_name']) ? $this->data['last_name'] : null; 22 | } 23 | 24 | public function getPicture() 25 | { 26 | return isset($this->data['profile_pic']) ? $this->data['profile_pic'] : null; 27 | } 28 | 29 | public function getLocale() 30 | { 31 | return isset($this->data['locale']) ? $this->data['locale'] : null; 32 | } 33 | 34 | public function getTimezone() 35 | { 36 | return isset($this->data['timezone']) ? $this->data['timezone'] : null; 37 | } 38 | 39 | public function getGender() 40 | { 41 | return isset($this->data['gender']) ? $this->data['gender'] : null; 42 | } 43 | 44 | /** 45 | * Get Data 46 | * 47 | * @return array 48 | */ 49 | public function getData() 50 | { 51 | return $this->data; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pimax/fb-messenger-php", 3 | "description": "Facebook Messenger Bot PHP API", 4 | "homepage": "https://github.com/pimax/fb-messenger-php", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Maksim Piniugin", 9 | "email": "m.pinyugin@gmail.com", 10 | "homepage": "https://maxpinyugin.com", 11 | "role": "Developer" 12 | } 13 | ], 14 | "require": { 15 | "php": "^7.1.3 || ^8.0 || ^8.1 || ^8.2" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit": "^7.3" 19 | }, 20 | "autoload": { 21 | "psr-4": { "pimax\\": "" } 22 | }, 23 | "scripts": { 24 | "test": "phpunit" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /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#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "fd8b0485d6bebcbff8757aa5f00d2135", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "doctrine/instantiator", 12 | "version": "1.2.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/doctrine/instantiator.git", 16 | "reference": "a2c590166b2133a4633738648b6b064edae0814a" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", 21 | "reference": "a2c590166b2133a4633738648b6b064edae0814a", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": "^7.1" 26 | }, 27 | "require-dev": { 28 | "doctrine/coding-standard": "^6.0", 29 | "ext-pdo": "*", 30 | "ext-phar": "*", 31 | "phpbench/phpbench": "^0.13", 32 | "phpstan/phpstan-phpunit": "^0.11", 33 | "phpstan/phpstan-shim": "^0.11", 34 | "phpunit/phpunit": "^7.0" 35 | }, 36 | "type": "library", 37 | "extra": { 38 | "branch-alias": { 39 | "dev-master": "1.2.x-dev" 40 | } 41 | }, 42 | "autoload": { 43 | "psr-4": { 44 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 45 | } 46 | }, 47 | "notification-url": "https://packagist.org/downloads/", 48 | "license": [ 49 | "MIT" 50 | ], 51 | "authors": [ 52 | { 53 | "name": "Marco Pivetta", 54 | "email": "ocramius@gmail.com", 55 | "homepage": "http://ocramius.github.com/" 56 | } 57 | ], 58 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 59 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", 60 | "keywords": [ 61 | "constructor", 62 | "instantiate" 63 | ], 64 | "time": "2019-03-17T17:37:11+00:00" 65 | }, 66 | { 67 | "name": "myclabs/deep-copy", 68 | "version": "1.9.1", 69 | "source": { 70 | "type": "git", 71 | "url": "https://github.com/myclabs/DeepCopy.git", 72 | "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72" 73 | }, 74 | "dist": { 75 | "type": "zip", 76 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", 77 | "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", 78 | "shasum": "" 79 | }, 80 | "require": { 81 | "php": "^7.1" 82 | }, 83 | "replace": { 84 | "myclabs/deep-copy": "self.version" 85 | }, 86 | "require-dev": { 87 | "doctrine/collections": "^1.0", 88 | "doctrine/common": "^2.6", 89 | "phpunit/phpunit": "^7.1" 90 | }, 91 | "type": "library", 92 | "autoload": { 93 | "psr-4": { 94 | "DeepCopy\\": "src/DeepCopy/" 95 | }, 96 | "files": [ 97 | "src/DeepCopy/deep_copy.php" 98 | ] 99 | }, 100 | "notification-url": "https://packagist.org/downloads/", 101 | "license": [ 102 | "MIT" 103 | ], 104 | "description": "Create deep copies (clones) of your objects", 105 | "keywords": [ 106 | "clone", 107 | "copy", 108 | "duplicate", 109 | "object", 110 | "object graph" 111 | ], 112 | "time": "2019-04-07T13:18:21+00:00" 113 | }, 114 | { 115 | "name": "phar-io/manifest", 116 | "version": "1.0.3", 117 | "source": { 118 | "type": "git", 119 | "url": "https://github.com/phar-io/manifest.git", 120 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" 121 | }, 122 | "dist": { 123 | "type": "zip", 124 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", 125 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", 126 | "shasum": "" 127 | }, 128 | "require": { 129 | "ext-dom": "*", 130 | "ext-phar": "*", 131 | "phar-io/version": "^2.0", 132 | "php": "^5.6 || ^7.0" 133 | }, 134 | "type": "library", 135 | "extra": { 136 | "branch-alias": { 137 | "dev-master": "1.0.x-dev" 138 | } 139 | }, 140 | "autoload": { 141 | "classmap": [ 142 | "src/" 143 | ] 144 | }, 145 | "notification-url": "https://packagist.org/downloads/", 146 | "license": [ 147 | "BSD-3-Clause" 148 | ], 149 | "authors": [ 150 | { 151 | "name": "Arne Blankerts", 152 | "email": "arne@blankerts.de", 153 | "role": "Developer" 154 | }, 155 | { 156 | "name": "Sebastian Heuer", 157 | "email": "sebastian@phpeople.de", 158 | "role": "Developer" 159 | }, 160 | { 161 | "name": "Sebastian Bergmann", 162 | "email": "sebastian@phpunit.de", 163 | "role": "Developer" 164 | } 165 | ], 166 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 167 | "time": "2018-07-08T19:23:20+00:00" 168 | }, 169 | { 170 | "name": "phar-io/version", 171 | "version": "2.0.1", 172 | "source": { 173 | "type": "git", 174 | "url": "https://github.com/phar-io/version.git", 175 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" 176 | }, 177 | "dist": { 178 | "type": "zip", 179 | "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", 180 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", 181 | "shasum": "" 182 | }, 183 | "require": { 184 | "php": "^5.6 || ^7.0" 185 | }, 186 | "type": "library", 187 | "autoload": { 188 | "classmap": [ 189 | "src/" 190 | ] 191 | }, 192 | "notification-url": "https://packagist.org/downloads/", 193 | "license": [ 194 | "BSD-3-Clause" 195 | ], 196 | "authors": [ 197 | { 198 | "name": "Arne Blankerts", 199 | "email": "arne@blankerts.de", 200 | "role": "Developer" 201 | }, 202 | { 203 | "name": "Sebastian Heuer", 204 | "email": "sebastian@phpeople.de", 205 | "role": "Developer" 206 | }, 207 | { 208 | "name": "Sebastian Bergmann", 209 | "email": "sebastian@phpunit.de", 210 | "role": "Developer" 211 | } 212 | ], 213 | "description": "Library for handling version information and constraints", 214 | "time": "2018-07-08T19:19:57+00:00" 215 | }, 216 | { 217 | "name": "phpdocumentor/reflection-common", 218 | "version": "1.0.1", 219 | "source": { 220 | "type": "git", 221 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 222 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" 223 | }, 224 | "dist": { 225 | "type": "zip", 226 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 227 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 228 | "shasum": "" 229 | }, 230 | "require": { 231 | "php": ">=5.5" 232 | }, 233 | "require-dev": { 234 | "phpunit/phpunit": "^4.6" 235 | }, 236 | "type": "library", 237 | "extra": { 238 | "branch-alias": { 239 | "dev-master": "1.0.x-dev" 240 | } 241 | }, 242 | "autoload": { 243 | "psr-4": { 244 | "phpDocumentor\\Reflection\\": [ 245 | "src" 246 | ] 247 | } 248 | }, 249 | "notification-url": "https://packagist.org/downloads/", 250 | "license": [ 251 | "MIT" 252 | ], 253 | "authors": [ 254 | { 255 | "name": "Jaap van Otterdijk", 256 | "email": "opensource@ijaap.nl" 257 | } 258 | ], 259 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 260 | "homepage": "http://www.phpdoc.org", 261 | "keywords": [ 262 | "FQSEN", 263 | "phpDocumentor", 264 | "phpdoc", 265 | "reflection", 266 | "static analysis" 267 | ], 268 | "time": "2017-09-11T18:02:19+00:00" 269 | }, 270 | { 271 | "name": "phpdocumentor/reflection-docblock", 272 | "version": "4.3.1", 273 | "source": { 274 | "type": "git", 275 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 276 | "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c" 277 | }, 278 | "dist": { 279 | "type": "zip", 280 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", 281 | "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", 282 | "shasum": "" 283 | }, 284 | "require": { 285 | "php": "^7.0", 286 | "phpdocumentor/reflection-common": "^1.0.0", 287 | "phpdocumentor/type-resolver": "^0.4.0", 288 | "webmozart/assert": "^1.0" 289 | }, 290 | "require-dev": { 291 | "doctrine/instantiator": "~1.0.5", 292 | "mockery/mockery": "^1.0", 293 | "phpunit/phpunit": "^6.4" 294 | }, 295 | "type": "library", 296 | "extra": { 297 | "branch-alias": { 298 | "dev-master": "4.x-dev" 299 | } 300 | }, 301 | "autoload": { 302 | "psr-4": { 303 | "phpDocumentor\\Reflection\\": [ 304 | "src/" 305 | ] 306 | } 307 | }, 308 | "notification-url": "https://packagist.org/downloads/", 309 | "license": [ 310 | "MIT" 311 | ], 312 | "authors": [ 313 | { 314 | "name": "Mike van Riel", 315 | "email": "me@mikevanriel.com" 316 | } 317 | ], 318 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 319 | "time": "2019-04-30T17:48:53+00:00" 320 | }, 321 | { 322 | "name": "phpdocumentor/type-resolver", 323 | "version": "0.4.0", 324 | "source": { 325 | "type": "git", 326 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 327 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" 328 | }, 329 | "dist": { 330 | "type": "zip", 331 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", 332 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", 333 | "shasum": "" 334 | }, 335 | "require": { 336 | "php": "^5.5 || ^7.0", 337 | "phpdocumentor/reflection-common": "^1.0" 338 | }, 339 | "require-dev": { 340 | "mockery/mockery": "^0.9.4", 341 | "phpunit/phpunit": "^5.2||^4.8.24" 342 | }, 343 | "type": "library", 344 | "extra": { 345 | "branch-alias": { 346 | "dev-master": "1.0.x-dev" 347 | } 348 | }, 349 | "autoload": { 350 | "psr-4": { 351 | "phpDocumentor\\Reflection\\": [ 352 | "src/" 353 | ] 354 | } 355 | }, 356 | "notification-url": "https://packagist.org/downloads/", 357 | "license": [ 358 | "MIT" 359 | ], 360 | "authors": [ 361 | { 362 | "name": "Mike van Riel", 363 | "email": "me@mikevanriel.com" 364 | } 365 | ], 366 | "time": "2017-07-14T14:27:02+00:00" 367 | }, 368 | { 369 | "name": "phpspec/prophecy", 370 | "version": "1.8.0", 371 | "source": { 372 | "type": "git", 373 | "url": "https://github.com/phpspec/prophecy.git", 374 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" 375 | }, 376 | "dist": { 377 | "type": "zip", 378 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 379 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 380 | "shasum": "" 381 | }, 382 | "require": { 383 | "doctrine/instantiator": "^1.0.2", 384 | "php": "^5.3|^7.0", 385 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", 386 | "sebastian/comparator": "^1.1|^2.0|^3.0", 387 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 388 | }, 389 | "require-dev": { 390 | "phpspec/phpspec": "^2.5|^3.2", 391 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" 392 | }, 393 | "type": "library", 394 | "extra": { 395 | "branch-alias": { 396 | "dev-master": "1.8.x-dev" 397 | } 398 | }, 399 | "autoload": { 400 | "psr-0": { 401 | "Prophecy\\": "src/" 402 | } 403 | }, 404 | "notification-url": "https://packagist.org/downloads/", 405 | "license": [ 406 | "MIT" 407 | ], 408 | "authors": [ 409 | { 410 | "name": "Konstantin Kudryashov", 411 | "email": "ever.zet@gmail.com", 412 | "homepage": "http://everzet.com" 413 | }, 414 | { 415 | "name": "Marcello Duarte", 416 | "email": "marcello.duarte@gmail.com" 417 | } 418 | ], 419 | "description": "Highly opinionated mocking framework for PHP 5.3+", 420 | "homepage": "https://github.com/phpspec/prophecy", 421 | "keywords": [ 422 | "Double", 423 | "Dummy", 424 | "fake", 425 | "mock", 426 | "spy", 427 | "stub" 428 | ], 429 | "time": "2018-08-05T17:53:17+00:00" 430 | }, 431 | { 432 | "name": "phpunit/php-code-coverage", 433 | "version": "6.1.4", 434 | "source": { 435 | "type": "git", 436 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 437 | "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" 438 | }, 439 | "dist": { 440 | "type": "zip", 441 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", 442 | "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", 443 | "shasum": "" 444 | }, 445 | "require": { 446 | "ext-dom": "*", 447 | "ext-xmlwriter": "*", 448 | "php": "^7.1", 449 | "phpunit/php-file-iterator": "^2.0", 450 | "phpunit/php-text-template": "^1.2.1", 451 | "phpunit/php-token-stream": "^3.0", 452 | "sebastian/code-unit-reverse-lookup": "^1.0.1", 453 | "sebastian/environment": "^3.1 || ^4.0", 454 | "sebastian/version": "^2.0.1", 455 | "theseer/tokenizer": "^1.1" 456 | }, 457 | "require-dev": { 458 | "phpunit/phpunit": "^7.0" 459 | }, 460 | "suggest": { 461 | "ext-xdebug": "^2.6.0" 462 | }, 463 | "type": "library", 464 | "extra": { 465 | "branch-alias": { 466 | "dev-master": "6.1-dev" 467 | } 468 | }, 469 | "autoload": { 470 | "classmap": [ 471 | "src/" 472 | ] 473 | }, 474 | "notification-url": "https://packagist.org/downloads/", 475 | "license": [ 476 | "BSD-3-Clause" 477 | ], 478 | "authors": [ 479 | { 480 | "name": "Sebastian Bergmann", 481 | "email": "sebastian@phpunit.de", 482 | "role": "lead" 483 | } 484 | ], 485 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 486 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 487 | "keywords": [ 488 | "coverage", 489 | "testing", 490 | "xunit" 491 | ], 492 | "time": "2018-10-31T16:06:48+00:00" 493 | }, 494 | { 495 | "name": "phpunit/php-file-iterator", 496 | "version": "2.0.2", 497 | "source": { 498 | "type": "git", 499 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 500 | "reference": "050bedf145a257b1ff02746c31894800e5122946" 501 | }, 502 | "dist": { 503 | "type": "zip", 504 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", 505 | "reference": "050bedf145a257b1ff02746c31894800e5122946", 506 | "shasum": "" 507 | }, 508 | "require": { 509 | "php": "^7.1" 510 | }, 511 | "require-dev": { 512 | "phpunit/phpunit": "^7.1" 513 | }, 514 | "type": "library", 515 | "extra": { 516 | "branch-alias": { 517 | "dev-master": "2.0.x-dev" 518 | } 519 | }, 520 | "autoload": { 521 | "classmap": [ 522 | "src/" 523 | ] 524 | }, 525 | "notification-url": "https://packagist.org/downloads/", 526 | "license": [ 527 | "BSD-3-Clause" 528 | ], 529 | "authors": [ 530 | { 531 | "name": "Sebastian Bergmann", 532 | "email": "sebastian@phpunit.de", 533 | "role": "lead" 534 | } 535 | ], 536 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 537 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 538 | "keywords": [ 539 | "filesystem", 540 | "iterator" 541 | ], 542 | "time": "2018-09-13T20:33:42+00:00" 543 | }, 544 | { 545 | "name": "phpunit/php-text-template", 546 | "version": "1.2.1", 547 | "source": { 548 | "type": "git", 549 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 550 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 551 | }, 552 | "dist": { 553 | "type": "zip", 554 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 555 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 556 | "shasum": "" 557 | }, 558 | "require": { 559 | "php": ">=5.3.3" 560 | }, 561 | "type": "library", 562 | "autoload": { 563 | "classmap": [ 564 | "src/" 565 | ] 566 | }, 567 | "notification-url": "https://packagist.org/downloads/", 568 | "license": [ 569 | "BSD-3-Clause" 570 | ], 571 | "authors": [ 572 | { 573 | "name": "Sebastian Bergmann", 574 | "email": "sebastian@phpunit.de", 575 | "role": "lead" 576 | } 577 | ], 578 | "description": "Simple template engine.", 579 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 580 | "keywords": [ 581 | "template" 582 | ], 583 | "time": "2015-06-21T13:50:34+00:00" 584 | }, 585 | { 586 | "name": "phpunit/php-timer", 587 | "version": "2.1.1", 588 | "source": { 589 | "type": "git", 590 | "url": "https://github.com/sebastianbergmann/php-timer.git", 591 | "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059" 592 | }, 593 | "dist": { 594 | "type": "zip", 595 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b389aebe1b8b0578430bda0c7c95a829608e059", 596 | "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059", 597 | "shasum": "" 598 | }, 599 | "require": { 600 | "php": "^7.1" 601 | }, 602 | "require-dev": { 603 | "phpunit/phpunit": "^7.0" 604 | }, 605 | "type": "library", 606 | "extra": { 607 | "branch-alias": { 608 | "dev-master": "2.1-dev" 609 | } 610 | }, 611 | "autoload": { 612 | "classmap": [ 613 | "src/" 614 | ] 615 | }, 616 | "notification-url": "https://packagist.org/downloads/", 617 | "license": [ 618 | "BSD-3-Clause" 619 | ], 620 | "authors": [ 621 | { 622 | "name": "Sebastian Bergmann", 623 | "email": "sebastian@phpunit.de", 624 | "role": "lead" 625 | } 626 | ], 627 | "description": "Utility class for timing", 628 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 629 | "keywords": [ 630 | "timer" 631 | ], 632 | "time": "2019-02-20T10:12:59+00:00" 633 | }, 634 | { 635 | "name": "phpunit/php-token-stream", 636 | "version": "3.0.1", 637 | "source": { 638 | "type": "git", 639 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 640 | "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" 641 | }, 642 | "dist": { 643 | "type": "zip", 644 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", 645 | "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", 646 | "shasum": "" 647 | }, 648 | "require": { 649 | "ext-tokenizer": "*", 650 | "php": "^7.1" 651 | }, 652 | "require-dev": { 653 | "phpunit/phpunit": "^7.0" 654 | }, 655 | "type": "library", 656 | "extra": { 657 | "branch-alias": { 658 | "dev-master": "3.0-dev" 659 | } 660 | }, 661 | "autoload": { 662 | "classmap": [ 663 | "src/" 664 | ] 665 | }, 666 | "notification-url": "https://packagist.org/downloads/", 667 | "license": [ 668 | "BSD-3-Clause" 669 | ], 670 | "authors": [ 671 | { 672 | "name": "Sebastian Bergmann", 673 | "email": "sebastian@phpunit.de" 674 | } 675 | ], 676 | "description": "Wrapper around PHP's tokenizer extension.", 677 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 678 | "keywords": [ 679 | "tokenizer" 680 | ], 681 | "time": "2018-10-30T05:52:18+00:00" 682 | }, 683 | { 684 | "name": "phpunit/phpunit", 685 | "version": "7.5.9", 686 | "source": { 687 | "type": "git", 688 | "url": "https://github.com/sebastianbergmann/phpunit.git", 689 | "reference": "134669cf0eeac3f79bc7f0c793efbc158bffc160" 690 | }, 691 | "dist": { 692 | "type": "zip", 693 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/134669cf0eeac3f79bc7f0c793efbc158bffc160", 694 | "reference": "134669cf0eeac3f79bc7f0c793efbc158bffc160", 695 | "shasum": "" 696 | }, 697 | "require": { 698 | "doctrine/instantiator": "^1.1", 699 | "ext-dom": "*", 700 | "ext-json": "*", 701 | "ext-libxml": "*", 702 | "ext-mbstring": "*", 703 | "ext-xml": "*", 704 | "myclabs/deep-copy": "^1.7", 705 | "phar-io/manifest": "^1.0.2", 706 | "phar-io/version": "^2.0", 707 | "php": "^7.1", 708 | "phpspec/prophecy": "^1.7", 709 | "phpunit/php-code-coverage": "^6.0.7", 710 | "phpunit/php-file-iterator": "^2.0.1", 711 | "phpunit/php-text-template": "^1.2.1", 712 | "phpunit/php-timer": "^2.1", 713 | "sebastian/comparator": "^3.0", 714 | "sebastian/diff": "^3.0", 715 | "sebastian/environment": "^4.0", 716 | "sebastian/exporter": "^3.1", 717 | "sebastian/global-state": "^2.0", 718 | "sebastian/object-enumerator": "^3.0.3", 719 | "sebastian/resource-operations": "^2.0", 720 | "sebastian/version": "^2.0.1" 721 | }, 722 | "conflict": { 723 | "phpunit/phpunit-mock-objects": "*" 724 | }, 725 | "require-dev": { 726 | "ext-pdo": "*" 727 | }, 728 | "suggest": { 729 | "ext-soap": "*", 730 | "ext-xdebug": "*", 731 | "phpunit/php-invoker": "^2.0" 732 | }, 733 | "bin": [ 734 | "phpunit" 735 | ], 736 | "type": "library", 737 | "extra": { 738 | "branch-alias": { 739 | "dev-master": "7.5-dev" 740 | } 741 | }, 742 | "autoload": { 743 | "classmap": [ 744 | "src/" 745 | ] 746 | }, 747 | "notification-url": "https://packagist.org/downloads/", 748 | "license": [ 749 | "BSD-3-Clause" 750 | ], 751 | "authors": [ 752 | { 753 | "name": "Sebastian Bergmann", 754 | "email": "sebastian@phpunit.de", 755 | "role": "lead" 756 | } 757 | ], 758 | "description": "The PHP Unit Testing framework.", 759 | "homepage": "https://phpunit.de/", 760 | "keywords": [ 761 | "phpunit", 762 | "testing", 763 | "xunit" 764 | ], 765 | "time": "2019-04-19T15:50:46+00:00" 766 | }, 767 | { 768 | "name": "sebastian/code-unit-reverse-lookup", 769 | "version": "1.0.1", 770 | "source": { 771 | "type": "git", 772 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 773 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 774 | }, 775 | "dist": { 776 | "type": "zip", 777 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 778 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 779 | "shasum": "" 780 | }, 781 | "require": { 782 | "php": "^5.6 || ^7.0" 783 | }, 784 | "require-dev": { 785 | "phpunit/phpunit": "^5.7 || ^6.0" 786 | }, 787 | "type": "library", 788 | "extra": { 789 | "branch-alias": { 790 | "dev-master": "1.0.x-dev" 791 | } 792 | }, 793 | "autoload": { 794 | "classmap": [ 795 | "src/" 796 | ] 797 | }, 798 | "notification-url": "https://packagist.org/downloads/", 799 | "license": [ 800 | "BSD-3-Clause" 801 | ], 802 | "authors": [ 803 | { 804 | "name": "Sebastian Bergmann", 805 | "email": "sebastian@phpunit.de" 806 | } 807 | ], 808 | "description": "Looks up which function or method a line of code belongs to", 809 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 810 | "time": "2017-03-04T06:30:41+00:00" 811 | }, 812 | { 813 | "name": "sebastian/comparator", 814 | "version": "3.0.2", 815 | "source": { 816 | "type": "git", 817 | "url": "https://github.com/sebastianbergmann/comparator.git", 818 | "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" 819 | }, 820 | "dist": { 821 | "type": "zip", 822 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", 823 | "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", 824 | "shasum": "" 825 | }, 826 | "require": { 827 | "php": "^7.1", 828 | "sebastian/diff": "^3.0", 829 | "sebastian/exporter": "^3.1" 830 | }, 831 | "require-dev": { 832 | "phpunit/phpunit": "^7.1" 833 | }, 834 | "type": "library", 835 | "extra": { 836 | "branch-alias": { 837 | "dev-master": "3.0-dev" 838 | } 839 | }, 840 | "autoload": { 841 | "classmap": [ 842 | "src/" 843 | ] 844 | }, 845 | "notification-url": "https://packagist.org/downloads/", 846 | "license": [ 847 | "BSD-3-Clause" 848 | ], 849 | "authors": [ 850 | { 851 | "name": "Jeff Welch", 852 | "email": "whatthejeff@gmail.com" 853 | }, 854 | { 855 | "name": "Volker Dusch", 856 | "email": "github@wallbash.com" 857 | }, 858 | { 859 | "name": "Bernhard Schussek", 860 | "email": "bschussek@2bepublished.at" 861 | }, 862 | { 863 | "name": "Sebastian Bergmann", 864 | "email": "sebastian@phpunit.de" 865 | } 866 | ], 867 | "description": "Provides the functionality to compare PHP values for equality", 868 | "homepage": "https://github.com/sebastianbergmann/comparator", 869 | "keywords": [ 870 | "comparator", 871 | "compare", 872 | "equality" 873 | ], 874 | "time": "2018-07-12T15:12:46+00:00" 875 | }, 876 | { 877 | "name": "sebastian/diff", 878 | "version": "3.0.2", 879 | "source": { 880 | "type": "git", 881 | "url": "https://github.com/sebastianbergmann/diff.git", 882 | "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" 883 | }, 884 | "dist": { 885 | "type": "zip", 886 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", 887 | "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", 888 | "shasum": "" 889 | }, 890 | "require": { 891 | "php": "^7.1" 892 | }, 893 | "require-dev": { 894 | "phpunit/phpunit": "^7.5 || ^8.0", 895 | "symfony/process": "^2 || ^3.3 || ^4" 896 | }, 897 | "type": "library", 898 | "extra": { 899 | "branch-alias": { 900 | "dev-master": "3.0-dev" 901 | } 902 | }, 903 | "autoload": { 904 | "classmap": [ 905 | "src/" 906 | ] 907 | }, 908 | "notification-url": "https://packagist.org/downloads/", 909 | "license": [ 910 | "BSD-3-Clause" 911 | ], 912 | "authors": [ 913 | { 914 | "name": "Kore Nordmann", 915 | "email": "mail@kore-nordmann.de" 916 | }, 917 | { 918 | "name": "Sebastian Bergmann", 919 | "email": "sebastian@phpunit.de" 920 | } 921 | ], 922 | "description": "Diff implementation", 923 | "homepage": "https://github.com/sebastianbergmann/diff", 924 | "keywords": [ 925 | "diff", 926 | "udiff", 927 | "unidiff", 928 | "unified diff" 929 | ], 930 | "time": "2019-02-04T06:01:07+00:00" 931 | }, 932 | { 933 | "name": "sebastian/environment", 934 | "version": "4.2.1", 935 | "source": { 936 | "type": "git", 937 | "url": "https://github.com/sebastianbergmann/environment.git", 938 | "reference": "3095910f0f0fb155ac4021fc51a4a7a39ac04e8a" 939 | }, 940 | "dist": { 941 | "type": "zip", 942 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/3095910f0f0fb155ac4021fc51a4a7a39ac04e8a", 943 | "reference": "3095910f0f0fb155ac4021fc51a4a7a39ac04e8a", 944 | "shasum": "" 945 | }, 946 | "require": { 947 | "php": "^7.1" 948 | }, 949 | "require-dev": { 950 | "phpunit/phpunit": "^7.5" 951 | }, 952 | "suggest": { 953 | "ext-posix": "*" 954 | }, 955 | "type": "library", 956 | "extra": { 957 | "branch-alias": { 958 | "dev-master": "4.2-dev" 959 | } 960 | }, 961 | "autoload": { 962 | "classmap": [ 963 | "src/" 964 | ] 965 | }, 966 | "notification-url": "https://packagist.org/downloads/", 967 | "license": [ 968 | "BSD-3-Clause" 969 | ], 970 | "authors": [ 971 | { 972 | "name": "Sebastian Bergmann", 973 | "email": "sebastian@phpunit.de" 974 | } 975 | ], 976 | "description": "Provides functionality to handle HHVM/PHP environments", 977 | "homepage": "http://www.github.com/sebastianbergmann/environment", 978 | "keywords": [ 979 | "Xdebug", 980 | "environment", 981 | "hhvm" 982 | ], 983 | "time": "2019-04-25T07:55:20+00:00" 984 | }, 985 | { 986 | "name": "sebastian/exporter", 987 | "version": "3.1.0", 988 | "source": { 989 | "type": "git", 990 | "url": "https://github.com/sebastianbergmann/exporter.git", 991 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" 992 | }, 993 | "dist": { 994 | "type": "zip", 995 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", 996 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", 997 | "shasum": "" 998 | }, 999 | "require": { 1000 | "php": "^7.0", 1001 | "sebastian/recursion-context": "^3.0" 1002 | }, 1003 | "require-dev": { 1004 | "ext-mbstring": "*", 1005 | "phpunit/phpunit": "^6.0" 1006 | }, 1007 | "type": "library", 1008 | "extra": { 1009 | "branch-alias": { 1010 | "dev-master": "3.1.x-dev" 1011 | } 1012 | }, 1013 | "autoload": { 1014 | "classmap": [ 1015 | "src/" 1016 | ] 1017 | }, 1018 | "notification-url": "https://packagist.org/downloads/", 1019 | "license": [ 1020 | "BSD-3-Clause" 1021 | ], 1022 | "authors": [ 1023 | { 1024 | "name": "Jeff Welch", 1025 | "email": "whatthejeff@gmail.com" 1026 | }, 1027 | { 1028 | "name": "Volker Dusch", 1029 | "email": "github@wallbash.com" 1030 | }, 1031 | { 1032 | "name": "Bernhard Schussek", 1033 | "email": "bschussek@2bepublished.at" 1034 | }, 1035 | { 1036 | "name": "Sebastian Bergmann", 1037 | "email": "sebastian@phpunit.de" 1038 | }, 1039 | { 1040 | "name": "Adam Harvey", 1041 | "email": "aharvey@php.net" 1042 | } 1043 | ], 1044 | "description": "Provides the functionality to export PHP variables for visualization", 1045 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1046 | "keywords": [ 1047 | "export", 1048 | "exporter" 1049 | ], 1050 | "time": "2017-04-03T13:19:02+00:00" 1051 | }, 1052 | { 1053 | "name": "sebastian/global-state", 1054 | "version": "2.0.0", 1055 | "source": { 1056 | "type": "git", 1057 | "url": "https://github.com/sebastianbergmann/global-state.git", 1058 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" 1059 | }, 1060 | "dist": { 1061 | "type": "zip", 1062 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1063 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1064 | "shasum": "" 1065 | }, 1066 | "require": { 1067 | "php": "^7.0" 1068 | }, 1069 | "require-dev": { 1070 | "phpunit/phpunit": "^6.0" 1071 | }, 1072 | "suggest": { 1073 | "ext-uopz": "*" 1074 | }, 1075 | "type": "library", 1076 | "extra": { 1077 | "branch-alias": { 1078 | "dev-master": "2.0-dev" 1079 | } 1080 | }, 1081 | "autoload": { 1082 | "classmap": [ 1083 | "src/" 1084 | ] 1085 | }, 1086 | "notification-url": "https://packagist.org/downloads/", 1087 | "license": [ 1088 | "BSD-3-Clause" 1089 | ], 1090 | "authors": [ 1091 | { 1092 | "name": "Sebastian Bergmann", 1093 | "email": "sebastian@phpunit.de" 1094 | } 1095 | ], 1096 | "description": "Snapshotting of global state", 1097 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1098 | "keywords": [ 1099 | "global state" 1100 | ], 1101 | "time": "2017-04-27T15:39:26+00:00" 1102 | }, 1103 | { 1104 | "name": "sebastian/object-enumerator", 1105 | "version": "3.0.3", 1106 | "source": { 1107 | "type": "git", 1108 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1109 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" 1110 | }, 1111 | "dist": { 1112 | "type": "zip", 1113 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", 1114 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", 1115 | "shasum": "" 1116 | }, 1117 | "require": { 1118 | "php": "^7.0", 1119 | "sebastian/object-reflector": "^1.1.1", 1120 | "sebastian/recursion-context": "^3.0" 1121 | }, 1122 | "require-dev": { 1123 | "phpunit/phpunit": "^6.0" 1124 | }, 1125 | "type": "library", 1126 | "extra": { 1127 | "branch-alias": { 1128 | "dev-master": "3.0.x-dev" 1129 | } 1130 | }, 1131 | "autoload": { 1132 | "classmap": [ 1133 | "src/" 1134 | ] 1135 | }, 1136 | "notification-url": "https://packagist.org/downloads/", 1137 | "license": [ 1138 | "BSD-3-Clause" 1139 | ], 1140 | "authors": [ 1141 | { 1142 | "name": "Sebastian Bergmann", 1143 | "email": "sebastian@phpunit.de" 1144 | } 1145 | ], 1146 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1147 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1148 | "time": "2017-08-03T12:35:26+00:00" 1149 | }, 1150 | { 1151 | "name": "sebastian/object-reflector", 1152 | "version": "1.1.1", 1153 | "source": { 1154 | "type": "git", 1155 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1156 | "reference": "773f97c67f28de00d397be301821b06708fca0be" 1157 | }, 1158 | "dist": { 1159 | "type": "zip", 1160 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", 1161 | "reference": "773f97c67f28de00d397be301821b06708fca0be", 1162 | "shasum": "" 1163 | }, 1164 | "require": { 1165 | "php": "^7.0" 1166 | }, 1167 | "require-dev": { 1168 | "phpunit/phpunit": "^6.0" 1169 | }, 1170 | "type": "library", 1171 | "extra": { 1172 | "branch-alias": { 1173 | "dev-master": "1.1-dev" 1174 | } 1175 | }, 1176 | "autoload": { 1177 | "classmap": [ 1178 | "src/" 1179 | ] 1180 | }, 1181 | "notification-url": "https://packagist.org/downloads/", 1182 | "license": [ 1183 | "BSD-3-Clause" 1184 | ], 1185 | "authors": [ 1186 | { 1187 | "name": "Sebastian Bergmann", 1188 | "email": "sebastian@phpunit.de" 1189 | } 1190 | ], 1191 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1192 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1193 | "time": "2017-03-29T09:07:27+00:00" 1194 | }, 1195 | { 1196 | "name": "sebastian/recursion-context", 1197 | "version": "3.0.0", 1198 | "source": { 1199 | "type": "git", 1200 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1201 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" 1202 | }, 1203 | "dist": { 1204 | "type": "zip", 1205 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1206 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1207 | "shasum": "" 1208 | }, 1209 | "require": { 1210 | "php": "^7.0" 1211 | }, 1212 | "require-dev": { 1213 | "phpunit/phpunit": "^6.0" 1214 | }, 1215 | "type": "library", 1216 | "extra": { 1217 | "branch-alias": { 1218 | "dev-master": "3.0.x-dev" 1219 | } 1220 | }, 1221 | "autoload": { 1222 | "classmap": [ 1223 | "src/" 1224 | ] 1225 | }, 1226 | "notification-url": "https://packagist.org/downloads/", 1227 | "license": [ 1228 | "BSD-3-Clause" 1229 | ], 1230 | "authors": [ 1231 | { 1232 | "name": "Jeff Welch", 1233 | "email": "whatthejeff@gmail.com" 1234 | }, 1235 | { 1236 | "name": "Sebastian Bergmann", 1237 | "email": "sebastian@phpunit.de" 1238 | }, 1239 | { 1240 | "name": "Adam Harvey", 1241 | "email": "aharvey@php.net" 1242 | } 1243 | ], 1244 | "description": "Provides functionality to recursively process PHP variables", 1245 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1246 | "time": "2017-03-03T06:23:57+00:00" 1247 | }, 1248 | { 1249 | "name": "sebastian/resource-operations", 1250 | "version": "2.0.1", 1251 | "source": { 1252 | "type": "git", 1253 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1254 | "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" 1255 | }, 1256 | "dist": { 1257 | "type": "zip", 1258 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", 1259 | "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", 1260 | "shasum": "" 1261 | }, 1262 | "require": { 1263 | "php": "^7.1" 1264 | }, 1265 | "type": "library", 1266 | "extra": { 1267 | "branch-alias": { 1268 | "dev-master": "2.0-dev" 1269 | } 1270 | }, 1271 | "autoload": { 1272 | "classmap": [ 1273 | "src/" 1274 | ] 1275 | }, 1276 | "notification-url": "https://packagist.org/downloads/", 1277 | "license": [ 1278 | "BSD-3-Clause" 1279 | ], 1280 | "authors": [ 1281 | { 1282 | "name": "Sebastian Bergmann", 1283 | "email": "sebastian@phpunit.de" 1284 | } 1285 | ], 1286 | "description": "Provides a list of PHP built-in functions that operate on resources", 1287 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1288 | "time": "2018-10-04T04:07:39+00:00" 1289 | }, 1290 | { 1291 | "name": "sebastian/version", 1292 | "version": "2.0.1", 1293 | "source": { 1294 | "type": "git", 1295 | "url": "https://github.com/sebastianbergmann/version.git", 1296 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 1297 | }, 1298 | "dist": { 1299 | "type": "zip", 1300 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 1301 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 1302 | "shasum": "" 1303 | }, 1304 | "require": { 1305 | "php": ">=5.6" 1306 | }, 1307 | "type": "library", 1308 | "extra": { 1309 | "branch-alias": { 1310 | "dev-master": "2.0.x-dev" 1311 | } 1312 | }, 1313 | "autoload": { 1314 | "classmap": [ 1315 | "src/" 1316 | ] 1317 | }, 1318 | "notification-url": "https://packagist.org/downloads/", 1319 | "license": [ 1320 | "BSD-3-Clause" 1321 | ], 1322 | "authors": [ 1323 | { 1324 | "name": "Sebastian Bergmann", 1325 | "email": "sebastian@phpunit.de", 1326 | "role": "lead" 1327 | } 1328 | ], 1329 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1330 | "homepage": "https://github.com/sebastianbergmann/version", 1331 | "time": "2016-10-03T07:35:21+00:00" 1332 | }, 1333 | { 1334 | "name": "symfony/polyfill-ctype", 1335 | "version": "v1.11.0", 1336 | "source": { 1337 | "type": "git", 1338 | "url": "https://github.com/symfony/polyfill-ctype.git", 1339 | "reference": "82ebae02209c21113908c229e9883c419720738a" 1340 | }, 1341 | "dist": { 1342 | "type": "zip", 1343 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", 1344 | "reference": "82ebae02209c21113908c229e9883c419720738a", 1345 | "shasum": "" 1346 | }, 1347 | "require": { 1348 | "php": ">=5.3.3" 1349 | }, 1350 | "suggest": { 1351 | "ext-ctype": "For best performance" 1352 | }, 1353 | "type": "library", 1354 | "extra": { 1355 | "branch-alias": { 1356 | "dev-master": "1.11-dev" 1357 | } 1358 | }, 1359 | "autoload": { 1360 | "psr-4": { 1361 | "Symfony\\Polyfill\\Ctype\\": "" 1362 | }, 1363 | "files": [ 1364 | "bootstrap.php" 1365 | ] 1366 | }, 1367 | "notification-url": "https://packagist.org/downloads/", 1368 | "license": [ 1369 | "MIT" 1370 | ], 1371 | "authors": [ 1372 | { 1373 | "name": "Symfony Community", 1374 | "homepage": "https://symfony.com/contributors" 1375 | }, 1376 | { 1377 | "name": "Gert de Pagter", 1378 | "email": "BackEndTea@gmail.com" 1379 | } 1380 | ], 1381 | "description": "Symfony polyfill for ctype functions", 1382 | "homepage": "https://symfony.com", 1383 | "keywords": [ 1384 | "compatibility", 1385 | "ctype", 1386 | "polyfill", 1387 | "portable" 1388 | ], 1389 | "time": "2019-02-06T07:57:58+00:00" 1390 | }, 1391 | { 1392 | "name": "theseer/tokenizer", 1393 | "version": "1.1.2", 1394 | "source": { 1395 | "type": "git", 1396 | "url": "https://github.com/theseer/tokenizer.git", 1397 | "reference": "1c42705be2b6c1de5904f8afacef5895cab44bf8" 1398 | }, 1399 | "dist": { 1400 | "type": "zip", 1401 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/1c42705be2b6c1de5904f8afacef5895cab44bf8", 1402 | "reference": "1c42705be2b6c1de5904f8afacef5895cab44bf8", 1403 | "shasum": "" 1404 | }, 1405 | "require": { 1406 | "ext-dom": "*", 1407 | "ext-tokenizer": "*", 1408 | "ext-xmlwriter": "*", 1409 | "php": "^7.0" 1410 | }, 1411 | "type": "library", 1412 | "autoload": { 1413 | "classmap": [ 1414 | "src/" 1415 | ] 1416 | }, 1417 | "notification-url": "https://packagist.org/downloads/", 1418 | "license": [ 1419 | "BSD-3-Clause" 1420 | ], 1421 | "authors": [ 1422 | { 1423 | "name": "Arne Blankerts", 1424 | "email": "arne@blankerts.de", 1425 | "role": "Developer" 1426 | } 1427 | ], 1428 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 1429 | "time": "2019-04-04T09:56:43+00:00" 1430 | }, 1431 | { 1432 | "name": "webmozart/assert", 1433 | "version": "1.4.0", 1434 | "source": { 1435 | "type": "git", 1436 | "url": "https://github.com/webmozart/assert.git", 1437 | "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" 1438 | }, 1439 | "dist": { 1440 | "type": "zip", 1441 | "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", 1442 | "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", 1443 | "shasum": "" 1444 | }, 1445 | "require": { 1446 | "php": "^5.3.3 || ^7.0", 1447 | "symfony/polyfill-ctype": "^1.8" 1448 | }, 1449 | "require-dev": { 1450 | "phpunit/phpunit": "^4.6", 1451 | "sebastian/version": "^1.0.1" 1452 | }, 1453 | "type": "library", 1454 | "extra": { 1455 | "branch-alias": { 1456 | "dev-master": "1.3-dev" 1457 | } 1458 | }, 1459 | "autoload": { 1460 | "psr-4": { 1461 | "Webmozart\\Assert\\": "src/" 1462 | } 1463 | }, 1464 | "notification-url": "https://packagist.org/downloads/", 1465 | "license": [ 1466 | "MIT" 1467 | ], 1468 | "authors": [ 1469 | { 1470 | "name": "Bernhard Schussek", 1471 | "email": "bschussek@gmail.com" 1472 | } 1473 | ], 1474 | "description": "Assertions to validate method input/output with nice error messages.", 1475 | "keywords": [ 1476 | "assert", 1477 | "check", 1478 | "validate" 1479 | ], 1480 | "time": "2018-12-25T11:19:39+00:00" 1481 | } 1482 | ], 1483 | "aliases": [], 1484 | "minimum-stability": "stable", 1485 | "stability-flags": [], 1486 | "prefer-stable": false, 1487 | "prefer-lowest": false, 1488 | "platform": { 1489 | "php": "^7.1.3" 1490 | }, 1491 | "platform-dev": [] 1492 | } 1493 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/TestCase 15 | 16 | 17 | 18 | 19 | 20 | ./Messages 21 | ./Menu 22 | FbBotApp.php 23 | UserProfile.php 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tests/Mocks/Menu/LocalizedMenu/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "locale": "default", 3 | "composer_input_disabled": false, 4 | "call_to_actions": [ 5 | { 6 | "type": "postback", 7 | "title": "title_1", 8 | "payload": "PAYLOAD_1" 9 | }, 10 | { 11 | "type": "postback", 12 | "title": "title_2", 13 | "payload": "PAYLOAD_2" 14 | }, 15 | { 16 | "type": "postback", 17 | "title": "title_3", 18 | "payload": "PAYLOAD_3" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tests/Mocks/Menu/LocalizedMenu/default_no_items.json: -------------------------------------------------------------------------------- 1 | { 2 | "locale": "default", 3 | "composer_input_disabled": false 4 | } 5 | -------------------------------------------------------------------------------- /tests/Mocks/Menu/MenuItem/nested.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "nested", 3 | "title": "title", 4 | "call_to_actions": [ 5 | { 6 | "type": "postback", 7 | "title": "title_1", 8 | "payload": "PAYLOAD_1" 9 | }, 10 | { 11 | "type": "postback", 12 | "title": "title_2", 13 | "payload": "PAYLOAD_2" 14 | }, 15 | { 16 | "type": "postback", 17 | "title": "title_3", 18 | "payload": "PAYLOAD_3" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tests/Mocks/Menu/MenuItem/postback.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "postback", 3 | "title": "title", 4 | "payload": "PAYLOAD" 5 | } 6 | -------------------------------------------------------------------------------- /tests/Mocks/Menu/MenuItem/web.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "web_url", 3 | "url": "https://github.com/pimax/fb-messenger-php/issues", 4 | "title": "title", 5 | "webview_height_ratio": "full", 6 | "messenger_extensions": true, 7 | "fallback_url": "https://github.com/pimax/fb-messenger-php", 8 | "webview_share_button": "hide" 9 | } 10 | -------------------------------------------------------------------------------- /tests/Mocks/Messages/AccountLink/link.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "title", 3 | "subtitle": "subtitle", 4 | "image_url": "https://www.facebook.com/images/fb_icon_325x325.png", 5 | "buttons": [ 6 | { 7 | "type": "account_link", 8 | "url": "https://www.example.com/oauth/authorize" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tests/Mocks/Messages/AccountLink/unlink.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "title", 3 | "subtitle": "subtitle", 4 | "image_url": "https://www.facebook.com/images/fb_icon_325x325.png", 5 | "buttons": [ 6 | { 7 | "type": "account_unlink" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /tests/Mocks/Messages/SenderAction/mark_seen.json: -------------------------------------------------------------------------------- 1 | { 2 | "recipient": { 3 | "id": "1234567890" 4 | }, 5 | "sender_action": "mark_seen" 6 | } 7 | -------------------------------------------------------------------------------- /tests/Mocks/Messages/SenderAction/typing_off.json: -------------------------------------------------------------------------------- 1 | { 2 | "recipient": { 3 | "id": "1234567890" 4 | }, 5 | "sender_action": "typing_off" 6 | } 7 | -------------------------------------------------------------------------------- /tests/Mocks/Messages/SenderAction/typing_on.json: -------------------------------------------------------------------------------- 1 | { 2 | "recipient": { 3 | "id": "1234567890" 4 | }, 5 | "sender_action": "typing_on" 6 | } 7 | -------------------------------------------------------------------------------- /tests/Mocks/Response/User/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Peter", 3 | "last_name": "Chang", 4 | "profile_pic": "https://placeimg.com/200/200/nature", 5 | "locale": "en_US", 6 | "timezone": -7, 7 | "gender": "male" 8 | } -------------------------------------------------------------------------------- /tests/TestCase/AbstractTestCase.php: -------------------------------------------------------------------------------- 1 | assertJsonStringEqualsJsonString($expectedJson, json_encode($localizedMenu->getData())); 29 | } 30 | 31 | public function testLocalizedMenuWithoutItems(): void 32 | { 33 | $expectedJson = file_get_contents(__DIR__ . '/../../Mocks/Menu/LocalizedMenu/default_no_items.json'); 34 | 35 | $localizedMenu = new LocalizedMenu('default', false); 36 | 37 | $this->assertJsonStringEqualsJsonString($expectedJson, json_encode($localizedMenu->getData())); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/TestCase/Menu/MenuItemTest.php: -------------------------------------------------------------------------------- 1 | assertJsonStringEqualsJsonString($expectedJson, json_encode($menuItem->getData())); 20 | } 21 | 22 | public function testItemWeb(): void 23 | { 24 | $expectedJson = file_get_contents(__DIR__ . '/../../Mocks/Menu/MenuItem/web.json'); 25 | 26 | $menuItem = new MenuItem( 27 | MenuItem::TYPE_WEB, 28 | 'title', 29 | 'https://github.com/pimax/fb-messenger-php/issues', 30 | 'full', 31 | true, 32 | 'https://github.com/pimax/fb-messenger-php', 33 | 'hide' 34 | ); 35 | 36 | $this->assertJsonStringEqualsJsonString($expectedJson, json_encode($menuItem->getData())); 37 | } 38 | 39 | public function testItemNested(): void 40 | { 41 | $expectedJson = file_get_contents(__DIR__ . '/../../Mocks/Menu/MenuItem/nested.json'); 42 | 43 | $menuItem = new MenuItem( 44 | MenuItem::TYPE_NESTED, 45 | 'title', 46 | [ 47 | new MenuItem(MenuItem::TYPE_POSTBACK, 'title_1', 'PAYLOAD_1'), 48 | new MenuItem(MenuItem::TYPE_POSTBACK, 'title_2', 'PAYLOAD_2'), 49 | new MenuItem(MenuItem::TYPE_POSTBACK, 'title_3', 'PAYLOAD_3'), 50 | ] 51 | ); 52 | 53 | $this->assertJsonStringEqualsJsonString($expectedJson, json_encode($menuItem->getData())); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/TestCase/Messages/AccountLinkTest.php: -------------------------------------------------------------------------------- 1 | assertJsonStringEqualsJsonString($expectedJson, json_encode($accountLink->getData())); 26 | } 27 | 28 | public function testAccountUnlink(): void 29 | { 30 | $expectedJson = file_get_contents(__DIR__ . '/../../Mocks/Messages/AccountLink/unlink.json'); 31 | 32 | $accountUnlink = new AccountLink( 33 | $title='title', 34 | $subtitle='subtitle', 35 | $url='', 36 | $image_url='https://www.facebook.com/images/fb_icon_325x325.png', 37 | $logout=true 38 | ); 39 | 40 | $this->assertJsonStringEqualsJsonString($expectedJson, json_encode($accountUnlink->getData())); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/TestCase/Messages/SenderActionTest.php: -------------------------------------------------------------------------------- 1 | assertJsonStringEqualsJsonString($expectedJson, json_encode($markSeen->getData())); 20 | } 21 | 22 | public function testTypingOn(): void 23 | { 24 | $expectedJson = file_get_contents(__DIR__ . '/../../Mocks/Messages/SenderAction/typing_on.json'); 25 | 26 | $typingOn = new SenderAction('1234567890', SenderAction::ACTION_TYPING_ON); 27 | 28 | $this->assertJsonStringEqualsJsonString($expectedJson, json_encode($typingOn->getData())); 29 | } 30 | 31 | public function testTypingOff(): void 32 | { 33 | $expectedJson = file_get_contents(__DIR__ . '/../../Mocks/Messages/SenderAction/typing_off.json'); 34 | 35 | $typingOff = new SenderAction('1234567890', SenderAction::ACTION_TYPING_OFF); 36 | 37 | $this->assertJsonStringEqualsJsonString($expectedJson, json_encode($typingOff->getData())); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/TestCase/UserProfile/UserProfileTest.php: -------------------------------------------------------------------------------- 1 | data = file_get_contents(__DIR__ . '/../../Mocks/Response/User/user.json'); 23 | 24 | $this->userProfile = new UserProfile(json_decode($this->data, true)); 25 | } 26 | 27 | public function testUserProfile(): void 28 | { 29 | $this->assertSame('Peter', $this->userProfile->getFirstName()); 30 | $this->assertSame('Chang', $this->userProfile->getLastName()); 31 | $this->assertSame('https://placeimg.com/200/200/nature', $this->userProfile->getPicture()); 32 | $this->assertSame('en_US', $this->userProfile->getLocale()); 33 | $this->assertSame(-7, $this->userProfile->getTimezone()); 34 | $this->assertSame('male', $this->userProfile->getGender()); 35 | } 36 | 37 | public function testUserProfileData(): void 38 | { 39 | $this->assertJsonStringEqualsJsonString($this->data, json_encode($this->userProfile->getData())); 40 | } 41 | } 42 | --------------------------------------------------------------------------------