├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── chat.php ├── database └── migrations │ ├── 2023_09_14_063446_create_channel_table.php │ ├── 2023_09_14_063507_create_channel_users_table.php │ ├── 2023_09_14_063530_create_message_table.php │ ├── 2023_09_18_063016_create_message_read_table.php │ ├── 2023_11_07_133442_alter_channel_table_for_add_slug_fields.php │ └── 2024_01_09_110654_create_message_varibale_table.php ├── src ├── Channel.php ├── Events │ ├── CreateChannel.php │ ├── DeleteMessage.php │ ├── SendMessage.php │ └── UpdateMessage.php ├── Exceptions │ └── InvalidConfig.php ├── Facades │ ├── Channel.php │ ├── Message.php │ └── User.php ├── Helpers │ └── Helper.php ├── Message.php ├── Models │ ├── Channel.php │ ├── ChannelUser.php │ ├── Message.php │ ├── MessageRead.php │ └── MessageVariable.php ├── Providers │ └── ChatServiceProvider.php └── User.php └── vendor ├── autoload.php └── composer ├── ClassLoader.php ├── LICENSE ├── autoload_classmap.php ├── autoload_namespaces.php ├── autoload_psr4.php ├── autoload_real.php └── autoload_static.php /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | composer.lock 3 | docs 4 | vendor/* 5 | coverage 6 | .idea -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `sevenspan/chat` will be documented in this file 4 | 5 | ## 1.0.0 - 2023-10-05 6 | 7 | - initial release 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Spatie bvba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Chat 2 | 3 | The Laravel Chat package simplifies one-to-one and group chat integration facilitates document sharing within chats, manages read and unread message counts, and supports document uploads to both local and AWS S3 storage 4 | 5 | ## Index 6 | 7 | - [Prerequisites](#prerequisites) 8 | - [Features](#features) 9 | - [Installation](#installation) 10 | - [Configurations](#configurations) 11 | - [Credits](#credits) 12 | - [Contributing](#contributing) 13 | - [License](#license) 14 | 15 | ## **Prerequisites** 16 | 17 | Before you get started, make sure you have the following prerequisites installed: 18 | 19 | - PHP >= 8.1 (Support 8.2) 20 | - Composer >= 2.0 21 | - Laravel >= 8.1 (Supports L10 and L11) 22 | - AWS API credentials (Optional) 23 | - Pusher 24 | 25 | ## **Features** 26 | 27 | - One-to-One Chat Integration 28 | - Group Chat Integration 29 | - Document Sharing within Chats 30 | - Read and Unread Message Count Management 31 | - Document Upload Support for Local Storage 32 | - Document Upload Support for AWS S3 Storage 33 | - Message body encryption and decryption 34 | 35 | ## **Installation** 36 | 37 | To install this package, use Composer: 38 | 39 | ```bash 40 | composer require sevenspan/laravel-chat 41 | ``` 42 | 43 | ## **Configurations** 44 | 45 | To configure the package, publish the migration file with the following command: 46 | 47 | ```bash 48 | php artisan vendor:publish --provider="SevenSpan\Chat\Providers\ChatServiceProvider" 49 | ``` 50 | 51 | This command will publish the configuration file chat.php to your project's config directories, respectively. 52 | 53 | If you have cached configurations locally, clear the config cache using one of these commands: 54 | 55 | ``` 56 | php artisan optimize:clear 57 | ``` 58 | 59 | After publishing the migration and configuring, create the required tables for this package by running: 60 | 61 | ``` 62 | php artisan migrate 63 | ``` 64 | 65 | To configure message body encryption add these key on `.env` file. 66 | 67 | ``` 68 | CHAT_ENCRYPT_MESSAGE=true #boolean 69 | ``` 70 | 71 | ## Usage 72 | 73 | Once you have installed the package, you can start using its features in your Laravel application. Here's a brief overview of how to use some of the main features: 74 | 75 | ### 1. List Channels 76 | 77 | Use the `list` method to get all channels. 78 | 79 | 80 | ``` php 81 | use SevenSpan\Chat\Facades\Channel; 82 | 83 | // $userId = 12; (Required) 84 | // $perPage = 10; (Optional) 85 | 86 | Channel::list($userId, $perPage); 87 | ``` 88 | 89 | ### 2. Detail of Channel 90 | 91 | Use the `detail` method to get the detail of channel. 92 | 93 | 94 | ``` php 95 | use SevenSpan\Chat\Facades\Channel; 96 | 97 | // $userId = 12; (Required) 98 | // $channelId = 10; (Required) 99 | 100 | Channel::detail($userId, $channelId); 101 | ``` 102 | 103 | ### 3. Create Channel 104 | 105 | Use the `create` method to create the new channel. 106 | 107 | 108 | ``` php 109 | use SevenSpan\Chat\Facades\Channel; 110 | 111 | // $userId = 12; (Required) 112 | // $receiverId = 10; (Required) 113 | // $channelName = "Goverment project" (Required) 114 | 115 | Channel::create($userId, $receiverId, $channelName); 116 | ``` 117 | 118 | 119 | ### 4. Update Channel 120 | 121 | Use the `update` method to update the channel details. 122 | 123 | 124 | ``` php 125 | use SevenSpan\Chat\Facades\Channel; 126 | 127 | // $userId = 12; (Required) 128 | // $receiverId = 10; (Required) 129 | // $channelName = "Goverment project" (Required) 130 | 131 | Channel::update($userId, $receiverId, $channelName); 132 | ``` 133 | 134 | ### 5. Delete Channel 135 | 136 | Use the `delete` method to delete the channel. 137 | 138 | 139 | ``` php 140 | use SevenSpan\Chat\Facades\Channel; 141 | 142 | // $userId = 12; (Required) 143 | // $channelId = 10; (Required) 144 | 145 | Channel::delete($userId, $channelId); 146 | ``` 147 | 148 | ### 6. Clear Channel History 149 | 150 | Use the `clearMessage` method to clear the chat history. 151 | 152 | ```php 153 | use SevenSpan\Chat\Facades\Channel; 154 | 155 | // $userId = 1; (Required) 156 | // $channelId = 1 (Required) 157 | 158 | Channel::clearMessage($userId, $channelId); 159 | ``` 160 | 161 | ### 7. List Message 162 | 163 | Use the `list` method to get all messages of the channel. 164 | 165 | ```php 166 | use SevenSpan\Chat\Facades\Message; 167 | 168 | // $userId = 1; (Required) 169 | // $channelId = 1 (Required) 170 | // $perPage = 10; (Optional) 171 | 172 | Message::list($userId, $channelId, $perPage); 173 | ``` 174 | 175 | ### 8. Send Message 176 | 177 | Use the `send` method to send a message. 178 | 179 | ```php 180 | use SevenSpan\Chat\Facades\Message; 181 | 182 | // $userId = 1; (Required) 183 | // $channelId = 1 (Required) 184 | // $data = [ 185 | // 'body' => 'TEXT_MESSAGE', 186 | // 'file' => Image Or Document 187 | // ]; (Required) 188 | 189 | Message::send($userId, $channelId, $data); 190 | ``` 191 | 192 | > [!NOTE] 193 | > In the $data param either body or file is required. 194 | 195 | ### 9. Get Files Message 196 | 197 | Use the `getFiles` method to document of the channel. 198 | 199 | ```php 200 | use SevenSpan\Chat\Facades\Message; 201 | 202 | // $userId = 1; (Required) 203 | // $channelId = 1 (Required) 204 | // $type = 'image' (Default: image) 205 | // $perPage = 10; (Optional) 206 | 207 | Message::getFiles($userId, $channelId, $type, $perPage); 208 | ``` 209 | 210 | > [!NOTE] 211 | > $type param supported value is `image` or `zip`. 212 | 213 | ### 10. Delete Message 214 | 215 | Use the `delete` method to delete the message. 216 | 217 | ```php 218 | use SevenSpan\Chat\Facades\Message; 219 | 220 | // $userId = 1; (Required) 221 | // $channelId = 1 (Required) 222 | // $messageId = 10; (Required) 223 | 224 | Message::delete($userId, $channelId, $messageId); 225 | ``` 226 | 227 | ### 11. Read Message 228 | 229 | Use the `read` method to read the message of a channel. 230 | 231 | ```php 232 | use SevenSpan\Chat\Facades\Message; 233 | 234 | // $userId = 1; (Required) 235 | // $channelId = 1 (Required) 236 | // $messageId = 10; (Required) 237 | 238 | Message::read($userId, $channelId, $messageId); 239 | ``` 240 | > [!NOTE] 241 | > The messages that have a lesser value than $messageId will be read automatically. 242 | 243 | ### 12. User List 244 | 245 | Use the `list` method to get a list of users and also search for the name of the user. 246 | 247 | ```php 248 | use SevenSpan\Chat\Facades\User; 249 | 250 | // $userId = 1; (Required) 251 | // $name = "John Doe" (Optional) 252 | // $perPage = 10; (Optional) 253 | 254 | User::list($userId, $name, $perPage); 255 | ``` 256 | 257 | ## Credits 258 | 259 | - [Harshil Patanvadiya](https://github.com/harshil-patanvadiya) 260 | - [Kajal Pandya](https://github.com/kajal98) 261 | - [Hemratna Bhimani](https://github.com/hemratna) 262 | 263 | ## Contributing 264 | 265 | If you encounter any issues or would like to contribute to this package, we welcome contributions from the community to improve and enhance this package. If you'd like to contribute, please follow our contribution guidelines: 266 | 267 | - Fork this repository. 268 | - Clone the forked repository to your local machine. 269 | - Create a new branch for your feature or bug fix: git checkout -b feature/your-feature-name 270 | - Make your changes and commit them: git commit -m 'Add new feature' 271 | - Push your changes to your fork: git push origin feature/your-feature-name 272 | - Create a pull request to the original repository. 273 | 274 | ## License 275 | 276 | This package is open-source software licensed under the MIT License. Feel free to use, modify, and distribute it according to the terms of the license. 277 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sevenspan/laravel-chat", 3 | "description": "The Laravel Chat package simplifies one-to-one and group chat integration, facilitates document sharing within chats, manages read and unread message counts, and supports document uploads to both local and AWS S3 storage", 4 | "keywords": [ 5 | "laravel", 6 | "chat", 7 | "chat-package", 8 | "chat-system", 9 | "chat-application", 10 | "composer", 11 | "messaging-package", 12 | "laravel-chat" 13 | ], 14 | "homepage": "https://github.com/7span/chat", 15 | "license": "MIT", 16 | "authors": [ 17 | { 18 | "name": "Harshil Patanvadiya", 19 | "email": "harshilpatanvadiya55@gmail.com", 20 | "homepage": "https://github.com/harshil-patanvadiya", 21 | "role": "Developer" 22 | }, 23 | { 24 | "name": "Kajal Pandiya", 25 | "email": "kjlkajal98@gmail.com", 26 | "homepage": "https://github.com/kajal98", 27 | "role": "Developer" 28 | }, 29 | { 30 | "name": "Hemratna Bhimani", 31 | "email": "hemratna.bhimani@gmail.com", 32 | "homepage": "https://github.com/hemratna", 33 | "role": "Developer" 34 | } 35 | ], 36 | "require": { 37 | "php": "^8.1 || ^8.2", 38 | "aws/aws-sdk-php": "^3.283", 39 | "league/flysystem-aws-s3-v3": "^3.0", 40 | "spatie/laravel-sluggable": "^3.5" 41 | }, 42 | "autoload": { 43 | "psr-4": { 44 | "SevenSpan\\Chat\\": "src" 45 | } 46 | }, 47 | "autoload-dev": { 48 | "psr-4": { 49 | "SevenSpan\\Chat\\Tests\\": "tests" 50 | } 51 | }, 52 | "scripts": {}, 53 | "config": { 54 | "sort-packages": true 55 | }, 56 | "extra": { 57 | "laravel": { 58 | "providers": [ 59 | "SevenSpan\\Chat\\Providers\\ChatServiceProvider" 60 | ], 61 | "aliases": { 62 | "User": "SevenSpan\\Chat\\Facades\\User", 63 | "Channel": "SevenSpan\\Chat\\Facades\\Channel", 64 | "Message": "SevenSpan\\Chat\\Facades\\Message" 65 | } 66 | } 67 | }, 68 | "minimum-stability": "dev", 69 | "prefer-stable": true 70 | } 71 | -------------------------------------------------------------------------------- /config/chat.php: -------------------------------------------------------------------------------- 1 | env('CHAT_MEDIA_FOLDER', 'image'), 15 | 'pusher_event_trigger' => [ 16 | 'send_message' => env('CHAT_SEND_MESSAGE_PUSHER_EVENT', true) 17 | ], 18 | 'encrypt_message' => env('CHAT_ENCRYPT_MESSAGE', false), 19 | ]; 20 | -------------------------------------------------------------------------------- /database/migrations/2023_09_14_063446_create_channel_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('name', 120); 17 | $table->unsignedBigInteger('created_by')->nullable(); 18 | $table->unsignedBigInteger('updated_by')->nullable(); 19 | $table->unsignedBigInteger('deleted_by')->nullable(); 20 | $table->timestamps(); 21 | $table->softDeletes(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | */ 28 | public function down(): void 29 | { 30 | Schema::dropIfExists('channels'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /database/migrations/2023_09_14_063507_create_channel_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->unsignedBigInteger('channel_id')->index(); 17 | $table->unsignedBigInteger('user_id')->index(); 18 | $table->bigInteger('unread_message_count')->default(0); 19 | 20 | $table->unsignedBigInteger('created_by')->nullable(); 21 | $table->unsignedBigInteger('updated_by')->nullable(); 22 | $table->unsignedBigInteger('deleted_by')->nullable(); 23 | $table->timestamps(); 24 | $table->softDeletes(); 25 | 26 | $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); 27 | }); 28 | } 29 | 30 | /** 31 | * Reverse the migrations. 32 | */ 33 | public function down(): void 34 | { 35 | Schema::dropIfExists('channel_users'); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /database/migrations/2023_09_14_063530_create_message_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->unsignedBigInteger('sender_id')->index(); 17 | $table->unsignedBigInteger('channel_id')->index(); 18 | $table->text('body')->nullable(); 19 | $table->string('disk', 64)->nullable(); 20 | $table->string('path', 64)->nullable(); 21 | $table->string('filename', 64)->nullable(); 22 | $table->bigInteger('size')->nullable(); 23 | $table->string('mime_type', 32)->nullable(); 24 | $table->string('type', 64)->default('text'); 25 | 26 | $table->unsignedBigInteger('created_by')->nullable(); 27 | $table->unsignedBigInteger('updated_by')->nullable(); 28 | $table->unsignedBigInteger('deleted_by')->nullable(); 29 | $table->timestamps(); 30 | $table->softDeletes(); 31 | 32 | $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); 33 | }); 34 | } 35 | 36 | /** 37 | * Reverse the migrations. 38 | */ 39 | public function down(): void 40 | { 41 | Schema::dropIfExists('messages'); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /database/migrations/2023_09_18_063016_create_message_read_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->unsignedBigInteger('user_id')->index(); 17 | $table->unsignedBigInteger('channel_id')->index(); 18 | $table->unsignedBigInteger('message_id')->index(); 19 | $table->timestamp('read_at')->nullable(); 20 | 21 | $table->unsignedBigInteger('created_by')->nullable(); 22 | $table->unsignedBigInteger('updated_by')->nullable(); 23 | $table->unsignedBigInteger('deleted_by')->nullable(); 24 | $table->timestamps(); 25 | $table->softDeletes(); 26 | 27 | $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); 28 | $table->foreign('message_id')->references('id')->on('messages')->onDelete('cascade'); 29 | }); 30 | } 31 | 32 | /** 33 | * Reverse the migrations. 34 | */ 35 | public function down(): void 36 | { 37 | Schema::dropIfExists('message_reads'); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /database/migrations/2023_11_07_133442_alter_channel_table_for_add_slug_fields.php: -------------------------------------------------------------------------------- 1 | string('slug')->after('name'); 16 | }); 17 | } 18 | 19 | /** 20 | * Reverse the migrations. 21 | */ 22 | public function down(): void 23 | { 24 | Schema::table('channels', function (Blueprint $table) { 25 | // 26 | }); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /database/migrations/2024_01_09_110654_create_message_varibale_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->unsignedBigInteger('message_id')->index(); 17 | $table->string('key'); 18 | $table->json('meta'); 19 | $table->timestamps(); 20 | $table->softDeletes(); 21 | 22 | $table->foreign('message_id')->references('id')->on('messages')->onDelete('cascade'); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | */ 29 | public function down(): void 30 | { 31 | Schema::dropIfExists('message_variables'); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/Channel.php: -------------------------------------------------------------------------------- 1 | join('channel_users', 'channels.id', '=', 'channel_users.channel_id')->with('channelUsers.user'); 21 | 22 | if (!empty($userId)) { 23 | $channels->where('channel_users.user_id', $userId); 24 | } 25 | 26 | if (count($channelIds) > 0) { 27 | $channels->whereIn('channels.id', $channelIds); 28 | } 29 | 30 | $channels->orderBy(DB::raw('DATE(channel_users.updated_at)'), 'DESC'); 31 | $channels = $perPage ? $channels->paginate($perPage) : $channels->get(); 32 | return $channels; 33 | } 34 | 35 | public function detail(int $userId, int $channelId) 36 | { 37 | $channel = ChannelModel::with('channelUsers.user') 38 | ->whereHas('channelUsers', function ($q) use ($userId) { 39 | $q->where('user_id', $userId); 40 | })->where('id', $channelId)->first(); 41 | 42 | if (empty($channel)) { 43 | $data['errors']['channel'][] = 'Channel not found.'; 44 | return $data; 45 | } 46 | 47 | return $channel; 48 | } 49 | 50 | public function create(int $userId, int $receiverId, string $channelName) 51 | { 52 | if ($userId == $receiverId) { 53 | $data['errors']['message'][] = "The sender and receiver should be different."; 54 | return $data; 55 | } 56 | 57 | $channel = ChannelModel::create(['name' => $channelName, 'created_by' => $userId]); 58 | 59 | ChannelUser::create(['user_id' => $userId, 'channel_id' => $channel->id, 'created_by' => $userId]); 60 | ChannelUser::create(['user_id' => $receiverId, 'channel_id' => $channel->id, 'created_by' => $userId]); 61 | 62 | broadcast(new CreateChannel($channel))->toOthers(); 63 | 64 | $response['message'] = "Channel created successfully."; 65 | $response['data'] = $channel; 66 | return $response; 67 | } 68 | 69 | public function update(int $userId, int $channelId, $channelName) 70 | { 71 | $channel = $this->detail($userId, $channelId); 72 | 73 | if ($channel == null) { 74 | $data['errors']['message'][] = "Channel not found."; 75 | return $data; 76 | } 77 | 78 | $channel->update(['name' => $channelName, 'updated_by' => $userId]); 79 | $data['message'] = "Channel updated successfully."; 80 | return $data; 81 | } 82 | 83 | public function delete(int $userId, int $channelId) 84 | { 85 | $channel = $this->detail($userId, $channelId); 86 | 87 | if ($channel == null) { 88 | $data['errors']['message'][] = "Channel not found."; 89 | return $data; 90 | } 91 | 92 | $channel->update(['deleted_by' => $userId]); 93 | 94 | $this->clearMessages($userId, $channelId); 95 | 96 | $channel->channelUsers()->delete(); 97 | $channel->delete(); 98 | 99 | $data['message'] = "Channel deleted successfully."; 100 | return $data; 101 | } 102 | 103 | public function clearMessages(int $userId, int $channelId) 104 | { 105 | $channel = $this->detail($userId, $channelId); 106 | 107 | if ($channel == null) { 108 | $data['errors']['message'][] = "Channel not found."; 109 | return $data; 110 | } 111 | 112 | $messages = Message::where('channel_id', $channelId)->get(); 113 | $documents = $messages->whereNotNull('disk'); 114 | 115 | if ($documents->isNotEmpty()) { 116 | foreach ($documents as $document) { 117 | Helper::fileDelete($document->disk, $document->path, $document->filename); 118 | } 119 | } 120 | 121 | MessageRead::where('channel_id', $channelId)->delete(); 122 | Message::where('channel_id', $channelId)->delete(); 123 | ChannelUser::where('channel_id', $channelId)->update(['unread_message_count' => 0]); 124 | 125 | $data['message'] = "Channel message clear successfully."; 126 | 127 | return $data; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/Events/CreateChannel.php: -------------------------------------------------------------------------------- 1 | channel->slug); 24 | } 25 | 26 | public function broadcastWith() 27 | { 28 | return $this->channel->toArray(); 29 | } 30 | 31 | public function broadcastAs() 32 | { 33 | return 'create-channel'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Events/DeleteMessage.php: -------------------------------------------------------------------------------- 1 | channelSlug); 25 | } 26 | 27 | public function broadcastWith() 28 | { 29 | return $this->message->toArray(); 30 | } 31 | 32 | public function broadcastAs() 33 | { 34 | return 'delete-message'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Events/SendMessage.php: -------------------------------------------------------------------------------- 1 | channelSlug); 25 | } 26 | 27 | public function broadcastWith() 28 | { 29 | return $this->message->toArray(); 30 | } 31 | 32 | public function broadcastAs() 33 | { 34 | return 'send-message'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Events/UpdateMessage.php: -------------------------------------------------------------------------------- 1 | channelSlug); 25 | } 26 | 27 | public function broadcastWith() 28 | { 29 | return $this->message->toArray(); 30 | } 31 | 32 | public function broadcastAs() 33 | { 34 | return 'update-message'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidConfig.php: -------------------------------------------------------------------------------- 1 | extension(); 20 | $size = $file->getSize(); 21 | $mimeType = $file->getClientMimeType(); 22 | 23 | if ($disk == 'local') { 24 | $file->storeAs($path, $filename, 'public'); 25 | } elseif ($disk == 's3') { 26 | $uploadFiles3 = Storage::disk('s3')->putFileAs($path, $file, $filename, 'public'); 27 | 28 | if (!$uploadFiles3) { 29 | $data['errors']['message'][] = 'File is not uploaded into the S3 bucket, Please check you AWS S3 configuration.'; 30 | return $data; 31 | } 32 | $disk = env('AWS_BUCKET') . '.s3.ap-south-1.amazonaws.com'; 33 | } else { 34 | $data['errors']['message'][] = 'File system disk not supported into laravel chat package.'; 35 | return $data; 36 | } 37 | 38 | $data = [ 39 | 'disk' => $disk, 40 | 'path' => $path, 41 | 'filename' => $filename, 42 | 'size' => $size, 43 | 'mime_type' => $mimeType, 44 | 'type' => 'zip' 45 | ]; 46 | 47 | $allowedImageMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; 48 | if (in_array($mimeType, $allowedImageMimeTypes)) { 49 | $data['type'] = 'image'; 50 | } 51 | 52 | return $data; 53 | } 54 | 55 | public static function fileDelete($disk, $path, $fileName) 56 | { 57 | if ($disk == 'local') { 58 | $file = public_path('storage/' . $path . '/' . $fileName); 59 | if (File::exists($file)) { 60 | unlink($file); 61 | return true; 62 | } 63 | } elseif ($disk != 'local') { 64 | Storage::disk('s3')->delete($path . '/' . $fileName); 65 | return true; 66 | } 67 | } 68 | 69 | public static function isEncrypted($value) 70 | { 71 | try { 72 | Crypt::decryptString($value); 73 | return true; 74 | } catch (DecryptException $e) { 75 | return false; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Message.php: -------------------------------------------------------------------------------- 1 | where('channel_id', $channelId) 24 | ->orderBy('id', 'DESC'); 25 | $messages = $perPage ? $messages->paginate($perPage) : $messages->get(); 26 | return $messages; 27 | } 28 | 29 | public function send(int $userId, int $channelId, array $data, array $variables = []) 30 | { 31 | if (!isset($data['body']) && !isset($data['file'])) { 32 | $error['errors']['message'][] = "The message body or file any one is should be required."; 33 | return $error; 34 | } 35 | 36 | $channel = Channel::where('id', $channelId)->first(); 37 | 38 | if ($channel == null) { 39 | $error['errors']['message'][] = "Channel not found."; 40 | return $error; 41 | } 42 | 43 | $messageData = [ 44 | 'channel_id' => $channel->id, 45 | 'sender_id' => $userId, 46 | 'created_by' => $userId, 47 | 'body' => isset($data['body']) ? $data['body'] : null 48 | ]; 49 | 50 | if (isset($data['file'])) { 51 | $file = Helper::fileUpload($data['file']); 52 | if (isset($file['errors'])) { 53 | return $file; 54 | } 55 | $messageData += $file; 56 | } 57 | 58 | $message = MessageModel::create($messageData); 59 | 60 | // Adding the dynamic variables 61 | if(count($variables) > 0 ) { 62 | foreach($variables as $variable) { 63 | if(isset($variable['key']) && isset($variable['meta'])){ 64 | $messageVariable = MessageVariable::create([ 65 | 'message_id' => $message->id, 66 | 'key' => $variable['key'], 67 | 'meta' => $variable['meta'] 68 | ]); 69 | } 70 | } 71 | } 72 | 73 | $message = MessageModel::with(['channel', 'sender', 'variables'])->find($message->id); 74 | 75 | if(config('chat.pusher_event_trigger.send_message')){ 76 | broadcast(new SendMessage($channel->slug, $message))->toOthers(); 77 | } 78 | 79 | // Added the unread message count 80 | ChannelUser::where('channel_id', $channelId)->where('user_id', '!=', $userId)->increment('unread_message_count', 1, ['updated_by' => $userId]); 81 | 82 | // Added the entry into the unread message table 83 | $channelUsers = $channel->channelUsers->where('user_id', '!=', $userId); 84 | foreach ($channelUsers as $channelUser) { 85 | MessageRead::create([ 86 | 'user_id' => $channelUser->user_id, 87 | 'message_id' => $message->id, 88 | 'channel_id' => $channelId, 89 | 'created_by' => $userId 90 | ]); 91 | } 92 | 93 | $response['message'] = 'Message send successfully.'; 94 | $response['data'] = $message; 95 | return $response; 96 | } 97 | 98 | public function update(int $userId, int $channelId, int $messageId, array $data, array $variables = []) 99 | { 100 | if (!isset($data['body']) && !isset($data['file'])) { 101 | $error['errors']['message'][] = "The message body or file any one is should be required."; 102 | return $error; 103 | } 104 | 105 | $channel = Channel::where('id', $channelId)->first(); 106 | 107 | if ($channel == null) { 108 | $error['errors']['message'][] = "Channel not found."; 109 | return $error; 110 | } 111 | 112 | $message = MessageModel::where('id', $messageId)->first(); 113 | 114 | if ($message == null) { 115 | $error['errors']['message'][] = "Message not found."; 116 | return $error; 117 | } 118 | 119 | $messageData = [ 120 | 'body' => isset($data['body']) ? $data['body'] : null 121 | ]; 122 | 123 | if (isset($data['file'])) { 124 | $file = Helper::fileUpload($data['file']); 125 | if (isset($file['errors'])) { 126 | return $file; 127 | } 128 | $messageData += $file; 129 | } 130 | 131 | $message->variables()->delete(); 132 | $message->update($messageData); 133 | 134 | // Adding the dynamic variables 135 | if(count($variables) > 0 ) { 136 | foreach($variables as $variable) { 137 | if(isset($variable['key']) && isset($variable['meta'])){ 138 | MessageVariable::create([ 139 | 'message_id' => $message->id, 140 | 'key' => $variable['key'], 141 | 'meta' => $variable['meta'] 142 | ]); 143 | } 144 | } 145 | } 146 | 147 | $message = MessageModel::with(['channel', 'sender', 'variables'])->find($message->id); 148 | 149 | broadcast(new UpdateMessage($channel->slug, $message))->toOthers(); 150 | 151 | $response['message'] = 'Message updated successfully.'; 152 | $response['data'] = $message; 153 | return $response; 154 | } 155 | 156 | public function getFiles(int $userId, int $channelId, string $type = 'image', int $perPage = null) 157 | { 158 | if (!in_array($type, ['image', 'zip'])) { 159 | $data['errors']['type'][] = 'The files types must be image or zip.'; 160 | return $data; 161 | } 162 | $messages = MessageModel::where('channel_id', $channelId)->where('type', $type)->orderBy('id', 'DESC'); 163 | $messages = $perPage == null ? $messages->get() : $messages->paginate($perPage); 164 | return $messages; 165 | } 166 | 167 | public function delete(int $userId, int $channelId, $messageId) 168 | { 169 | $message = MessageModel::with('channel')->where('sender_id', $userId)->where('channel_id', $channelId)->find($messageId); 170 | 171 | if ($message == null) { 172 | $data['errors']['message'][] = 'Sorry, This message is not found.'; 173 | return $data; 174 | } 175 | if ($message->disk != null) { 176 | Helper::fileDelete($message->disk, $message->path, $message->filename); 177 | } 178 | 179 | $messageRead = MessageRead::where('channel_id', $channelId)->where('message_id', $messageId)->whereNull('read_at'); 180 | $unReadMessage = $messageRead->first(); 181 | 182 | if ($unReadMessage) { 183 | ChannelUser::where("user_id", $unReadMessage->user_id)->where('channel_id', $channelId)->decrement('unread_message_count', 1, ['updated_by' => $userId]); 184 | } 185 | $messageRead->delete(); 186 | 187 | broadcast(new DeleteMessage($message->channel->slug, $message))->toOthers(); 188 | 189 | $message->variables()->delete(); 190 | $message->delete(); 191 | 192 | $data['message'] = "Message deleted successfully."; 193 | return $data; 194 | } 195 | 196 | public function read(int $userId, int $channelId, int $messageId) 197 | { 198 | $message = MessageModel::select('id')->where('channel_id', $channelId)->find($messageId); 199 | 200 | if ($message == null) { 201 | $data['errors']['message'][] = "Message not found."; 202 | return $data; 203 | } 204 | 205 | $unReadMessage = MessageRead::where('user_id', $userId)->where('channel_id', $channelId)->where('message_id', '<=', $messageId)->whereNull('read_at'); 206 | 207 | ChannelUser::where("user_id", $userId)->where('channel_id', $channelId)->decrement('unread_message_count', $unReadMessage->count(), ['updated_by' => $userId]); 208 | 209 | $unReadMessage->update(['read_at' => now()]); 210 | 211 | $data['message'] = 'Messages read successfully.'; 212 | return $data; 213 | } 214 | 215 | public function readAll(int $userId, int $channelId) 216 | { 217 | $channelObj = new ChatChannel(); 218 | $channel = $channelObj->detail($userId, $channelId); 219 | 220 | if ($channel == null) { 221 | $error['errors']['message'][] = "Channel not found."; 222 | return $error; 223 | } 224 | 225 | ChannelUser::where('user_id', $userId)->where('channel_id', $channelId)->update(['unread_message_count' => 0]); 226 | 227 | $data['message'] = "Messages read successfully."; 228 | 229 | return $data; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/Models/Channel.php: -------------------------------------------------------------------------------- 1 | hasMany(ChannelUser::class); 34 | } 35 | 36 | protected $relationship = []; 37 | 38 | protected $scopedFilters = []; 39 | 40 | protected function casts(): array 41 | { 42 | return [ 43 | 'created_at' => 'timestamp', 44 | 'updated_at' => 'timestamp', 45 | 'deleted_at' => 'timestamp' 46 | ]; 47 | } 48 | 49 | public function getSlugOptions(): SlugOptions 50 | { 51 | return SlugOptions::create() 52 | ->generateSlugsFrom('name') 53 | ->saveSlugsTo('slug'); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Models/ChannelUser.php: -------------------------------------------------------------------------------- 1 | 'timestamp', 39 | 'updated_at' => 'timestamp', 40 | 'deleted_at' => 'timestamp' 41 | ]; 42 | } 43 | 44 | public function user() 45 | { 46 | return $this->belongsTo(User::class); 47 | } 48 | 49 | public function channel() 50 | { 51 | return $this->belongsTo(Channel::class); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Models/Message.php: -------------------------------------------------------------------------------- 1 | 'timestamp', 37 | 'updated_at' => 'timestamp', 38 | 'deleted_at' => 'timestamp' 39 | ]; 40 | 41 | protected $hidden = ['deleted_at']; 42 | 43 | public $queryable = [ 44 | 'id' 45 | ]; 46 | 47 | protected $relationship = []; 48 | 49 | protected $scopedFilters = []; 50 | 51 | public function channel() 52 | { 53 | return $this->belongsTo(Channel::class); 54 | } 55 | 56 | public function sender() 57 | { 58 | return $this->belongsTo(User::class); 59 | } 60 | 61 | public function getFileUrlAttribute() 62 | { 63 | $url = null; 64 | if ($this->type != 'text' && $this->disk != null) { 65 | if ($this->disk == 'local') { 66 | $url = Storage::disk('public')->url($this->path . '/' . $this->filename); 67 | } elseif ($this->disk != 'local') { 68 | $url = 'https://' . $this->disk . '/' . $this->path . '/' . $this->filename; 69 | } 70 | } 71 | 72 | return $url; 73 | } 74 | 75 | public function variables() 76 | { 77 | return $this->hasMany(MessageVariable::class, 'message_id', 'id'); 78 | } 79 | 80 | /** 81 | * Get the attributes that should be cast. 82 | * 83 | * @return array 84 | */ 85 | protected function casts(): array 86 | { 87 | if(config('chat.encrypt_message')) { 88 | return [ 89 | 'body' => 'encrypted', 90 | ]; 91 | }else { 92 | return [ 93 | 'body' => 'string', 94 | ]; 95 | } 96 | } 97 | 98 | 99 | protected function body(): Attribute 100 | { 101 | return Attribute::make( 102 | get: function (string $value) { 103 | return Helper::isEncrypted($value) ? Crypt::decryptString($value) : $value; 104 | } 105 | ); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Models/MessageRead.php: -------------------------------------------------------------------------------- 1 | 'timestamp', 29 | 'updated_at' => 'timestamp', 30 | 'deleted_at' => 'timestamp' 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Models/MessageVariable.php: -------------------------------------------------------------------------------- 1 | 'timestamp', 26 | 'updated_at' => 'timestamp', 27 | 'deleted_at' => 'timestamp' 28 | ]; 29 | } 30 | 31 | protected function meta(): Attribute 32 | { 33 | return Attribute::make( 34 | get: fn ($value) => json_decode($value, true), 35 | set: fn ($value) => json_encode($value), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Providers/ChatServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->runningInConsole()) { 18 | $this->publishes([ 19 | __DIR__ . '/../../config/chat.php' => config_path('chat.php'), 20 | ], 'config'); 21 | } 22 | 23 | $this->loadMigrationsFrom(__DIR__ . '/../../database/migrations'); 24 | 25 | $this->app->bind('Channel', function () { 26 | $this->ensureConfigValuesAreSet(); 27 | 28 | return new Channel(); 29 | }); 30 | 31 | $this->app->bind('Message', function () { 32 | $this->ensureConfigValuesAreSet(); 33 | 34 | return new Message(); 35 | }); 36 | 37 | $this->app->bind('User', function () { 38 | $this->ensureConfigValuesAreSet(); 39 | 40 | return new User(); 41 | }); 42 | } 43 | 44 | public function register(): void 45 | { 46 | $this->mergeConfigFrom(__DIR__ . '/../../config/chat.php', 'chat'); 47 | } 48 | 49 | protected function ensureConfigValuesAreSet(): void 50 | { 51 | $mandatoryAttributes = config('chat'); 52 | foreach ($mandatoryAttributes as $key => $value) { 53 | if (!isset($value)) { 54 | throw InvalidConfig::couldNotFindConfig($key); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/User.php: -------------------------------------------------------------------------------- 1 | where("name", 'LIKE', "{$name}%"); 17 | } 18 | 19 | $users = $perPage ? $users->paginate($perPage) : $users->get(); 20 | return $users; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. 17 | * 18 | * $loader = new \Composer\Autoload\ClassLoader(); 19 | * 20 | * // register classes with namespaces 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); 22 | * $loader->add('Symfony', __DIR__.'/framework'); 23 | * 24 | * // activate the autoloader 25 | * $loader->register(); 26 | * 27 | * // to enable searching the include path (eg. for PEAR packages) 28 | * $loader->setUseIncludePath(true); 29 | * 30 | * In this example, if you try to use a class in the Symfony\Component 31 | * namespace or one of its children (Symfony\Component\Console for instance), 32 | * the autoloader will first look for the class under the component/ 33 | * directory, and it will then fallback to the framework/ directory if not 34 | * found before giving up. 35 | * 36 | * This class is loosely based on the Symfony UniversalClassLoader. 37 | * 38 | * @author Fabien Potencier 39 | * @author Jordi Boggiano 40 | * @see https://www.php-fig.org/psr/psr-0/ 41 | * @see https://www.php-fig.org/psr/psr-4/ 42 | */ 43 | class ClassLoader 44 | { 45 | /** @var \Closure(string):void */ 46 | private static $includeFile; 47 | 48 | /** @var string|null */ 49 | private $vendorDir; 50 | 51 | // PSR-4 52 | /** 53 | * @var array> 54 | */ 55 | private $prefixLengthsPsr4 = array(); 56 | /** 57 | * @var array> 58 | */ 59 | private $prefixDirsPsr4 = array(); 60 | /** 61 | * @var list 62 | */ 63 | private $fallbackDirsPsr4 = array(); 64 | 65 | // PSR-0 66 | /** 67 | * List of PSR-0 prefixes 68 | * 69 | * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) 70 | * 71 | * @var array>> 72 | */ 73 | private $prefixesPsr0 = array(); 74 | /** 75 | * @var list 76 | */ 77 | private $fallbackDirsPsr0 = array(); 78 | 79 | /** @var bool */ 80 | private $useIncludePath = false; 81 | 82 | /** 83 | * @var array 84 | */ 85 | private $classMap = array(); 86 | 87 | /** @var bool */ 88 | private $classMapAuthoritative = false; 89 | 90 | /** 91 | * @var array 92 | */ 93 | private $missingClasses = array(); 94 | 95 | /** @var string|null */ 96 | private $apcuPrefix; 97 | 98 | /** 99 | * @var array 100 | */ 101 | private static $registeredLoaders = array(); 102 | 103 | /** 104 | * @param string|null $vendorDir 105 | */ 106 | public function __construct($vendorDir = null) 107 | { 108 | $this->vendorDir = $vendorDir; 109 | self::initializeIncludeClosure(); 110 | } 111 | 112 | /** 113 | * @return array> 114 | */ 115 | public function getPrefixes() 116 | { 117 | if (!empty($this->prefixesPsr0)) { 118 | return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); 119 | } 120 | 121 | return array(); 122 | } 123 | 124 | /** 125 | * @return array> 126 | */ 127 | public function getPrefixesPsr4() 128 | { 129 | return $this->prefixDirsPsr4; 130 | } 131 | 132 | /** 133 | * @return list 134 | */ 135 | public function getFallbackDirs() 136 | { 137 | return $this->fallbackDirsPsr0; 138 | } 139 | 140 | /** 141 | * @return list 142 | */ 143 | public function getFallbackDirsPsr4() 144 | { 145 | return $this->fallbackDirsPsr4; 146 | } 147 | 148 | /** 149 | * @return array Array of classname => path 150 | */ 151 | public function getClassMap() 152 | { 153 | return $this->classMap; 154 | } 155 | 156 | /** 157 | * @param array $classMap Class to filename map 158 | * 159 | * @return void 160 | */ 161 | public function addClassMap(array $classMap) 162 | { 163 | if ($this->classMap) { 164 | $this->classMap = array_merge($this->classMap, $classMap); 165 | } else { 166 | $this->classMap = $classMap; 167 | } 168 | } 169 | 170 | /** 171 | * Registers a set of PSR-0 directories for a given prefix, either 172 | * appending or prepending to the ones previously set for this prefix. 173 | * 174 | * @param string $prefix The prefix 175 | * @param list|string $paths The PSR-0 root directories 176 | * @param bool $prepend Whether to prepend the directories 177 | * 178 | * @return void 179 | */ 180 | public function add($prefix, $paths, $prepend = false) 181 | { 182 | $paths = (array) $paths; 183 | if (!$prefix) { 184 | if ($prepend) { 185 | $this->fallbackDirsPsr0 = array_merge( 186 | $paths, 187 | $this->fallbackDirsPsr0 188 | ); 189 | } else { 190 | $this->fallbackDirsPsr0 = array_merge( 191 | $this->fallbackDirsPsr0, 192 | $paths 193 | ); 194 | } 195 | 196 | return; 197 | } 198 | 199 | $first = $prefix[0]; 200 | if (!isset($this->prefixesPsr0[$first][$prefix])) { 201 | $this->prefixesPsr0[$first][$prefix] = $paths; 202 | 203 | return; 204 | } 205 | if ($prepend) { 206 | $this->prefixesPsr0[$first][$prefix] = array_merge( 207 | $paths, 208 | $this->prefixesPsr0[$first][$prefix] 209 | ); 210 | } else { 211 | $this->prefixesPsr0[$first][$prefix] = array_merge( 212 | $this->prefixesPsr0[$first][$prefix], 213 | $paths 214 | ); 215 | } 216 | } 217 | 218 | /** 219 | * Registers a set of PSR-4 directories for a given namespace, either 220 | * appending or prepending to the ones previously set for this namespace. 221 | * 222 | * @param string $prefix The prefix/namespace, with trailing '\\' 223 | * @param list|string $paths The PSR-4 base directories 224 | * @param bool $prepend Whether to prepend the directories 225 | * 226 | * @throws \InvalidArgumentException 227 | * 228 | * @return void 229 | */ 230 | public function addPsr4($prefix, $paths, $prepend = false) 231 | { 232 | $paths = (array) $paths; 233 | if (!$prefix) { 234 | // Register directories for the root namespace. 235 | if ($prepend) { 236 | $this->fallbackDirsPsr4 = array_merge( 237 | $paths, 238 | $this->fallbackDirsPsr4 239 | ); 240 | } else { 241 | $this->fallbackDirsPsr4 = array_merge( 242 | $this->fallbackDirsPsr4, 243 | $paths 244 | ); 245 | } 246 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 247 | // Register directories for a new namespace. 248 | $length = strlen($prefix); 249 | if ('\\' !== $prefix[$length - 1]) { 250 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 251 | } 252 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 253 | $this->prefixDirsPsr4[$prefix] = $paths; 254 | } elseif ($prepend) { 255 | // Prepend directories for an already registered namespace. 256 | $this->prefixDirsPsr4[$prefix] = array_merge( 257 | $paths, 258 | $this->prefixDirsPsr4[$prefix] 259 | ); 260 | } else { 261 | // Append directories for an already registered namespace. 262 | $this->prefixDirsPsr4[$prefix] = array_merge( 263 | $this->prefixDirsPsr4[$prefix], 264 | $paths 265 | ); 266 | } 267 | } 268 | 269 | /** 270 | * Registers a set of PSR-0 directories for a given prefix, 271 | * replacing any others previously set for this prefix. 272 | * 273 | * @param string $prefix The prefix 274 | * @param list|string $paths The PSR-0 base directories 275 | * 276 | * @return void 277 | */ 278 | public function set($prefix, $paths) 279 | { 280 | if (!$prefix) { 281 | $this->fallbackDirsPsr0 = (array) $paths; 282 | } else { 283 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 284 | } 285 | } 286 | 287 | /** 288 | * Registers a set of PSR-4 directories for a given namespace, 289 | * replacing any others previously set for this namespace. 290 | * 291 | * @param string $prefix The prefix/namespace, with trailing '\\' 292 | * @param list|string $paths The PSR-4 base directories 293 | * 294 | * @throws \InvalidArgumentException 295 | * 296 | * @return void 297 | */ 298 | public function setPsr4($prefix, $paths) 299 | { 300 | if (!$prefix) { 301 | $this->fallbackDirsPsr4 = (array) $paths; 302 | } else { 303 | $length = strlen($prefix); 304 | if ('\\' !== $prefix[$length - 1]) { 305 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 306 | } 307 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 308 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 309 | } 310 | } 311 | 312 | /** 313 | * Turns on searching the include path for class files. 314 | * 315 | * @param bool $useIncludePath 316 | * 317 | * @return void 318 | */ 319 | public function setUseIncludePath($useIncludePath) 320 | { 321 | $this->useIncludePath = $useIncludePath; 322 | } 323 | 324 | /** 325 | * Can be used to check if the autoloader uses the include path to check 326 | * for classes. 327 | * 328 | * @return bool 329 | */ 330 | public function getUseIncludePath() 331 | { 332 | return $this->useIncludePath; 333 | } 334 | 335 | /** 336 | * Turns off searching the prefix and fallback directories for classes 337 | * that have not been registered with the class map. 338 | * 339 | * @param bool $classMapAuthoritative 340 | * 341 | * @return void 342 | */ 343 | public function setClassMapAuthoritative($classMapAuthoritative) 344 | { 345 | $this->classMapAuthoritative = $classMapAuthoritative; 346 | } 347 | 348 | /** 349 | * Should class lookup fail if not found in the current class map? 350 | * 351 | * @return bool 352 | */ 353 | public function isClassMapAuthoritative() 354 | { 355 | return $this->classMapAuthoritative; 356 | } 357 | 358 | /** 359 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. 360 | * 361 | * @param string|null $apcuPrefix 362 | * 363 | * @return void 364 | */ 365 | public function setApcuPrefix($apcuPrefix) 366 | { 367 | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; 368 | } 369 | 370 | /** 371 | * The APCu prefix in use, or null if APCu caching is not enabled. 372 | * 373 | * @return string|null 374 | */ 375 | public function getApcuPrefix() 376 | { 377 | return $this->apcuPrefix; 378 | } 379 | 380 | /** 381 | * Registers this instance as an autoloader. 382 | * 383 | * @param bool $prepend Whether to prepend the autoloader or not 384 | * 385 | * @return void 386 | */ 387 | public function register($prepend = false) 388 | { 389 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 390 | 391 | if (null === $this->vendorDir) { 392 | return; 393 | } 394 | 395 | if ($prepend) { 396 | self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; 397 | } else { 398 | unset(self::$registeredLoaders[$this->vendorDir]); 399 | self::$registeredLoaders[$this->vendorDir] = $this; 400 | } 401 | } 402 | 403 | /** 404 | * Unregisters this instance as an autoloader. 405 | * 406 | * @return void 407 | */ 408 | public function unregister() 409 | { 410 | spl_autoload_unregister(array($this, 'loadClass')); 411 | 412 | if (null !== $this->vendorDir) { 413 | unset(self::$registeredLoaders[$this->vendorDir]); 414 | } 415 | } 416 | 417 | /** 418 | * Loads the given class or interface. 419 | * 420 | * @param string $class The name of the class 421 | * @return true|null True if loaded, null otherwise 422 | */ 423 | public function loadClass($class) 424 | { 425 | if ($file = $this->findFile($class)) { 426 | $includeFile = self::$includeFile; 427 | $includeFile($file); 428 | 429 | return true; 430 | } 431 | 432 | return null; 433 | } 434 | 435 | /** 436 | * Finds the path to the file where the class is defined. 437 | * 438 | * @param string $class The name of the class 439 | * 440 | * @return string|false The path if found, false otherwise 441 | */ 442 | public function findFile($class) 443 | { 444 | // class map lookup 445 | if (isset($this->classMap[$class])) { 446 | return $this->classMap[$class]; 447 | } 448 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 449 | return false; 450 | } 451 | if (null !== $this->apcuPrefix) { 452 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); 453 | if ($hit) { 454 | return $file; 455 | } 456 | } 457 | 458 | $file = $this->findFileWithExtension($class, '.php'); 459 | 460 | // Search for Hack files if we are running on HHVM 461 | if (false === $file && defined('HHVM_VERSION')) { 462 | $file = $this->findFileWithExtension($class, '.hh'); 463 | } 464 | 465 | if (null !== $this->apcuPrefix) { 466 | apcu_add($this->apcuPrefix.$class, $file); 467 | } 468 | 469 | if (false === $file) { 470 | // Remember that this class does not exist. 471 | $this->missingClasses[$class] = true; 472 | } 473 | 474 | return $file; 475 | } 476 | 477 | /** 478 | * Returns the currently registered loaders keyed by their corresponding vendor directories. 479 | * 480 | * @return array 481 | */ 482 | public static function getRegisteredLoaders() 483 | { 484 | return self::$registeredLoaders; 485 | } 486 | 487 | /** 488 | * @param string $class 489 | * @param string $ext 490 | * @return string|false 491 | */ 492 | private function findFileWithExtension($class, $ext) 493 | { 494 | // PSR-4 lookup 495 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; 496 | 497 | $first = $class[0]; 498 | if (isset($this->prefixLengthsPsr4[$first])) { 499 | $subPath = $class; 500 | while (false !== $lastPos = strrpos($subPath, '\\')) { 501 | $subPath = substr($subPath, 0, $lastPos); 502 | $search = $subPath . '\\'; 503 | if (isset($this->prefixDirsPsr4[$search])) { 504 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); 505 | foreach ($this->prefixDirsPsr4[$search] as $dir) { 506 | if (file_exists($file = $dir . $pathEnd)) { 507 | return $file; 508 | } 509 | } 510 | } 511 | } 512 | } 513 | 514 | // PSR-4 fallback dirs 515 | foreach ($this->fallbackDirsPsr4 as $dir) { 516 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 517 | return $file; 518 | } 519 | } 520 | 521 | // PSR-0 lookup 522 | if (false !== $pos = strrpos($class, '\\')) { 523 | // namespaced class name 524 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 525 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 526 | } else { 527 | // PEAR-like class name 528 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; 529 | } 530 | 531 | if (isset($this->prefixesPsr0[$first])) { 532 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 533 | if (0 === strpos($class, $prefix)) { 534 | foreach ($dirs as $dir) { 535 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 536 | return $file; 537 | } 538 | } 539 | } 540 | } 541 | } 542 | 543 | // PSR-0 fallback dirs 544 | foreach ($this->fallbackDirsPsr0 as $dir) { 545 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 546 | return $file; 547 | } 548 | } 549 | 550 | // PSR-0 include paths. 551 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 552 | return $file; 553 | } 554 | 555 | return false; 556 | } 557 | 558 | /** 559 | * @return void 560 | */ 561 | private static function initializeIncludeClosure() 562 | { 563 | if (self::$includeFile !== null) { 564 | return; 565 | } 566 | 567 | /** 568 | * Scope isolated include. 569 | * 570 | * Prevents access to $this/self from included files. 571 | * 572 | * @param string $file 573 | * @return void 574 | */ 575 | self::$includeFile = \Closure::bind(static function($file) { 576 | include $file; 577 | }, null, null); 578 | } 579 | } 580 | -------------------------------------------------------------------------------- /vendor/composer/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) Nils Adermann, Jordi Boggiano 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished 9 | to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /vendor/composer/autoload_classmap.php: -------------------------------------------------------------------------------- 1 | $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php', 10 | 'AWS\\CRT\\Auth\\CredentialsProvider' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php', 11 | 'AWS\\CRT\\Auth\\Signable' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php', 12 | 'AWS\\CRT\\Auth\\SignatureType' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php', 13 | 'AWS\\CRT\\Auth\\SignedBodyHeaderType' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SignedBodyHeaderType.php', 14 | 'AWS\\CRT\\Auth\\Signing' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/Signing.php', 15 | 'AWS\\CRT\\Auth\\SigningAlgorithm' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php', 16 | 'AWS\\CRT\\Auth\\SigningConfigAWS' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningConfigAWS.php', 17 | 'AWS\\CRT\\Auth\\SigningResult' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php', 18 | 'AWS\\CRT\\Auth\\StaticCredentialsProvider' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php', 19 | 'AWS\\CRT\\CRT' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/CRT.php', 20 | 'AWS\\CRT\\HTTP\\Headers' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php', 21 | 'AWS\\CRT\\HTTP\\Message' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php', 22 | 'AWS\\CRT\\HTTP\\Request' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php', 23 | 'AWS\\CRT\\HTTP\\Response' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php', 24 | 'AWS\\CRT\\IO\\EventLoopGroup' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php', 25 | 'AWS\\CRT\\IO\\InputStream' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php', 26 | 'AWS\\CRT\\Internal\\Encoding' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php', 27 | 'AWS\\CRT\\Internal\\Extension' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Internal/Extension.php', 28 | 'AWS\\CRT\\Log' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Log.php', 29 | 'AWS\\CRT\\NativeResource' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/NativeResource.php', 30 | 'AWS\\CRT\\OptionValue' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Options.php', 31 | 'AWS\\CRT\\Options' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Options.php', 32 | 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 33 | ); 34 | -------------------------------------------------------------------------------- /vendor/composer/autoload_namespaces.php: -------------------------------------------------------------------------------- 1 | array($vendorDir . '/symfony/polyfill-mbstring'), 10 | 'SevenSpan\\Chat\\Tests\\' => array($baseDir . '/tests'), 11 | 'SevenSpan\\Chat\\' => array($baseDir . '/src'), 12 | 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), 13 | 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), 14 | 'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), 15 | 'League\\Flysystem\\Local\\' => array($vendorDir . '/league/flysystem-local'), 16 | 'League\\Flysystem\\AwsS3V3\\' => array($vendorDir . '/league/flysystem-aws-s3-v3'), 17 | 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), 18 | 'JmesPath\\' => array($vendorDir . '/mtdowling/jmespath.php/src'), 19 | 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), 20 | 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), 21 | 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), 22 | 'Aws\\' => array($vendorDir . '/aws/aws-sdk-php/src'), 23 | ); 24 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | register(true); 35 | 36 | $filesToLoad = \Composer\Autoload\ComposerStaticInit5e31203c50732deea847731f5bc1193e::$files; 37 | $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { 38 | if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 39 | $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 40 | 41 | require $file; 42 | } 43 | }, null, null); 44 | foreach ($filesToLoad as $fileIdentifier => $file) { 45 | $requireFile($fileIdentifier, $file); 46 | } 47 | 48 | return $loader; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', 11 | '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', 12 | '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', 13 | '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', 14 | 'b067bc7112e384b61c701452d53a14a8' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/JmesPath.php', 15 | '8a9dc1de0ca7e01f3e08231539562f61' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/functions.php', 16 | ); 17 | 18 | public static $prefixLengthsPsr4 = array ( 19 | 'S' => 20 | array ( 21 | 'Symfony\\Polyfill\\Mbstring\\' => 26, 22 | 'SevenSpan\\Chat\\Tests\\' => 21, 23 | 'SevenSpan\\Chat\\' => 15, 24 | ), 25 | 'P' => 26 | array ( 27 | 'Psr\\Http\\Message\\' => 17, 28 | 'Psr\\Http\\Client\\' => 16, 29 | ), 30 | 'L' => 31 | array ( 32 | 'League\\MimeTypeDetection\\' => 25, 33 | 'League\\Flysystem\\Local\\' => 23, 34 | 'League\\Flysystem\\AwsS3V3\\' => 25, 35 | 'League\\Flysystem\\' => 17, 36 | ), 37 | 'J' => 38 | array ( 39 | 'JmesPath\\' => 9, 40 | ), 41 | 'G' => 42 | array ( 43 | 'GuzzleHttp\\Psr7\\' => 16, 44 | 'GuzzleHttp\\Promise\\' => 19, 45 | 'GuzzleHttp\\' => 11, 46 | ), 47 | 'A' => 48 | array ( 49 | 'Aws\\' => 4, 50 | ), 51 | ); 52 | 53 | public static $prefixDirsPsr4 = array ( 54 | 'Symfony\\Polyfill\\Mbstring\\' => 55 | array ( 56 | 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', 57 | ), 58 | 'SevenSpan\\Chat\\Tests\\' => 59 | array ( 60 | 0 => __DIR__ . '/../..' . '/tests', 61 | ), 62 | 'SevenSpan\\Chat\\' => 63 | array ( 64 | 0 => __DIR__ . '/../..' . '/src', 65 | ), 66 | 'Psr\\Http\\Message\\' => 67 | array ( 68 | 0 => __DIR__ . '/..' . '/psr/http-factory/src', 69 | 1 => __DIR__ . '/..' . '/psr/http-message/src', 70 | ), 71 | 'Psr\\Http\\Client\\' => 72 | array ( 73 | 0 => __DIR__ . '/..' . '/psr/http-client/src', 74 | ), 75 | 'League\\MimeTypeDetection\\' => 76 | array ( 77 | 0 => __DIR__ . '/..' . '/league/mime-type-detection/src', 78 | ), 79 | 'League\\Flysystem\\Local\\' => 80 | array ( 81 | 0 => __DIR__ . '/..' . '/league/flysystem-local', 82 | ), 83 | 'League\\Flysystem\\AwsS3V3\\' => 84 | array ( 85 | 0 => __DIR__ . '/..' . '/league/flysystem-aws-s3-v3', 86 | ), 87 | 'League\\Flysystem\\' => 88 | array ( 89 | 0 => __DIR__ . '/..' . '/league/flysystem/src', 90 | ), 91 | 'JmesPath\\' => 92 | array ( 93 | 0 => __DIR__ . '/..' . '/mtdowling/jmespath.php/src', 94 | ), 95 | 'GuzzleHttp\\Psr7\\' => 96 | array ( 97 | 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', 98 | ), 99 | 'GuzzleHttp\\Promise\\' => 100 | array ( 101 | 0 => __DIR__ . '/..' . '/guzzlehttp/promises/src', 102 | ), 103 | 'GuzzleHttp\\' => 104 | array ( 105 | 0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src', 106 | ), 107 | 'Aws\\' => 108 | array ( 109 | 0 => __DIR__ . '/..' . '/aws/aws-sdk-php/src', 110 | ), 111 | ); 112 | 113 | public static $classMap = array ( 114 | 'AWS\\CRT\\Auth\\AwsCredentials' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php', 115 | 'AWS\\CRT\\Auth\\CredentialsProvider' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php', 116 | 'AWS\\CRT\\Auth\\Signable' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php', 117 | 'AWS\\CRT\\Auth\\SignatureType' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php', 118 | 'AWS\\CRT\\Auth\\SignedBodyHeaderType' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SignedBodyHeaderType.php', 119 | 'AWS\\CRT\\Auth\\Signing' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/Signing.php', 120 | 'AWS\\CRT\\Auth\\SigningAlgorithm' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php', 121 | 'AWS\\CRT\\Auth\\SigningConfigAWS' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningConfigAWS.php', 122 | 'AWS\\CRT\\Auth\\SigningResult' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php', 123 | 'AWS\\CRT\\Auth\\StaticCredentialsProvider' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php', 124 | 'AWS\\CRT\\CRT' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/CRT.php', 125 | 'AWS\\CRT\\HTTP\\Headers' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php', 126 | 'AWS\\CRT\\HTTP\\Message' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php', 127 | 'AWS\\CRT\\HTTP\\Request' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php', 128 | 'AWS\\CRT\\HTTP\\Response' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php', 129 | 'AWS\\CRT\\IO\\EventLoopGroup' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php', 130 | 'AWS\\CRT\\IO\\InputStream' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php', 131 | 'AWS\\CRT\\Internal\\Encoding' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php', 132 | 'AWS\\CRT\\Internal\\Extension' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Internal/Extension.php', 133 | 'AWS\\CRT\\Log' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Log.php', 134 | 'AWS\\CRT\\NativeResource' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/NativeResource.php', 135 | 'AWS\\CRT\\OptionValue' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Options.php', 136 | 'AWS\\CRT\\Options' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Options.php', 137 | 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 138 | ); 139 | 140 | public static function getInitializer(ClassLoader $loader) 141 | { 142 | return \Closure::bind(function () use ($loader) { 143 | $loader->prefixLengthsPsr4 = ComposerStaticInit5e31203c50732deea847731f5bc1193e::$prefixLengthsPsr4; 144 | $loader->prefixDirsPsr4 = ComposerStaticInit5e31203c50732deea847731f5bc1193e::$prefixDirsPsr4; 145 | $loader->classMap = ComposerStaticInit5e31203c50732deea847731f5bc1193e::$classMap; 146 | 147 | }, null, ClassLoader::class); 148 | } 149 | } 150 | --------------------------------------------------------------------------------