├── .coveralls.yml
├── .gitignore
├── .scrutinizer.yml
├── .sensiolabs.yml
├── .styleci.yml
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── nitpick.json
├── phpcs.xml
├── phpmd.xml
├── phpunit.xml
├── src
├── Cache
│ ├── CouchbaseLock.php
│ ├── CouchbaseStore.php
│ └── MemcachedBucketStore.php
├── Console
│ ├── DesignCreatorCommand.php
│ ├── IndexCreatorCommand.php
│ ├── IndexFinderCommand.php
│ ├── IndexRemoverCommand.php
│ ├── PrimaryIndexCreatorCommand.php
│ ├── PrimaryIndexRemoverCommand.php
│ └── QueueCreatorCommand.php
├── ConsoleServiceProvider.php
├── CouchbaseServiceProvider.php
├── Database
│ ├── Connectable.php
│ ├── CouchbaseConnection.php
│ └── CouchbaseConnector.php
├── Design
│ └── AbstractDocument.php
├── Events
│ ├── QueryPrepared.php
│ ├── ResultReturning.php
│ └── ViewQuerying.php
├── Exceptions
│ ├── FlushException.php
│ └── NotSupportedException.php
├── MemcachedConnector.php
├── Migrations
│ └── CouchbaseMigrationRepository.php
├── Query
│ ├── Builder.php
│ ├── Grammar.php
│ ├── Processor.php
│ └── View.php
├── Queue
│ ├── CouchbaseConnector.php
│ └── CouchbaseQueue.php
├── Schema
│ ├── Blueprint.php
│ ├── Builder.php
│ └── NotSupportedTrait.php
├── config
│ └── couchbase.php
├── resources
│ └── sample.ddoc
└── transfer.php
└── tests
├── Console
├── DesignCreatorCommandTest.php
├── IndexCreatorCommandTest.php
├── IndexFinderCommandTest.php
├── IndexRemoverCommandTest.php
├── PrimaryIndexCreatorCommandTest.php
└── PrimaryIndexRemoverCommandTest.php
├── CouchbaseConnectorTest.php
├── CouchbaseGrammerTest.php
├── CouchbaseReconnectionTest.php
├── CouchbaseStoreSerializeTest.php
├── CouchbaseStoreTest.php
├── CouchbaseTestCase.php
├── DatabaseTest.php
├── DeleteQueryTest.php
├── DesignDocumentTest.php
├── MemcachedBucketTest.php
├── MemcachedConnectorTest.php
├── MockApplication.php
├── ProviderTest.php
├── Query
└── ViewTest.php
├── Queue
└── QueueCouchbaseConnectorTest.php
├── Schema
├── BlueprintTest.php
└── BuilderTest.php
├── TaggingCacheStoreTest.php
├── UpdateQueryTest.php
├── bin
└── memcached.sh
├── config
├── app.php
├── cache.php
├── couchbase.php
├── database.php
├── queue.php
└── session.php
├── logs
└── .gitignore
└── resources
└── sample.ddoc
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service_name: travis-ci
2 | coverage_clover: tests/build/clover.xml
3 | json_path: tests/build/coveralls-upload.json
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | composer.lock
3 | composer.phar
4 | ocular.phar
5 | coverage.clover
6 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | filter:
2 | paths:
3 | - src/*
4 | excluded_paths:
5 | - tests/*
6 | tools:
7 | php_code_sniffer: true
8 | php_cpd: true
9 | php_loc: true
10 | php_mess_detector: true
11 | php_pdepend: true
12 | php_analyzer: true
13 | sensiolabs_security_checker: true
14 | php_code_sniffer:
15 | config:
16 | standard: "PSR2"
17 | php_cs_fixer:
18 | config: { level: psr2 }
19 | external_code_coverage:
20 | timeout: 600 # Timeout in seconds.
21 | runs: 2
22 | checks:
23 | php:
24 | code_rating: true
25 | duplication: true
26 |
--------------------------------------------------------------------------------
/.sensiolabs.yml:
--------------------------------------------------------------------------------
1 | global_exclude_dirs:
2 | - vendor
3 | - tests
4 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: psr2
2 |
3 | finder:
4 | exclude:
5 | - tests
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | language: php
3 | dist: trusty
4 |
5 | php:
6 | - 7.1
7 |
8 | before_script:
9 | - chmod -R 755 tests/bin/memcached.sh
10 | - tests/bin/memcached.sh
11 | - wget http://packages.couchbase.com/releases/couchbase-release/couchbase-release-1.0-4-amd64.deb
12 | - sudo dpkg -i couchbase-release-1.0-4-amd64.deb
13 | - sudo apt-get update
14 | - sudo apt-get install python libcouchbase-dev libcouchbase2-bin build-essential libssl-dev python-dev python-pip python-httplib2
15 | - wget https://packages.couchbase.com/releases/5.0.1/couchbase-server-community_5.0.1-ubuntu14.04_amd64.deb
16 | - sudo dpkg -i couchbase-server-community_5.0.1-ubuntu14.04_amd64.deb
17 | # Will install or upgrade packages
18 | - sudo apt-get update
19 | - sudo apt-get install debian-archive-keyring
20 | - sudo apt-get update
21 | #- sudo apt-get upgrade
22 | #- sudo apt-get install libcouchbase-dev libcouchbase2-bin build-essential libssl-dev
23 | - pecl install pcs-beta
24 | - pecl install igbinary
25 | - pecl install couchbase
26 | - cd $home/opt/couchbase
27 | - ./bin/couchbase-server -- -noinput -detached
28 | - sleep 20
29 | - ./bin/couchbase-cli cluster-init -c 127.0.0.1:8091 --cluster-username=Administrator --cluster-password=Administrator --cluster-port=8091 --cluster-index-ramsize=512 --cluster-ramsize=512
30 | #--services=data,query,index
31 | - ./bin/couchbase-cli rebalance -c 127.0.0.1:8091 -u Administrator -p Administrator
32 | - curl -u Administrator:Administrator -v -X POST 'http://127.0.0.1:8091/pools/default/buckets' -d name=testing -d ramQuotaMB=128 -d bucketType=couchbase -d flushEnabled=1 -d evictionPolicy=fullEviction -d authType=none -d saslPassword=none
33 | - sleep 10
34 | - curl -u Administrator:Administrator -v -X POST 'http://127.0.0.1:8091/pools/default/buckets' -d name=index_testing -d ramQuotaMB=128 -d bucketType=couchbase -d flushEnabled=1 -d evictionPolicy=fullEviction -d authType=none -d saslPassword=none
35 | - sleep 10
36 | - curl -u Administrator:Administrator -v -X POST 'http://127.0.0.1:8091/pools/default/buckets' -d name=memcache-couch -d ramQuotaMB=128 -d bucketType=memcached -d flushEnabled=1 -d evictionPolicy=fullEviction -d authType=none -d proxyPort=11255 -d saslPassword=none
37 | - sleep 10
38 | - ./bin/couchbase-cli user-manage -c localhost -u Administrator -p Administrator --set --rbac-username Administrator --rbac-password Administrator --rbac-name "Administrator" --roles bucket_full_access[*],ro_admin --auth-domain local
39 | - ./bin/cbq -e http://127.0.0.1:8091 --script "CREATE PRIMARY INDEX ON \`testing\`" -u=Administrator -p=Administrator
40 | - cd $TRAVIS_BUILD_DIR
41 | - composer self-update
42 | - composer install --prefer-source
43 | script:
44 | - chmod -R 777 tests/logs
45 | - ./vendor/bin/phpunit
46 | - chmod 777 tests/logs/clover.xml
47 | after_success:
48 | - if [[ ${TRAVIS_PHP_VERSION:0:3} == "7.1" ]]; then travis_retry php vendor/bin/coveralls; fi
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2018 Yuuki Takezawa
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-Couchbase
2 | for Laravel 5.1.*(higher)
3 |
4 | cache, session, database, queue extension package
5 | *required ext-couchbase*
6 |
7 | [](https://travis-ci.org/ytake/Laravel-Couchbase)
8 | [](https://scrutinizer-ci.com/g/ytake/Laravel-Couchbase/?branch=master)
9 | [](https://scrutinizer-ci.com/g/ytake/Laravel-Couchbase/?branch=masnter)
10 | [](https://styleci.io/repos/45177780)
11 |
12 | [](https://packagist.org/packages/ytake/laravel-couchbase)
13 | [](https://packagist.org/packages/ytake/laravel-couchbase)
14 | [](https://packagist.org/packages/ytake/laravel-couchbase)
15 | [](https://www.codacy.com/app/yuuki-takezawa/Laravel-Couchbase?utm_source=github.com&utm_medium=referral&utm_content=ytake/Laravel-Couchbase&utm_campaign=Badge_Grade)
16 |
17 | [](https://insight.sensiolabs.com/projects/944f9bc0-7ee6-4f5f-b371-8ec216ea317e)
18 |
19 | ## Notice
20 | Supported Auto-Discovery, Design Document, Cache Lock (Laravel5.5)
21 |
22 | | Laravel version | Laravel-Couchbase version | ext-couchbase |
23 | | ------------- | ------------- | ------------------|
24 | | Laravel 5.6 | ^1.1 | >=2.3.2 |
25 | | Laravel 5.5 | ^1.0 | >=2.3.2 |
26 | | Laravel 5.4 | ^0.7 | ^2.2.2 |
27 | | Laravel 5.3 | ^0.6 | ^2.2.2 |
28 | | Laravel 5.2 | ^0.5 | ^2.2.2 |
29 | | Laravel 5.1 | ^0.4 | ^2.2.2 |
30 |
31 | ### Deprecated
32 |
33 | *not recommended* couchbase-memcached driver `couchbase session driver`
34 |
35 | ## install
36 |
37 | ```bash
38 | $ composer require ytake/laravel-couchbase
39 | ```
40 |
41 | or your config/app.php
42 |
43 | ```php
44 | 'providers' => [
45 | // added service provider
46 | \Ytake\LaravelCouchbase\CouchbaseServiceProvider::class,
47 | \Ytake\LaravelCouchbase\ConsoleServiceProvider::class,
48 | ]
49 | ```
50 |
51 | ## usage
52 | ### database extension
53 |
54 | add database driver(config/database.php)
55 |
56 | ```php
57 |
58 | 'couchbase' => [
59 | 'driver' => 'couchbase',
60 | 'host' => 'couchbase://127.0.0.1',
61 | 'user' => 'userName', // optional administrator
62 | 'password' => 'password', // optional administrator
63 | // optional configuration / management operations against a bucket.
64 | 'administrator' => [
65 | 'user' => 'Administrator',
66 | 'password' => 'password',
67 | ],
68 | ],
69 | ```
70 |
71 | case cluster
72 |
73 | ```php
74 |
75 | 'couchbase' => [
76 | 'driver' => 'couchbase',
77 | 'host' => 'couchbase://127.0.0.1,192.168.1.2',
78 | 'user' => 'userName', // optional administrator
79 | 'password' => 'password', // optional administrator
80 | ],
81 | ```
82 |
83 | choose bucket `table()` method
84 | or
85 |
86 | basic usage `bucket()` method
87 |
88 | N1QL supported(upsert enabled)
89 |
90 | see http://developer.couchbase.com/documentation/server/4.1/n1ql/n1ql-language-reference/index.html
91 |
92 | #### SELECT
93 |
94 | ```php
95 | // service container access
96 | $this->app['db']->connection('couchbase')
97 | ->table('testing')->where('whereKey', 'value')->first();
98 |
99 | // use DB facades
100 | \DB::connection('couchbase')
101 | ->table('testing')->where('whereKey', 'value')->get();
102 | ```
103 |
104 | #### INSERT / UPSERT
105 |
106 | ```php
107 | $value = [
108 | 'click' => 'to edit',
109 | 'content' => 'testing'
110 | ];
111 | $key = 'insert:and:delete';
112 |
113 | $result = \DB::connection('couchbase')
114 | ->table('testing')->key($key)->insert($value);
115 |
116 | \DB::connection('couchbase')
117 | ->table('testing')->key($key)->upsert([
118 | 'click' => 'to edit',
119 | 'content' => 'testing for upsert',
120 | ]);
121 | ```
122 |
123 | #### DELETE / UPDATE
124 |
125 | ```php
126 | \DB::connection('couchbase')
127 | ->table('testing')->key($key)->where('clicking', 'to edit')->delete();
128 |
129 | \DB::connection('couchbase')
130 | ->table('testing')->key($key)
131 | ->where('click', 'to edit')->update(
132 | ['click' => 'testing edit']
133 | );
134 | ```
135 |
136 | ##### execute queries
137 | example)
138 |
139 | ````php
140 | "delete from testing USE KEYS "delete" RETURNING *"
141 | "update testing USE KEYS "insert" set click = ? where click = ? RETURNING *"
142 | ````
143 |
144 | #### returning
145 |
146 | default *
147 |
148 | ```php
149 | \DB::connection('couchbase')
150 | ->table('testing')
151 | ->where('id', 1)
152 | ->offset($from)->limit($perPage)
153 | ->orderBy('created_at', $sort)
154 | ->returning(['id', 'name'])->get();
155 | ```
156 |
157 | #### View Query
158 |
159 | ```php
160 | $view = \DB::view("testing");
161 | $result = $view->execute($view->from("dev_testing", "testing"));
162 | ```
163 |
164 | ### cache extension
165 | #### for bucket type couchbase
166 |
167 | *config/cache.php*
168 |
169 | ```php
170 | 'couchbase' => [
171 | 'driver' => 'couchbase',
172 | 'bucket' => 'session'
173 | ],
174 | ```
175 |
176 | #### for bucket type memcached
177 |
178 | ```php
179 | 'couchbase-memcached' => [
180 | 'driver' => 'couchbase-memcached',
181 | 'servers' => [
182 | [
183 | 'host' => '127.0.0.1',
184 | 'port' => 11255,
185 | 'weight' => 100,
186 | 'bucket' => 'memcached-bucket-name',
187 | 'option' => [
188 | // curl option
189 | ],
190 | ],
191 | ],
192 | ],
193 | ```
194 |
195 | *not supported*
196 |
197 | ### couchbase bucket, use bucket password
198 |
199 | *config/cache.php*
200 |
201 | ```php
202 | 'couchbase' => [
203 | 'driver' => 'couchbase',
204 | 'bucket' => 'session',
205 | 'bucket_password' => 'your bucket password'
206 | ],
207 |
208 | ```
209 |
210 | ### session extension
211 |
212 | .env etc..
213 |
214 | specify couchbase driver
215 |
216 | ### consistency
217 | default :CouchbaseN1qlQuery::NOT_BOUNDED
218 |
219 | ```php
220 | $this->app['db']->connection('couchbase')
221 | ->consistency(\CouchbaseN1qlQuery::REQUEST_PLUS)
222 | ->table('testing')
223 | ->where('id', 1)
224 | ->returning(['id', 'name'])->get();
225 | ```
226 |
227 | #### callable consistency
228 |
229 | ```php
230 | $this->app['db']->connection('couchbase')
231 | ->callableConsistency(\CouchbaseN1qlQuery::REQUEST_PLUS, function ($con) {
232 | return $con->table('testing')->where('id', 1)->returning(['id', 'name'])->get();
233 | });
234 | ```
235 |
236 | ### Event
237 | for N1QL
238 |
239 | | events | description |
240 | | ------------- | ------------- |
241 | | \Ytake\LaravelCouchbase\Events\QueryPrepared | get n1ql query |
242 | | \Ytake\LaravelCouchbase\Events\ResultReturning | get all property from returned result |
243 | | \Ytake\LaravelCouchbase\Events\ViewQuerying | for view query (request uri) |
244 |
245 | ### Schema / Migrations
246 | The database driver also has (limited) schema builder support.
247 | easily manipulate indexes(primary and secondary)
248 |
249 | ```php
250 | use Ytake\LaravelCouchbase\Schema\Blueprint as CouchbaseBlueprint;
251 |
252 | \Schema::create('samples', function (CouchbaseBlueprint $table) {
253 | $table->primaryIndex(); // primary index
254 | $table->index(['message', 'identifier'], 'sample_secondary_index'); // secondary index
255 | // dropped
256 | $table->dropIndex('sample_secondary_index');
257 | $table->dropPrimary();
258 | });
259 | ```
260 |
261 | Supported operations:
262 |
263 | - create and drop
264 | - index and dropIndex (primary index and secondary index)
265 |
266 | ### Artisan
267 | for couchbase manipulate indexes
268 |
269 | | commands | description |
270 | | ------------- | ------------- |
271 | | couchbase:create-index | Create a secondary index for the current bucket. |
272 | | couchbase:create-primary-index | Create a primary N1QL index for the current bucket. |
273 | | couchbase:drop-index | Drop the given secondary index associated with the current bucket. |
274 | | couchbase:drop-primary-index | Drop the given primary index associated with the current bucket. |
275 | | couchbase:indexes | List all N1QL indexes that are registered for the current bucket. |
276 | | couchbase:create-queue-index | Create primary index, secondary indexes for the queue jobs couchbase bucket. |
277 | | couchbase:create-design | Inserts design document and fails if it is exist already. for MapReduce views |
278 |
279 | `-h` more information.
280 |
281 | #### create design
282 |
283 | config/couchbase.php
284 |
285 | ```php
286 | return [
287 | 'design' => [
288 | 'Your Design Document Name' => [
289 | 'views' => [
290 | 'Your View Name' => [
291 | 'map' => file_get_contents(__DIR__ . '/../resources/sample.ddoc'),
292 | ],
293 | ],
294 | ],
295 | ]
296 | ];
297 |
298 | ```
299 |
300 | ## Queue
301 |
302 | Change the the driver in config/queue.php:
303 |
304 | ```php
305 | 'connections' => [
306 | 'couchbase' => [
307 | 'driver' => 'couchbase',
308 | 'bucket' => 'jobs',
309 | 'queue' => 'default',
310 | 'retry_after' => 90,
311 | ],
312 | ],
313 | ```
314 |
315 | example
316 |
317 | ```bash
318 | php artisan queue:work couchbase --queue=send_email
319 | ```
320 |
321 | ## hacking
322 |
323 | To run tests there are should be following buckets created on local Couchbase cluster:
324 |
325 | ``` php
326 | $cluster = new CouchbaseCluster('couchbase://127.0.0.1');
327 | $clusterManager = $cluster->manager('Administrator', 'password');
328 | $clusterManager->createBucket('testing', ['bucketType' => 'couchbase', 'saslPassword' => '', 'flushEnabled' => true]);
329 | $clusterManager->createBucket('memcache-couch', ['bucketType' => 'memcached', 'saslPassword' => '', 'flushEnabled' => true]);
330 | sleep(5);
331 | $bucketManager = $cluster->openBucket('testing')->manager();
332 | $bucketManager->createN1qlPrimaryIndex();
333 | ```
334 |
335 | Also tests are expecting regular Memcached daemon listening on port 11255.
336 |
337 | ## soon
338 | - authintication driver
339 | - Eloquent support
340 |
341 | ## Couchbase Document
342 |
343 | [REST API / Creating and Editing Buckets](https://developer.couchbase.com/documentation/server/current/rest-api/rest-bucket-create.html)
344 | [couchbase-cli / user-manage](https://developer.couchbase.com/documentation/server/5.1/cli/cbcli/couchbase-cli-user-manage.html)
345 | [Authentication](https://developer.couchbase.com/documentation/server/5.1/security/security-authentication.html)
346 | [Authorization API](https://developer.couchbase.com/documentation/server/5.1/rest-api/rest-authorization.html)
347 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ytake/laravel-couchbase",
3 | "description": "Couchbase providers for Laravel",
4 | "keywords": [
5 | "laravel",
6 | "couchbase",
7 | "database",
8 | "session",
9 | "cache",
10 | "queue"
11 | ],
12 | "authors": [
13 | {
14 | "name": "Yuuki Takezawa",
15 | "email": "yuuki.takezawa@comnect.jp.net"
16 | }
17 | ],
18 | "license": "MIT",
19 | "require": {
20 | "php": "^7.1.3",
21 | "ext-couchbase": ">=2.3.2",
22 | "illuminate/support": "5.6.*",
23 | "illuminate/config": "5.6.*",
24 | "illuminate/console": "5.6.*",
25 | "illuminate/events": "5.6.*",
26 | "illuminate/cache": "5.6.*",
27 | "illuminate/session": "5.6.*",
28 | "illuminate/database": "5.6.*",
29 | "illuminate/encryption": "5.6.*",
30 | "illuminate/queue": "5.6.*",
31 | "illuminate/contracts": "5.6.*",
32 | "illuminate/container": "5.6.*"
33 | },
34 | "require-dev": {
35 | "symfony/framework-bundle": "^4.0",
36 | "symfony/console": "^4.0",
37 | "phpunit/phpunit": "^6.0",
38 | "satooshi/php-coveralls": "*",
39 | "phploc/phploc": "*",
40 | "pdepend/pdepend" : "^2.2.4",
41 | "phpmd/phpmd": "@stable",
42 | "friendsofphp/php-cs-fixer": "^2.0"
43 | },
44 | "autoload": {
45 | "psr-4": {
46 | "Ytake\\LaravelCouchbase\\": "src"
47 | },
48 | "files": [
49 | "src/transfer.php"
50 | ]
51 | },
52 | "autoload-dev": {
53 | "classmap": [
54 | "tests/CouchbaseTestCase.php",
55 | "tests/MockApplication.php"
56 | ]
57 | },
58 | "scripts": {
59 | "test": [
60 | "php vendor/bin/phpunit"
61 | ],
62 | "cs": [
63 | "php vendor/bin/php-cs-fixer fix"
64 | ],
65 | "scrutinizer_test": [
66 | "php vendor/bin/phpunit --coverage-clover=coverage.clover",
67 | "wget https://scrutinizer-ci.com/ocular.phar",
68 | "php ocular.phar code-coverage:upload --format=php-clover coverage.clover"
69 | ]
70 | },
71 | "minimum-stability": "stable",
72 | "extra": {
73 | "laravel": {
74 | "providers": [
75 | "Ytake\\LaravelCouchbase\\CouchbaseServiceProvider",
76 | "Ytake\\LaravelCouchbase\\ConsoleServiceProvider"
77 | ]
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/nitpick.json:
--------------------------------------------------------------------------------
1 | {
2 | "ignore": [
3 | "tests/*"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/phpmd.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
19 |
20 | ./src
21 |
22 | ./src/CouchbaseServiceProvider.php
23 | ./src/ConsoleServiceProvider.php
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/Cache/CouchbaseLock.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | class CouchbaseLock extends Lock implements Lockable
28 | {
29 | /** @var Bucket */
30 | protected $bucket;
31 |
32 | /**
33 | * CouchbaseLock constructor.
34 | *
35 | * @param Bucket $bucket
36 | * @param string $name
37 | * @param int $seconds
38 | */
39 | public function __construct(Bucket $bucket, string $name, int $seconds)
40 | {
41 | parent::__construct($name, $seconds);
42 |
43 | $this->bucket = $bucket;
44 | }
45 |
46 | /**
47 | * @return bool
48 | */
49 | public function acquire()
50 | {
51 | try {
52 | $result = $this->bucket->insert($this->name, 1, ['expiry' => $this->seconds]);
53 | if ($result instanceof Document) {
54 | return true;
55 | }
56 | } catch (CouchbaseException $e) {
57 | return false;
58 | }
59 |
60 | return false;
61 | }
62 |
63 | /**
64 | * {@inheritdoc}
65 | */
66 | public function release()
67 | {
68 | $this->bucket->remove($this->name);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Cache/CouchbaseStore.php:
--------------------------------------------------------------------------------
1 |
29 | */
30 | class CouchbaseStore extends TaggableStore implements Store
31 | {
32 | use RetrievesMultipleKeys;
33 |
34 | /** @var string */
35 | protected $prefix;
36 |
37 | /** @var Bucket */
38 | protected $bucket;
39 |
40 | /** @var Cluster */
41 | protected $cluster;
42 |
43 | /**
44 | * CouchbaseStore constructor.
45 | *
46 | * @param Cluster $cluster
47 | * @param string $bucket
48 | * @param string $password
49 | * @param string|null $prefix
50 | * @param string $serialize
51 | */
52 | public function __construct(
53 | Cluster $cluster,
54 | string $bucket,
55 | string $password = '',
56 | string $prefix = null,
57 | string $serialize = 'php'
58 | ) {
59 | $this->cluster = $cluster;
60 | $this->setBucket($bucket, $password, $serialize);
61 | $this->setPrefix($prefix);
62 | }
63 |
64 | /**
65 | * {@inheritdoc}
66 | */
67 | public function get($key)
68 | {
69 | try {
70 | $result = $this->bucket->get($this->resolveKey($key));
71 |
72 | return $this->getMetaDoc($result);
73 | } catch (CouchbaseException $e) {
74 | return;
75 | }
76 | }
77 |
78 | /**
79 | * Store an item in the cache if the key doesn't exist.
80 | *
81 | * @param string|array $key
82 | * @param mixed $value
83 | * @param int $minutes
84 | *
85 | * @return bool
86 | */
87 | public function add($key, $value, $minutes = 0): bool
88 | {
89 | $options = ($minutes === 0) ? [] : ['expiry' => ($minutes * 60)];
90 | try {
91 | $this->bucket->insert($this->resolveKey($key), $value, $options);
92 |
93 | return true;
94 | } catch (CouchbaseException $e) {
95 | return false;
96 | }
97 | }
98 |
99 | /**
100 | * {@inheritdoc}
101 | */
102 | public function put($key, $value, $minutes)
103 | {
104 | $this->bucket->upsert($this->resolveKey($key), $value, ['expiry' => $minutes * 60]);
105 | }
106 |
107 | /**
108 | * {@inheritdoc}
109 | */
110 | public function increment($key, $value = 1)
111 | {
112 | return $this->bucket
113 | ->counter($this->resolveKey($key), $value, ['initial' => abs($value)])->value;
114 | }
115 |
116 | /**
117 | * {@inheritdoc}
118 | */
119 | public function decrement($key, $value = 1)
120 | {
121 | return $this->bucket
122 | ->counter($this->resolveKey($key), (0 - abs($value)), ['initial' => (0 - abs($value))])->value;
123 | }
124 |
125 | /**
126 | * {@inheritdoc}
127 | */
128 | public function forever($key, $value)
129 | {
130 | try {
131 | $this->bucket->insert($this->resolveKey($key), $value);
132 | } catch (CouchbaseException $e) {
133 | // bucket->insert when called from resetTag in TagSet can throw CAS exceptions, ignore.\
134 | $this->bucket->upsert($this->resolveKey($key), $value);
135 | }
136 | }
137 |
138 | /**
139 | * {@inheritdoc}
140 | */
141 | public function forget($key)
142 | {
143 | try {
144 | $this->bucket->remove($this->resolveKey($key));
145 | } catch (\Exception $e) {
146 | // Ignore exceptions from remove
147 | }
148 | }
149 |
150 | /**
151 | * flush bucket.
152 | *
153 | * @throws FlushException
154 | * @codeCoverageIgnore
155 | */
156 | public function flush()
157 | {
158 | $result = $this->bucket->manager()->flush();
159 | if (isset($result['_'])) {
160 | throw new FlushException($result);
161 | }
162 | }
163 |
164 | /**
165 | * {@inheritdoc}
166 | */
167 | public function getPrefix()
168 | {
169 | return $this->prefix;
170 | }
171 |
172 | /**
173 | * Set the cache key prefix.
174 | *
175 | * @param string $prefix
176 | */
177 | public function setPrefix(string $prefix)
178 | {
179 | $this->prefix = !empty($prefix) ? $prefix . ':' : '';
180 | }
181 |
182 | /**
183 | * @param string $bucket
184 | * @param string $password
185 | * @param string $serialize
186 | *
187 | * @return CouchbaseStore
188 | */
189 | public function setBucket(string $bucket, string $password = '', string $serialize = 'php'): CouchbaseStore
190 | {
191 | $this->bucket = $this->cluster->openBucket($bucket, $password);
192 | if ($serialize === 'php') {
193 | $this->bucket->setTranscoder('couchbase_php_serialize_encoder', 'couchbase_default_decoder');
194 | }
195 |
196 | return $this;
197 | }
198 |
199 | /**
200 | * @param $keys
201 | *
202 | * @return array|string
203 | */
204 | private function resolveKey($keys)
205 | {
206 | if (is_array($keys)) {
207 | $result = [];
208 | foreach ($keys as $key) {
209 | $result[] = $this->prefix . $key;
210 | }
211 |
212 | return $result;
213 | }
214 |
215 | return $this->prefix . $keys;
216 | }
217 |
218 | /**
219 | * @param $meta
220 | *
221 | * @return array|null
222 | */
223 | protected function getMetaDoc($meta)
224 | {
225 | if ($meta instanceof \Couchbase\Document) {
226 | return $meta->value;
227 | }
228 | if (is_array($meta)) {
229 | $result = [];
230 | foreach ($meta as $row) {
231 | $result[] = $this->getMetaDoc($row);
232 | }
233 |
234 | return $result;
235 | }
236 |
237 | return null;
238 | }
239 |
240 | /**
241 | * Get a lock instance.
242 | *
243 | * @param string $name
244 | * @param int $seconds
245 | * @return \Illuminate\Contracts\Cache\Lock
246 | */
247 | public function lock(string $name, int $seconds = 0): Lock
248 | {
249 | return new CouchbaseLock($this->bucket, $this->prefix.$name, $seconds);
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/src/Cache/MemcachedBucketStore.php:
--------------------------------------------------------------------------------
1 |
22 | * @deprecated
23 | */
24 | class MemcachedBucketStore extends MemcachedStore
25 | {
26 | /** @var string[] */
27 | protected $servers;
28 |
29 | /** @var array */
30 | protected $options = [
31 | CURLOPT_RETURNTRANSFER => false,
32 | CURLOPT_SSL_VERIFYPEER => false,
33 | ];
34 |
35 | /** @var int */
36 | protected $port = 8091;
37 |
38 | /** @var int */
39 | protected $timeout = 1;
40 |
41 | /** @var string */
42 | protected $flushEndpoint = ':%s/pools/default/buckets/%s/controller/doFlush';
43 |
44 | /** @var array */
45 | protected $sasl = [];
46 |
47 | /**
48 | * MemcachedBucketStore constructor.
49 | *
50 | * @param \Memcached $memcached
51 | * @param string $prefix
52 | * @param array $servers
53 | * @param array $sasl
54 | */
55 | public function __construct(
56 | \Memcached $memcached,
57 | string $prefix = '',
58 | array $servers,
59 | array $sasl = []
60 | ) {
61 | parent::__construct($memcached, $prefix);
62 | $this->servers = $servers;
63 | $this->sasl = $sasl;
64 | }
65 |
66 | /**
67 | * Increment the value of an item in the cache.
68 | *
69 | * @param string $key
70 | * @param mixed $value
71 | *
72 | * @return int|bool
73 | */
74 | public function increment($key, $value = 1)
75 | {
76 | if ($integer = $this->get($key)) {
77 | $this->put($key, $integer + $value, 0);
78 |
79 | return $integer + $value;
80 | }
81 |
82 | $this->put($key, $value, 0);
83 |
84 | return $value;
85 | }
86 |
87 | /**
88 | * Decrement the value of an item in the cache.
89 | *
90 | * @param string $key
91 | * @param mixed $value
92 | *
93 | * @return int|bool
94 | */
95 | public function decrement($key, $value = 1)
96 | {
97 | $decrement = 0;
98 | if ($integer = $this->get($key)) {
99 | $decrement = $integer - $value;
100 | if ($decrement <= 0) {
101 | $decrement = 0;
102 | }
103 | $this->put($key, $decrement, 0);
104 |
105 | return $decrement;
106 | }
107 |
108 | $this->put($key, $decrement, 0);
109 |
110 | return $decrement;
111 | }
112 |
113 | /**
114 | * {@inheritdoc}
115 | */
116 | public function flush()
117 | {
118 | $handler = curl_multi_init();
119 | foreach ($this->servers as $server) {
120 | $initialize = curl_init();
121 | $configureOption = (isset($server['options'])) ? $server['options'] : [];
122 |
123 | $options = array_replace($this->options, [
124 | CURLOPT_POST => true,
125 | CURLOPT_URL => $server['host'] . sprintf($this->flushEndpoint, $this->port, $server['bucket']),
126 | ], $configureOption, $this->setCredential());
127 | curl_setopt_array($initialize, $options);
128 | curl_multi_add_handle($handler, $initialize);
129 | }
130 | $this->callMulti($handler);
131 | }
132 |
133 | /**
134 | * @return array
135 | */
136 | protected function setCredential(): array
137 | {
138 | if (count($this->sasl) === 2) {
139 | list($username, $password) = $this->sasl;
140 |
141 | return [CURLOPT_USERPWD => "{$username}:{$password}"];
142 | }
143 |
144 | return [];
145 | }
146 |
147 | /**
148 | * @param $handler
149 | *
150 | * @throws \RuntimeException
151 | */
152 | protected function callMulti($handler)
153 | {
154 | $running = null;
155 |
156 | do {
157 | $stat = curl_multi_exec($handler, $running);
158 | } while ($stat === CURLM_CALL_MULTI_PERFORM);
159 | if (!$running || $stat !== CURLM_OK) {
160 | throw new \RuntimeException('failed to initialized cURL');
161 | }
162 |
163 | do {
164 | curl_multi_select($handler, $this->timeout);
165 | do {
166 | $stat = curl_multi_exec($handler, $running);
167 | } while ($stat === CURLM_CALL_MULTI_PERFORM);
168 | do {
169 | if ($read = curl_multi_info_read($handler, $remains)) {
170 | $response = curl_multi_getcontent($read['handle']);
171 |
172 | if ($response === false) {
173 | $info = curl_getinfo($read['handle']);
174 | throw new \RuntimeException("error: {$info['url']}: {$info['http_code']}");
175 | }
176 | curl_multi_remove_handle($handler, $read['handle']);
177 | curl_close($read['handle']);
178 | }
179 | } while ($remains);
180 | } while ($running);
181 | curl_multi_close($handler);
182 | }
183 |
184 | /**
185 | * @param int $second
186 | */
187 | public function timeout(int $second)
188 | {
189 | $this->timeout = $second;
190 | }
191 |
192 | /**
193 | * @param int $port
194 | */
195 | public function port(int $port)
196 | {
197 | $this->port = $port;
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/src/Console/DesignCreatorCommand.php:
--------------------------------------------------------------------------------
1 | */
40 | private $config = [];
41 |
42 | /**
43 | * DesignCreatorCommand constructor.
44 | *
45 | * @param DatabaseManager $databaseManager
46 | * @param array $config
47 | */
48 | public function __construct(DatabaseManager $databaseManager, array $config = [])
49 | {
50 | $this->databaseManager = $databaseManager;
51 | $this->config = $config;
52 | parent::__construct();
53 | }
54 |
55 | /**
56 | * @return string[]
57 | */
58 | protected function getArguments()
59 | {
60 | return [
61 | ['bucket', InputArgument::REQUIRED, 'Represents a bucket connection.'],
62 | ];
63 | }
64 |
65 | /**
66 | * Get the console command options.
67 | *
68 | * @return array
69 | */
70 | protected function getOptions()
71 | {
72 | return [
73 | ['database', 'db', InputOption::VALUE_REQUIRED, 'The database connection to use.', $this->defaultDatabase],
74 | ];
75 | }
76 |
77 | /**
78 | * Execute the console command
79 | */
80 | public function handle()
81 | {
82 | /** @var \Illuminate\Database\Connection|CouchbaseConnection $connection */
83 | $connection = $this->databaseManager->connection($this->option('database'));
84 | if ($connection instanceof CouchbaseConnection) {
85 | /** @var \Couchbase\Bucket $bucket */
86 | $bucket = $connection->openBucket($this->argument('bucket'));
87 | foreach ($this->config as $name => $document) {
88 | $bucket->manager()->insertDesignDocument($name, $document);
89 | $this->comment("created view name [{$name}]");
90 | }
91 | }
92 |
93 | return;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Console/IndexCreatorCommand.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | class IndexCreatorCommand extends Command
28 | {
29 | /** @var string */
30 | protected $name = 'couchbase:create-index';
31 |
32 | /** @var string */
33 | protected $description = 'Create a secondary index for the current bucket.';
34 |
35 | /** @var DatabaseManager */
36 | protected $databaseManager;
37 |
38 | /** @var string */
39 | protected $defaultDatabase = 'couchbase';
40 |
41 | /**
42 | * IndexFinderCommand constructor.
43 | *
44 | * @param DatabaseManager $databaseManager
45 | */
46 | public function __construct(DatabaseManager $databaseManager)
47 | {
48 | $this->databaseManager = $databaseManager;
49 | parent::__construct();
50 | }
51 |
52 | /**
53 | * @return string[]
54 | */
55 | protected function getArguments()
56 | {
57 | return [
58 | ['bucket', InputArgument::REQUIRED, 'Represents a bucket connection.'],
59 | ['name', InputArgument::REQUIRED, 'the name of the index.'],
60 | ['fields', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'the JSON fields to index.'],
61 | ];
62 | }
63 |
64 | /**
65 | * Get the console command options.
66 | *
67 | * @return array
68 | */
69 | protected function getOptions()
70 | {
71 | return [
72 | ['database', 'db', InputOption::VALUE_REQUIRED, 'The database connection to use.', $this->defaultDatabase],
73 | [
74 | 'where',
75 | null,
76 | InputOption::VALUE_REQUIRED,
77 | 'the WHERE clause of the index.',
78 | '',
79 | ],
80 | [
81 | 'ignore',
82 | 'ig',
83 | InputOption::VALUE_NONE,
84 | 'if a primary index already exists, an exception will be thrown unless this is set to true.',
85 | ],
86 | [
87 | 'defer',
88 | null,
89 | InputOption::VALUE_NONE,
90 | 'true to defer building of the index until buildN1qlDeferredIndexes()}is called (or a direct call to the corresponding query service API)',
91 | ],
92 | ];
93 | }
94 |
95 | /**
96 | * Execute the console command
97 | */
98 | public function handle()
99 | {
100 | /** @var \Illuminate\Database\Connection|CouchbaseConnection $connection */
101 | $connection = $this->databaseManager->connection($this->option('database'));
102 | if ($connection instanceof CouchbaseConnection) {
103 | $bucket = $connection->openBucket($this->argument('bucket'));
104 | $fields = $this->argument('fields');
105 | $whereClause = $this->option('where');
106 | $name = $this->argument('name');
107 | $bucket->manager()->createN1qlIndex(
108 | $name,
109 | $fields,
110 | $whereClause,
111 | $this->option('ignore'),
112 | $this->option('defer')
113 | );
114 | $field = implode(",", $fields);
115 | $this->info("created SECONDARY INDEX [{$name}] fields [{$field}], for [{$this->argument('bucket')}] bucket.");
116 | if ($whereClause !== '') {
117 | $this->comment("WHERE clause [{$whereClause}]");
118 | }
119 | }
120 |
121 | return;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/Console/IndexFinderCommand.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | class IndexFinderCommand extends Command
28 | {
29 | /** @var string */
30 | protected $name = 'couchbase:indexes';
31 |
32 | /** @var string */
33 | protected $description = 'List all N1QL indexes that are registered for the current bucket.';
34 |
35 | /** @var DatabaseManager */
36 | protected $databaseManager;
37 |
38 | /** @var string */
39 | protected $defaultDatabase = 'couchbase';
40 |
41 | /** @var string[] */
42 | private $headers = [
43 | "name",
44 | "isPrimary",
45 | "type",
46 | "state",
47 | "keyspace",
48 | "namespace",
49 | "fields",
50 | "condition",
51 | ];
52 |
53 | /**
54 | * IndexFinderCommand constructor.
55 | *
56 | * @param DatabaseManager $databaseManager
57 | */
58 | public function __construct(DatabaseManager $databaseManager)
59 | {
60 | $this->databaseManager = $databaseManager;
61 | parent::__construct();
62 | }
63 |
64 | /**
65 | * @return string[]
66 | */
67 | protected function getArguments()
68 | {
69 | return [
70 | ['bucket', InputArgument::REQUIRED, 'Represents a bucket connection.'],
71 | ];
72 | }
73 |
74 | /**
75 | * Get the console command options.
76 | *
77 | * @return array
78 | */
79 | protected function getOptions()
80 | {
81 | return [
82 | ['database', 'db', InputOption::VALUE_REQUIRED, 'The database connection to use.', $this->defaultDatabase],
83 | ];
84 | }
85 |
86 | /**
87 | * Execute the console command
88 | */
89 | public function handle()
90 | {
91 | $row = [];
92 | $tableRows = [];
93 | /** @var \Illuminate\Database\Connection|CouchbaseConnection $connection */
94 | $connection = $this->databaseManager->connection($this->option('database'));
95 | if ($connection instanceof CouchbaseConnection) {
96 | $bucket = $connection->getCouchbase()->openBucket($this->argument('bucket'));
97 | $indexes = $bucket->manager()->listN1qlIndexes();
98 | foreach ($indexes as $index) {
99 | foreach ($index as $key => $value) {
100 | if (array_search($key, $this->headers) !== false) {
101 | $row[] = (!is_array($value)) ? $value : implode(",", $value);
102 | }
103 | }
104 | $tableRows[] = $row;
105 | $row = [];
106 | }
107 | $this->table($this->headers, $tableRows);
108 | }
109 |
110 | return;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/Console/IndexRemoverCommand.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | class IndexRemoverCommand extends Command
28 | {
29 | /** @var string */
30 | protected $name = 'couchbase:drop-index';
31 |
32 | /** @var string */
33 | protected $description = 'Drop the given secondary index associated with the current bucket.';
34 |
35 | /** @var DatabaseManager */
36 | protected $databaseManager;
37 |
38 | /** @var string */
39 | protected $defaultDatabase = 'couchbase';
40 |
41 | /**
42 | * IndexFinderCommand constructor.
43 | *
44 | * @param DatabaseManager $databaseManager
45 | */
46 | public function __construct(DatabaseManager $databaseManager)
47 | {
48 | $this->databaseManager = $databaseManager;
49 | parent::__construct();
50 | }
51 |
52 | /**
53 | * @return string[]
54 | */
55 | protected function getArguments()
56 | {
57 | return [
58 | ['bucket', InputArgument::REQUIRED, 'Represents a bucket connection.'],
59 | ['name', InputArgument::REQUIRED, 'the name of the index.'],
60 | ];
61 | }
62 |
63 | /**
64 | * Get the console command options.
65 | *
66 | * @return array
67 | */
68 | protected function getOptions()
69 | {
70 | return [
71 | ['database', 'db', InputOption::VALUE_REQUIRED, 'The database connection to use.', $this->defaultDatabase],
72 | [
73 | 'ignore',
74 | 'ig',
75 | InputOption::VALUE_NONE,
76 | 'if a primary index already exists, an exception will be thrown unless this is set to true.',
77 | ],
78 | ];
79 | }
80 |
81 | /**
82 | * Execute the console command
83 | */
84 | public function handle()
85 | {
86 | /** @var \Illuminate\Database\Connection|CouchbaseConnection $connection */
87 | $connection = $this->databaseManager->connection($this->option('database'));
88 | if ($connection instanceof CouchbaseConnection) {
89 | $bucket = $connection->openBucket($this->argument('bucket'));
90 | $name = $this->argument('name');
91 | $bucket->manager()->dropN1qlIndex(
92 | $name,
93 | $this->option('ignore')
94 | );
95 | $this->info("dropped SECONDARY INDEX [{$name}] for [{$this->argument('bucket')}] bucket.");
96 | }
97 |
98 | return;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/Console/PrimaryIndexCreatorCommand.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | class PrimaryIndexCreatorCommand extends Command
28 | {
29 | /** @var string */
30 | protected $name = 'couchbase:create-primary-index';
31 |
32 | /** @var string */
33 | protected $description = 'Create a primary N1QL index for the current bucket.';
34 |
35 | /** @var DatabaseManager */
36 | protected $databaseManager;
37 |
38 | /** @var string */
39 | protected $defaultDatabase = 'couchbase';
40 |
41 | /**
42 | * IndexFinderCommand constructor.
43 | *
44 | * @param DatabaseManager $databaseManager
45 | */
46 | public function __construct(DatabaseManager $databaseManager)
47 | {
48 | $this->databaseManager = $databaseManager;
49 | parent::__construct();
50 | }
51 |
52 | /**
53 | * @return string[]
54 | */
55 | protected function getArguments()
56 | {
57 | return [
58 | ['bucket', InputArgument::REQUIRED, 'Represents a bucket connection.'],
59 | ];
60 | }
61 |
62 | /**
63 | * Get the console command options.
64 | *
65 | * @return array
66 | */
67 | protected function getOptions()
68 | {
69 | return [
70 | ['database', 'db', InputOption::VALUE_REQUIRED, 'The database connection to use.', $this->defaultDatabase],
71 | ['name', null, InputOption::VALUE_REQUIRED, 'the custom name for the primary index.', '#primary'],
72 | [
73 | 'ignore',
74 | 'ig',
75 | InputOption::VALUE_NONE,
76 | 'if a primary index already exists, an exception will be thrown unless this is set to true.',
77 | ],
78 | [
79 | 'defer',
80 | null,
81 | InputOption::VALUE_NONE,
82 | 'true to defer building of the index until buildN1qlDeferredIndexes()}is called (or a direct call to the corresponding query service API)',
83 | ],
84 | ];
85 | }
86 |
87 | /**
88 | * Execute the console command
89 | */
90 | public function handle()
91 | {
92 | /** @var \Illuminate\Database\Connection|CouchbaseConnection $connection */
93 | $connection = $this->databaseManager->connection($this->option('database'));
94 | if ($connection instanceof CouchbaseConnection) {
95 | $bucket = $connection->openBucket($this->argument('bucket'));
96 | $bucket->manager()->createN1qlPrimaryIndex(
97 | $this->option('name'),
98 | $this->option('ignore'),
99 | $this->option('defer')
100 | );
101 | $this->info("created PRIMARY INDEX [{$this->option('name')}] for [{$this->argument('bucket')}] bucket.");
102 | }
103 |
104 | return;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/Console/PrimaryIndexRemoverCommand.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | class PrimaryIndexRemoverCommand extends Command
28 | {
29 | /** @var string */
30 | protected $name = 'couchbase:drop-primary-index';
31 |
32 | /** @var string */
33 | protected $description = 'Drop the given primary index associated with the current bucket.';
34 |
35 | /** @var DatabaseManager */
36 | protected $databaseManager;
37 |
38 | /** @var string */
39 | protected $defaultDatabase = 'couchbase';
40 |
41 | /**
42 | * IndexFinderCommand constructor.
43 | *
44 | * @param DatabaseManager $databaseManager
45 | */
46 | public function __construct(DatabaseManager $databaseManager)
47 | {
48 | $this->databaseManager = $databaseManager;
49 | parent::__construct();
50 | }
51 |
52 | /**
53 | * @return string[]
54 | */
55 | protected function getArguments()
56 | {
57 | return [
58 | ['bucket', InputArgument::REQUIRED, 'Represents a bucket connection.'],
59 | ];
60 | }
61 |
62 | /**
63 | * Get the console command options.
64 | *
65 | * @return array
66 | */
67 | protected function getOptions()
68 | {
69 | return [
70 | ['database', 'db', InputOption::VALUE_REQUIRED, 'The database connection to use.', $this->defaultDatabase],
71 | ['name', null, InputOption::VALUE_REQUIRED, 'the custom name for the primary index.', '#primary'],
72 | [
73 | 'ignore',
74 | 'ig',
75 | InputOption::VALUE_NONE,
76 | 'if a primary index already exists, an exception will be thrown unless this is set to true.',
77 | ],
78 | ];
79 | }
80 |
81 | /**
82 | * Execute the console command
83 | */
84 | public function handle()
85 | {
86 | /** @var \Illuminate\Database\Connection|CouchbaseConnection $connection */
87 | $connection = $this->databaseManager->connection($this->option('database'));
88 | if ($connection instanceof CouchbaseConnection) {
89 | $bucket = $connection->openBucket($this->argument('bucket'));
90 | $bucket->manager()->dropN1qlPrimaryIndex(
91 | $this->option('name'),
92 | $this->option('ignore')
93 | );
94 | $this->info("dropped PRIMARY INDEX [{$this->option('name')}] for [{$this->argument('bucket')}] bucket.");
95 | }
96 |
97 | return;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/Console/QueueCreatorCommand.php:
--------------------------------------------------------------------------------
1 |
28 | */
29 | class QueueCreatorCommand extends Command
30 | {
31 | /** @var string */
32 | protected $name = 'couchbase:create-queue-index';
33 |
34 | /** @var string */
35 | protected $description = 'Create primary index, secondary indexes for the queue jobs couchbase bucket.';
36 |
37 | /** @var DatabaseManager */
38 | protected $databaseManager;
39 |
40 | /** @var string */
41 | protected $defaultDatabase = 'couchbase';
42 |
43 | const PRIMARY_KEY = '#job_queue_primary';
44 |
45 | /** @var array */
46 | protected $secondaryIndexes = [
47 | 'idx_job_queue' => [ // index name
48 | 'queue', // fields
49 | ],
50 | 'idx_job_identifier' => [
51 | 'id',
52 | ],
53 | 'idx_job_queue_cover' => [
54 | 'queue',
55 | 'reserved_at',
56 | 'available_at',
57 | 'id',
58 | ],
59 | ];
60 |
61 | /**
62 | * IndexFinderCommand constructor.
63 | *
64 | * @param DatabaseManager $databaseManager
65 | */
66 | public function __construct(DatabaseManager $databaseManager)
67 | {
68 | $this->databaseManager = $databaseManager;
69 | parent::__construct();
70 | }
71 |
72 | /**
73 | * @return string[]
74 | */
75 | protected function getArguments()
76 | {
77 | return [
78 | ['bucket', InputArgument::OPTIONAL, 'Represents a bucket connection.', 'jobs'],
79 | ];
80 | }
81 |
82 | /**
83 | * Get the console command options.
84 | *
85 | * @return array
86 | */
87 | protected function getOptions()
88 | {
89 | return [
90 | ['database', 'db', InputOption::VALUE_REQUIRED, 'The database connection to use.', $this->defaultDatabase],
91 | [
92 | 'ignore',
93 | 'ig',
94 | InputOption::VALUE_NONE,
95 | 'if a primary index already exists, an exception will be thrown unless this is set to true.',
96 | ],
97 | [
98 | 'defer',
99 | null,
100 | InputOption::VALUE_NONE,
101 | 'true to defer building of the index until buildN1qlDeferredIndexes()}is called (or a direct call to the corresponding query service API)',
102 | ],
103 | ];
104 | }
105 |
106 | /**
107 | * Execute the console command
108 | */
109 | public function handle()
110 | {
111 | /** @var \Illuminate\Database\Connection|CouchbaseConnection $connection */
112 | $connection = $this->databaseManager->connection($this->option('database'));
113 | if ($connection instanceof CouchbaseConnection) {
114 | $bucket = $connection->openBucket($this->argument('bucket'));
115 | $primary = self::PRIMARY_KEY;
116 | try {
117 | $bucket->manager()->createN1qlPrimaryIndex(
118 | $primary,
119 | $this->option('ignore'),
120 | $this->option('defer')
121 | );
122 | $this->info("created PRIMARY INDEX [{$primary}] for [{$this->argument('bucket')}] bucket.");
123 | } catch (\Exception $e) {
124 | $this->error($e->getMessage());
125 | }
126 | foreach ($this->secondaryIndexes as $name => $fields) {
127 | try {
128 | $bucket->manager()->createN1qlIndex(
129 | $name,
130 | $fields,
131 | '',
132 | $this->option('ignore'),
133 | $this->option('defer')
134 | );
135 | $field = implode(",", $fields);
136 | $this->info("created SECONDARY INDEX [{$name}] fields [{$field}], for [{$this->argument('bucket')}] bucket.");
137 | } catch (\Exception $e) {
138 | $this->error($e->getMessage());
139 | }
140 | }
141 | }
142 |
143 | return;
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/ConsoleServiceProvider.php:
--------------------------------------------------------------------------------
1 |
32 | */
33 | class ConsoleServiceProvider extends ServiceProvider
34 | {
35 | /** @var bool */
36 | protected $defer = true;
37 |
38 | public function boot()
39 | {
40 | $this->registerCommands();
41 | }
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function register()
47 | {
48 | $this->app->singleton('migration.repository', function ($app) {
49 | $table = $app['config']['database.migrations'];
50 |
51 | return new CouchbaseMigrationRepository($app['db'], $table);
52 | });
53 | }
54 |
55 | /**
56 | * register laravel-couchbase commands
57 | */
58 | protected function registerCommands(): void
59 | {
60 | $this->app->singleton('command.couchbase.indexes', function ($app) {
61 | return new IndexFinderCommand($app['Illuminate\Database\DatabaseManager']);
62 | });
63 | $this->app->singleton('command.couchbase.primary.index.create', function ($app) {
64 | return new PrimaryIndexCreatorCommand($app['Illuminate\Database\DatabaseManager']);
65 | });
66 | $this->app->singleton('command.couchbase.primary.index.drop', function ($app) {
67 | return new PrimaryIndexRemoverCommand($app['Illuminate\Database\DatabaseManager']);
68 | });
69 | $this->app->singleton('command.couchbase.index.create', function ($app) {
70 | return new IndexCreatorCommand($app['Illuminate\Database\DatabaseManager']);
71 | });
72 | $this->app->singleton('command.couchbase.index.drop', function ($app) {
73 | return new IndexRemoverCommand($app['Illuminate\Database\DatabaseManager']);
74 | });
75 | $this->app->singleton('command.couchbase.queue.index.create', function ($app) {
76 | return new QueueCreatorCommand($app['Illuminate\Database\DatabaseManager']);
77 | });
78 | $this->app->singleton('command.couchbase.design.document.create', function ($app) {
79 | return new DesignCreatorCommand(
80 | $app['Illuminate\Database\DatabaseManager'],
81 | $app['config']->get('couchbase.design')
82 | );
83 | });
84 | $this->commands([
85 | 'command.couchbase.indexes',
86 | 'command.couchbase.primary.index.create',
87 | 'command.couchbase.primary.index.drop',
88 | 'command.couchbase.index.create',
89 | 'command.couchbase.index.drop',
90 | 'command.couchbase.queue.index.create',
91 | 'command.couchbase.design.document.create',
92 | ]);
93 | }
94 |
95 | /**
96 | * {@inheritdoc}
97 | */
98 | public function provides()
99 | {
100 | return [
101 | 'command.couchbase.indexes',
102 | 'command.couchbase.primary.index.create',
103 | 'command.couchbase.primary.index.drop',
104 | 'command.couchbase.index.create',
105 | 'command.couchbase.index.drop',
106 | 'command.couchbase.queue.index.create',
107 | 'command.couchbase.design.document.create',
108 | 'migration.repository',
109 | ];
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/CouchbaseServiceProvider.php:
--------------------------------------------------------------------------------
1 |
34 | */
35 | class CouchbaseServiceProvider extends ServiceProvider
36 | {
37 | /**
38 | * Bootstrap application services.
39 | */
40 | public function boot()
41 | {
42 | $this->registerCouchbaseBucketCacheDriver();
43 | $this->registerMemcachedBucketCacheDriver();
44 | $this->registerCouchbaseQueueDriver();
45 | }
46 |
47 | /**
48 | * {@inheritdoc}
49 | */
50 | public function register()
51 | {
52 | $configPath = __DIR__ . '/config/couchbase.php';
53 | $this->mergeConfigFrom($configPath, 'couchbase');
54 | $this->publishes([$configPath => config_path('couchbase.php')], 'couchbase');
55 | $this->registerCouchbaseComponent();
56 | }
57 |
58 | protected function registerCouchbaseComponent()
59 | {
60 | $this->app->singleton(Connectable::class, function () {
61 | return new CouchbaseConnector();
62 | });
63 |
64 | $this->app->singleton('couchbase.memcached.connector', function () {
65 | return new MemcachedConnector();
66 | });
67 |
68 | // add couchbase session driver
69 | $this->app['session']->extend('couchbase', function ($app) {
70 | $minutes = $app['config']['session.lifetime'];
71 |
72 | return new CacheBasedSessionHandler(clone $this->app['cache']->driver('couchbase'), $minutes);
73 | });
74 |
75 | // add couchbase session driver
76 | $this->app['session']->extend('couchbase-memcached', function ($app) {
77 | $minutes = $app['config']['session.lifetime'];
78 |
79 | return new CacheBasedSessionHandler(clone $this->app['cache']->driver('couchbase-memcached'), $minutes);
80 | });
81 |
82 | // add couchbase extension
83 | $this->app['db']->extend('couchbase', function (array $config, $name) {
84 | /* @var \Couchbase\Cluster $cluster */
85 | return new CouchbaseConnection($config, $name);
86 | });
87 | }
88 |
89 | /**
90 | * register 'couchbase' cache driver.
91 | * for bucket type couchbase.
92 | */
93 | protected function registerCouchbaseBucketCacheDriver(): void
94 | {
95 | $this->app['cache']->extend('couchbase', function ($app, $config) {
96 | /** @var \Couchbase\Cluster $cluster */
97 | $cluster = $app['db']->connection($config['driver'])->getCouchbase();
98 | $password = (isset($config['bucket_password'])) ? $config['bucket_password'] : '';
99 |
100 | return new Repository(
101 | new CouchbaseStore(
102 | $cluster,
103 | $config['bucket'],
104 | $password,
105 | $app['config']->get('cache.prefix')
106 | )
107 | );
108 | });
109 | }
110 |
111 | /**
112 | * register 'couchbase' cache driver.
113 | * for bucket type memcached.
114 | */
115 | protected function registerMemcachedBucketCacheDriver(): void
116 | {
117 | $this->app['cache']->extend('couchbase-memcached', function ($app, $config) {
118 | $prefix = $app['config']['cache.prefix'];
119 | $credential = $config['sasl'] ?? [];
120 | $memcachedBucket = $this->app['couchbase.memcached.connector']
121 | ->connect($config['servers']);
122 |
123 | return new Repository(
124 | new MemcachedBucketStore(
125 | $memcachedBucket,
126 | strval($prefix),
127 | $config['servers'],
128 | $credential
129 | )
130 | );
131 | });
132 | }
133 |
134 | /**
135 | * register custom queue 'couchbase' driver
136 | */
137 | protected function registerCouchbaseQueueDriver(): void
138 | {
139 | /** @var QueueManager $queueManager */
140 | $queueManager = $this->app['queue'];
141 | $queueManager->addConnector('couchbase', function () {
142 | /** @var DatabaseManager $databaseManager */
143 | $databaseManager = $this->app['db'];
144 |
145 | return new QueueConnector($databaseManager);
146 | });
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/Database/Connectable.php:
--------------------------------------------------------------------------------
1 |
22 | */
23 | interface Connectable
24 | {
25 | /**
26 | * @param array $servers
27 | *
28 | * @return Cluster
29 | */
30 | public function connect(array $servers): Cluster;
31 | }
32 |
--------------------------------------------------------------------------------
/src/Database/CouchbaseConnection.php:
--------------------------------------------------------------------------------
1 |
35 | */
36 | class CouchbaseConnection extends Connection
37 | {
38 | /** @var string */
39 | protected $bucket;
40 |
41 | /** @var Cluster */
42 | protected $connection;
43 |
44 | /** @var */
45 | protected $managerUser;
46 |
47 | /** @var */
48 | protected $managerPassword;
49 |
50 | /** @var array */
51 | protected $options = [];
52 |
53 | /** @var int */
54 | protected $fetchMode = 0;
55 |
56 | /** @var array */
57 | protected $enableN1qlServers = [];
58 |
59 | /** @var string */
60 | protected $bucketPassword = '';
61 |
62 | /** @var string[] */
63 | protected $metrics;
64 |
65 | /** @var int default consistency */
66 | protected $consistency = N1qlQuery::NOT_BOUNDED;
67 |
68 | /** @var string[] function to handle the retrieval of various properties. */
69 | private $properties = [
70 | 'operationTimeout',
71 | 'viewTimeout',
72 | 'durabilityInterval',
73 | 'durabilityTimeout',
74 | 'httpTimeout',
75 | 'configTimeout',
76 | 'configDelay',
77 | 'configNodeTimeout',
78 | 'htconfigIdleTimeout',
79 | ];
80 |
81 | /** @var array */
82 | protected $config = [];
83 |
84 | /** @var string */
85 | private $name;
86 |
87 | /** @var bool */
88 | private $crossBucket = true;
89 |
90 | /**
91 | * @param array $config
92 | * @param string $name
93 | */
94 | public function __construct(array $config, $name)
95 | {
96 | $this->config = $config;
97 | $this->name = $name;
98 | $this->getManagedConfigure($config);
99 |
100 | $this->useDefaultQueryGrammar();
101 |
102 | $this->useDefaultPostProcessor();
103 | }
104 |
105 | /**
106 | * @param string $password
107 | *
108 | * @return CouchbaseConnection
109 | */
110 | public function setBucketPassword(string $password): CouchbaseConnection
111 | {
112 | $this->bucketPassword = $password;
113 |
114 | return $this;
115 | }
116 |
117 | /**
118 | * @param string $name
119 | *
120 | * @return Bucket
121 | */
122 | public function openBucket(string $name): Bucket
123 | {
124 | $couchbase = $this->getCouchbase();
125 | if ($this->bucketPassword === '') {
126 | return $couchbase->openBucket($name);
127 | }
128 |
129 | return $couchbase->openBucket($name, $this->bucketPassword);
130 | }
131 |
132 | /**
133 | * @return ClusterManager
134 | */
135 | public function manager(): ClusterManager
136 | {
137 | return $this->getCouchbase()->manager($this->managerUser, $this->managerPassword);
138 | }
139 |
140 | /**
141 | * @param Bucket $bucket
142 | *
143 | * @return string[]
144 | */
145 | public function getOptions(Bucket $bucket): array
146 | {
147 | $options = [];
148 | foreach ($this->properties as $property) {
149 | $options[$property] = $bucket->$property;
150 | }
151 |
152 | return $options;
153 | }
154 |
155 | /**
156 | * @param Bucket $bucket
157 | */
158 | protected function registerOption(Bucket $bucket)
159 | {
160 | if (count($this->options)) {
161 | foreach ($this->options as $option => $value) {
162 | $bucket->$option = $value;
163 | }
164 | }
165 | }
166 |
167 | /**
168 | * @return Processor
169 | */
170 | protected function getDefaultPostProcessor()
171 | {
172 | return new Processor();
173 | }
174 |
175 | /**
176 | * @return Grammar
177 | */
178 | protected function getDefaultQueryGrammar()
179 | {
180 | return new Grammar();
181 | }
182 |
183 | /**
184 | * @return Builder|\Illuminate\Database\Schema\Builder
185 | */
186 | public function getSchemaBuilder()
187 | {
188 | return new Builder($this);
189 | }
190 |
191 | /**
192 | * @param array $config enable(array), options(array), administrator(array), bucket_password(string)
193 | */
194 | protected function getManagedConfigure(array $config)
195 | {
196 | $this->enableN1qlServers = (isset($config['enables'])) ? $config['enables'] : [];
197 | $this->options = (isset($config['options'])) ? $config['options'] : [];
198 | $manager = (isset($config['administrator'])) ? $config['administrator'] : null;
199 | $this->managerUser = '';
200 | $this->managerPassword = '';
201 | if (!is_null($manager)) {
202 | $this->managerUser = $config['administrator']['user'];
203 | $this->managerPassword = $config['administrator']['password'];
204 | }
205 | $this->bucketPassword = (isset($config['bucket_password'])) ? $config['bucket_password'] : '';
206 | }
207 |
208 | /**
209 | * {@inheritdoc}
210 | */
211 | public function getName()
212 | {
213 | return $this->name;
214 | }
215 |
216 | /**
217 | * @return \Couchbase\Cluster
218 | */
219 | protected function createConnection(): Cluster
220 | {
221 | $this->setReconnector(function () {
222 | $this->connection = (new CouchbaseConnector)->connect($this->config);
223 |
224 | return $this;
225 | });
226 |
227 | return (new CouchbaseConnector)->connect($this->config);
228 | }
229 |
230 | /**
231 | * {@inheritdoc}
232 | */
233 | public function getDriverName()
234 | {
235 | return 'couchbase';
236 | }
237 |
238 | /**
239 | * @return Cluster
240 | */
241 | public function getCouchbase(): Cluster
242 | {
243 | if (is_null($this->connection)) {
244 | $this->connection = $this->createConnection();
245 | }
246 |
247 | return $this->connection;
248 | }
249 |
250 | /**
251 | * @param string $table
252 | *
253 | * @return QueryBuilder
254 | */
255 | public function table($table)
256 | {
257 | return $this->bucket($table)->query()->from($table);
258 | }
259 |
260 | /**
261 | * @param int $consistency
262 | * @param callable $callback
263 | *
264 | * @return mixed
265 | */
266 | public function callableConsistency(int $consistency, callable $callback)
267 | {
268 | $clone = clone $this;
269 | $clone->consistency = $consistency;
270 |
271 | return call_user_func_array($callback, [$clone]);
272 | }
273 |
274 | /**
275 | * @param int $consistency
276 | *
277 | * @return CouchbaseConnection
278 | */
279 | public function consistency(int $consistency): CouchbaseConnection
280 | {
281 | $this->consistency = $consistency;
282 |
283 | return $this;
284 | }
285 |
286 | /**
287 | * @param bool $cross
288 | */
289 | public function crossBucket(bool $cross): void
290 | {
291 | $this->crossBucket = $cross;
292 | }
293 |
294 | /**
295 | * @param string $bucket
296 | *
297 | * @return $this
298 | */
299 | public function bucket(string $bucket): CouchbaseConnection
300 | {
301 | $this->bucket = $bucket;
302 |
303 | return $this;
304 | }
305 |
306 | /**
307 | * @param N1qlQuery $query
308 | *
309 | * @return mixed
310 | */
311 | protected function executeQuery(N1qlQuery $query)
312 | {
313 | $bucket = $this->openBucket($this->bucket);
314 | $this->registerOption($bucket);
315 | $this->firePreparedQuery($query);
316 | $result = $bucket->query($query);
317 | $this->fireReturning($result);
318 |
319 | return $result;
320 | }
321 |
322 | /**
323 | * @param string $query
324 | * @param array $bindings
325 | *
326 | * @return \stdClass
327 | */
328 | protected function execute(string $query, array $bindings = [])
329 | {
330 | $query = N1qlQuery::fromString($query);
331 | $query->consistency($this->consistency);
332 | $query->crossBucket($this->crossBucket);
333 | $query->positionalParams($bindings);
334 | $result = $this->executeQuery($query);
335 | $this->metrics = $result->metrics ?? [];
336 |
337 | return $result;
338 | }
339 |
340 | /**
341 | * {@inheritdoc}
342 | */
343 | public function select($query, $bindings = [], $useReadPdo = true)
344 | {
345 | return $this->run($query, $bindings, function ($query, $bindings) {
346 | if ($this->pretending()) {
347 | return [];
348 | }
349 |
350 | $result = $this->execute($query, $bindings);
351 | $returning = [];
352 | if (isset($result->rows)) {
353 | foreach ($result->rows as $row) {
354 | if (!isset($row->{$this->bucket})) {
355 | return [$row];
356 | }
357 | $returning[] = $row;
358 | }
359 | }
360 |
361 | return $returning;
362 | });
363 | }
364 |
365 | /**
366 | * {@inheritdoc}
367 | */
368 | public function cursor($query, $bindings = [], $useReadPdo = true)
369 | {
370 | return $this->run($query, $bindings, function ($query, $bindings) {
371 | if ($this->pretending()) {
372 | return [];
373 | }
374 |
375 | $result = $this->execute($query, $bindings);
376 | if (isset($result->rows)) {
377 | foreach ($result->rows as $row) {
378 | yield $row->{$this->bucket};
379 | }
380 | }
381 | });
382 | }
383 |
384 | /**
385 | * @param string $query
386 | * @param array $bindings
387 | *
388 | * @return int|mixed
389 | */
390 | public function insert($query, $bindings = [])
391 | {
392 | return $this->affectingStatement($query, $bindings);
393 | }
394 |
395 | /**
396 | * {@inheritdoc}
397 | */
398 | public function affectingStatement($query, $bindings = [])
399 | {
400 | return $this->run($query, $bindings, function ($query, $bindings) {
401 | if ($this->pretending()) {
402 | return 0;
403 | }
404 | $query = N1qlQuery::fromString($query);
405 | $query->consistency($this->consistency);
406 | $query->crossBucket($this->crossBucket);
407 | $query->namedParams(['parameters' => $bindings]);
408 | $result = $this->executeQuery($query);
409 | $this->metrics = $result->metrics ?? [];
410 | if (!count($result->rows)) {
411 | return false;
412 | }
413 |
414 | return $result->rows[0]->{$this->bucket} ?? $result->rows[0];
415 | });
416 | }
417 |
418 | /**
419 | * @param string $query
420 | * @param array $bindings
421 | *
422 | * @return mixed
423 | */
424 | public function positionalStatement(string $query, array $bindings = [])
425 | {
426 | return $this->run($query, $bindings, function ($query, $bindings) {
427 | if ($this->pretending()) {
428 | return 0;
429 | }
430 | $query = N1qlQuery::fromString($query);
431 | $query->consistency($this->consistency);
432 | $query->crossBucket($this->crossBucket);
433 | $query->positionalParams($bindings);
434 | $result = $this->executeQuery($query);
435 | $this->metrics = $result->metrics ?? [];
436 | if (!count($result->rows)) {
437 | return false;
438 | }
439 |
440 | return $result->rows[0]->{$this->bucket} ?? $result->rows[0];
441 | });
442 | }
443 |
444 | /**
445 | * {@inheritdoc}
446 | */
447 | public function transaction(Closure $callback, $attempts = 1)
448 | {
449 | throw new NotSupportedException(__METHOD__);
450 | }
451 |
452 | /**
453 | * {@inheritdoc}
454 | */
455 | public function beginTransaction()
456 | {
457 | throw new NotSupportedException(__METHOD__);
458 | }
459 |
460 | /**
461 | * {@inheritdoc}
462 | */
463 | public function commit()
464 | {
465 | throw new NotSupportedException(__METHOD__);
466 | }
467 |
468 | /**
469 | * {@inheritdoc}
470 | */
471 | public function rollBack($toLevel = null)
472 | {
473 | throw new NotSupportedException(__METHOD__);
474 | }
475 |
476 | /**
477 | * {@inheritdoc}
478 | */
479 | protected function reconnectIfMissingConnection()
480 | {
481 | if (is_null($this->connection)) {
482 | $this->reconnect();
483 | }
484 | }
485 |
486 | /**
487 | * {@inheritdoc}
488 | */
489 | public function disconnect()
490 | {
491 | $this->connection = null;
492 | }
493 |
494 | /**
495 | * N1QL upsert query.
496 | *
497 | * @param string $query
498 | * @param array $bindings
499 | *
500 | * @return int
501 | */
502 | public function upsert(string $query, array $bindings = [])
503 | {
504 | return $this->affectingStatement($query, $bindings);
505 | }
506 |
507 | /**
508 | * Get a new query builder instance.
509 | *
510 | * @return QueryBuilder
511 | */
512 | public function query()
513 | {
514 | return new QueryBuilder(
515 | $this, $this->getQueryGrammar(), $this->getPostProcessor()
516 | );
517 | }
518 |
519 | /**
520 | * @param string|null $bucket
521 | *
522 | * @return View
523 | */
524 | public function view(string $bucket = null): View
525 | {
526 | $bucket = is_null($bucket) ? $this->bucket : $bucket;
527 |
528 | return new View($this->openBucket($bucket), $this->events);
529 | }
530 |
531 | /**
532 | * Run an update statement against the database.
533 | *
534 | * @param string $query
535 | * @param array $bindings
536 | *
537 | * @return int|\stdClass
538 | */
539 | public function update($query, $bindings = [])
540 | {
541 | return $this->positionalStatement($query, $bindings);
542 | }
543 |
544 | /**
545 | * Run a delete statement against the database.
546 | *
547 | * @param string $query
548 | * @param array $bindings
549 | *
550 | * @return int|\stdClass
551 | */
552 | public function delete($query, $bindings = [])
553 | {
554 | return $this->positionalStatement($query, $bindings);
555 | }
556 |
557 | /**
558 | * @return \string[]
559 | */
560 | public function metrics(): array
561 | {
562 | return $this->metrics;
563 | }
564 |
565 | /**
566 | * @param N1qlQuery $queryObject
567 | */
568 | protected function firePreparedQuery(N1qlQuery $queryObject)
569 | {
570 | if (isset($this->events)) {
571 | $this->events->dispatch(new QueryPrepared($queryObject));
572 | }
573 | }
574 |
575 | /**
576 | * @param mixed $returning
577 | */
578 | protected function fireReturning($returning)
579 | {
580 | if (isset($this->events)) {
581 | $this->events->dispatch(new ResultReturning($returning));
582 | }
583 | }
584 |
585 | /**
586 | * @param null|\PDO $pdo
587 | *
588 | * @return $this
589 | */
590 | public function setPdo($pdo)
591 | {
592 | $this->connection = $this->createConnection();
593 | $this->getManagedConfigure($this->config);
594 | $this->useDefaultQueryGrammar();
595 | $this->useDefaultPostProcessor();
596 |
597 | return $this;
598 | }
599 | }
600 |
--------------------------------------------------------------------------------
/src/Database/CouchbaseConnector.php:
--------------------------------------------------------------------------------
1 |
21 | */
22 | class CouchbaseConnector implements Connectable
23 | {
24 | /** @var string[] */
25 | protected $configure = [
26 | 'host' => 'couchbase://127.0.0.1',
27 | 'user' => '',
28 | 'password' => '',
29 | ];
30 |
31 | /**
32 | * @param array $servers
33 | *
34 | * @return Cluster
35 | */
36 | public function connect(array $servers): Cluster
37 | {
38 | $configure = array_merge($this->configure, $servers);
39 | $cluster = new Cluster($configure['host']);
40 | if (!empty($configure['user']) && !empty($configure['password'])) {
41 | $cluster->authenticateAs(strval($configure['user']), strval($configure['password']));
42 | }
43 |
44 | return $cluster;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Design/AbstractDocument.php:
--------------------------------------------------------------------------------
1 | name = $name;
22 | }
23 |
24 | /**
25 | * @return string
26 | */
27 | abstract protected function document(): string;
28 |
29 | /**
30 | * @return string
31 | */
32 | public function __toString(): string
33 | {
34 | return json_encode([
35 | $this->name => [
36 | 'map' => $this->document(),
37 | ],
38 | ]);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Events/QueryPrepared.php:
--------------------------------------------------------------------------------
1 |
22 | */
23 | final class QueryPrepared
24 | {
25 | /** @var N1qlQuery */
26 | private $object;
27 |
28 | /**
29 | * QueryPrepared constructor.
30 | *
31 | * @param mixed $queryObject
32 | */
33 | public function __construct($queryObject)
34 | {
35 | if ($this->isN1ql($queryObject)) {
36 | $this->object = $queryObject;
37 | }
38 | }
39 |
40 | /**
41 | * @param mixed $queryObject
42 | *
43 | * @return bool
44 | */
45 | private function isN1ql($queryObject): bool
46 | {
47 | if ($queryObject instanceof N1qlQuery) {
48 | return true;
49 | }
50 |
51 | return false;
52 | }
53 |
54 | /**
55 | * @return N1qlQuery|null
56 | */
57 | public function getQuery(): ?N1qlQuery
58 | {
59 | return $this->object;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Events/ResultReturning.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | final class ResultReturning
22 | {
23 | /** @var mixed */
24 | private $returning;
25 |
26 | /**
27 | * ResultReturning constructor.
28 | *
29 | * @param mixed $returning
30 | */
31 | public function __construct($returning)
32 | {
33 | $this->returning = $returning;
34 | }
35 |
36 | /**
37 | * @return mixed
38 | */
39 | public function returning()
40 | {
41 | return $this->returning;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Events/ViewQuerying.php:
--------------------------------------------------------------------------------
1 |
22 | */
23 | final class ViewQuerying
24 | {
25 | /** @var ViewQuery */
26 | private $viewQuery;
27 |
28 | /**
29 | * ViewQuerying constructor.
30 | *
31 | * @param ViewQuery $viewQuery
32 | */
33 | public function __construct(ViewQuery $viewQuery)
34 | {
35 | $this->viewQuery = $viewQuery;
36 | }
37 |
38 | /**
39 | * @return ViewQuery
40 | */
41 | public function viewQuery(): ViewQuery
42 | {
43 | return $this->viewQuery;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Exceptions/FlushException.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | final class FlushException extends \Exception
22 | {
23 | /**
24 | * FlushException constructor.
25 | *
26 | * @param array $message
27 | * @param int $code
28 | * @param \Throwable|null $previous
29 | */
30 | public function __construct(array $message, $code = 0, \Throwable $previous = null)
31 | {
32 | parent::__construct($message['_'], $code, $previous);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Exceptions/NotSupportedException.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | final class NotSupportedException extends \Exception
22 | {
23 | /**
24 | * @param string $message
25 | * @param int $code
26 | * @param \Throwable|null $previous
27 | */
28 | public function __construct($message, $code = 0, \Throwable $previous = null)
29 | {
30 | parent::__construct("$message method is not supported", $code, $previous);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/MemcachedConnector.php:
--------------------------------------------------------------------------------
1 |
23 | */
24 | class MemcachedConnector extends \Illuminate\Cache\MemcachedConnector
25 | {
26 | /**
27 | * Create a new Memcached connection.
28 | *
29 | * @param array $servers
30 | * @param string|null $connectionId
31 | * @param array $options
32 | * @param array $credentials
33 | *
34 | * @return \Memcached
35 | *
36 | * @throws \RuntimeException
37 | */
38 | public function connect(
39 | array $servers,
40 | $connectionId = null,
41 | array $options = [],
42 | array $credentials = []
43 | ) {
44 | $memcached = $this->getMemcached($connectionId, $credentials, []);
45 |
46 | foreach ($servers as $server) {
47 | $memcached->addServer(
48 | $server['host'], intval($server['port']), $server['weight']
49 | );
50 | }
51 |
52 | return $memcached;
53 | }
54 |
55 | /**
56 | * {@inheritdoc}
57 | */
58 | protected function getMemcached($connectionId, array $credentials, array $options)
59 | {
60 | return $this->createMemcachedInstance($connectionId);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Migrations/CouchbaseMigrationRepository.php:
--------------------------------------------------------------------------------
1 |
27 | */
28 | class CouchbaseMigrationRepository extends DatabaseMigrationRepository
29 | {
30 | /**
31 | * {@inheritdoc}
32 | */
33 | public function log($file, $batch)
34 | {
35 | $record = ['migration' => $file, 'batch' => $batch];
36 |
37 | $builder = $this->table();
38 | if ($builder instanceof QueryBuilder) {
39 | /** @var Builder */
40 | $builder->key("{$file}:{$batch}")->insert($record);
41 |
42 | return;
43 | }
44 | $builder->insert($record);
45 | }
46 |
47 | /**
48 | * {@inheritdoc}
49 | */
50 | public function createRepository()
51 | {
52 | $schema = $this->getConnection()->getSchemaBuilder();
53 |
54 | if ($schema instanceof Builder) {
55 | $schema->create($this->table, function (CouchbaseBlueprint $table) {
56 | $table->primaryIndex();
57 | $table->index(['migration', 'batch'], 'migration_secondary_index');
58 | });
59 |
60 | return;
61 | }
62 | $schema->create($this->table, function (Blueprint $table) {
63 | $table->string('migration');
64 | $table->integer('batch');
65 | });
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Query/Builder.php:
--------------------------------------------------------------------------------
1 | key = $key;
49 |
50 | return $this;
51 | }
52 |
53 | /**
54 | * @param array $column
55 | *
56 | * @return Builder
57 | */
58 | public function returning(array $column = ['*']): Builder
59 | {
60 | $this->returning = $column;
61 |
62 | return $this;
63 | }
64 |
65 | /**
66 | * Insert a new record into the database.
67 | *
68 | * @param array $values
69 | *
70 | * @return bool
71 | */
72 | public function insert(array $values)
73 | {
74 | if (empty($values)) {
75 | return true;
76 | }
77 | $values = $this->detectValues($values);
78 | $bindings = [];
79 | foreach ($values as $record) {
80 | foreach ($record as $key => $value) {
81 | $bindings[$key] = $value;
82 | }
83 | }
84 |
85 | $sql = $this->grammar->compileInsert($this, $values);
86 |
87 | return $this->connection->insert($sql, $bindings);
88 | }
89 |
90 | /**
91 | * supported N1QL upsert query.
92 | *
93 | * @param array $values
94 | *
95 | * @return bool|mixed
96 | */
97 | public function upsert(array $values)
98 | {
99 | if (empty($values)) {
100 | return true;
101 | }
102 | $values = $this->detectValues($values);
103 | $bindings = [];
104 | foreach ($values as $record) {
105 | foreach ($record as $key => $value) {
106 | $bindings[$key] = $value;
107 | }
108 | }
109 |
110 | $sql = $this->grammar->compileUpsert($this, $values);
111 |
112 | return $this->connection->upsert($sql, $bindings);
113 | }
114 |
115 | /**
116 | * @param string|int|array $values
117 | *
118 | * @return array
119 | */
120 | protected function detectValues($values): array
121 | {
122 | if (!is_array(reset($values))) {
123 | $values = [$values];
124 | } else {
125 | foreach ($values as $key => $value) {
126 | ksort($value);
127 | $values[$key] = $value;
128 | }
129 | }
130 |
131 | return $values;
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/Query/Grammar.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | class Grammar extends IlluminateGrammar
26 | {
27 | /**
28 | * {@inheritdoc}
29 | */
30 | protected function wrapValue($value)
31 | {
32 | if ($value === '*') {
33 | return $value;
34 | }
35 |
36 | return $value;
37 | }
38 |
39 | /**
40 | * @param mixed $value
41 | *
42 | * @return string
43 | */
44 | protected function wrapKey($value)
45 | {
46 | if (is_null($value)) {
47 | return;
48 | }
49 |
50 | return '"' . str_replace('"', '""', $value) . '"';
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | *
56 | * notice: supported set query only
57 | */
58 | public function compileUpdate(Builder $query, $values)
59 | {
60 | // keyspace-ref:
61 | $table = $this->wrapTable($query->from);
62 | // use-keys-clause:
63 | $keyClause = $this->wrapKey($query->key);
64 | // returning-clause
65 | $returning = implode(', ', $query->returning);
66 |
67 | $columns = [];
68 |
69 | foreach ($values as $key => $value) {
70 | $columns[] = $this->wrap($key) . ' = ' . $this->parameter($value);
71 | }
72 |
73 | $columns = implode(', ', $columns);
74 |
75 | $joins = '';
76 | if (isset($query->joins)) {
77 | $joins = ' ' . $this->compileJoins($query, $query->joins);
78 | }
79 | $where = $this->compileWheres($query);
80 |
81 | return trim("update {$table} USE KEYS {$keyClause} {$joins} set $columns $where RETURNING {$returning}");
82 | }
83 |
84 | /**
85 | * {@inheritdoc}
86 | */
87 | public function compileInsert(Builder $query, array $values)
88 | {
89 | // keyspace-ref:
90 | $table = $this->wrapTable($query->from);
91 | // use-keys-clause:
92 | $keyClause = $this->wrapKey($query->key);
93 | // returning-clause
94 | $returning = implode(', ', $query->returning);
95 |
96 | if (!is_array(reset($values))) {
97 | $values = [$values];
98 | }
99 | $parameters = [];
100 |
101 | foreach ($values as $record) {
102 | $parameters[] = '(' . $this->parameterize($record) . ')';
103 | }
104 | $parameters = (!$keyClause) ? implode(', ', $parameters) : "({$keyClause}, \$parameters)";
105 | $keyValue = (!$keyClause) ? null : '(KEY, VALUE)';
106 |
107 | return "insert into {$table} {$keyValue} values $parameters RETURNING {$returning}";
108 | }
109 |
110 | /**
111 | * {@inheritdoc}
112 | *
113 | * @see http://developer.couchbase.com/documentation/server/4.1/n1ql/n1ql-language-reference/delete.html
114 | */
115 | public function compileDelete(Builder $query)
116 | {
117 | // keyspace-ref:
118 | $table = $this->wrapTable($query->from);
119 | // use-keys-clause:
120 | $keyClause = null;
121 | if ($query->key) {
122 | $key = $this->wrapKey($query->key);
123 | $keyClause = "USE KEYS {$key}";
124 | }
125 | // returning-clause
126 | $returning = implode(', ', $query->returning);
127 | $where = is_array($query->wheres) ? $this->compileWheres($query) : '';
128 |
129 | return trim("delete from {$table} {$keyClause} {$where} RETURNING {$returning}");
130 | }
131 |
132 | /**
133 | * @param QueryBuilder $query
134 | * @param array $values
135 | *
136 | * @return string
137 | */
138 | public function compileUpsert(QueryBuilder $query, array $values): string
139 | {
140 | // keyspace-ref:
141 | $table = $this->wrapTable($query->from);
142 | // use-keys-clause:
143 | $keyClause = $this->wrapKey($query->key);
144 | // returning-clause
145 | $returning = implode(', ', $query->returning);
146 |
147 | if (!is_array(reset($values))) {
148 | $values = [$values];
149 | }
150 | $parameters = [];
151 |
152 | foreach ($values as $record) {
153 | $parameters[] = '(' . $this->parameterize($record) . ')';
154 | }
155 | $parameters = (!$keyClause) ? implode(', ', $parameters) : "({$keyClause}, \$parameters)";
156 | $keyValue = (!$keyClause) ? null : '(KEY, VALUE)';
157 |
158 | return "UPSERT INTO {$table} {$keyValue} VALUES $parameters RETURNING {$returning}";
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/Query/Processor.php:
--------------------------------------------------------------------------------
1 |
22 | */
23 | class Processor extends IlluminateProcessor
24 | {
25 | }
26 |
--------------------------------------------------------------------------------
/src/Query/View.php:
--------------------------------------------------------------------------------
1 |
28 | */
29 | class View
30 | {
31 | /** @var Bucket */
32 | protected $bucket;
33 |
34 | /** @var Dispatcher */
35 | protected $dispatcher;
36 |
37 | /**
38 | * Specifies the mode of updating to perorm before and after executing the query
39 | *
40 | * @see \Couchbase\ViewQuery::UPDATE_BEFORE
41 | * @see \Couchbase\ViewQuery::UPDATE_NONE
42 | * @see \Couchbase\ViewQuery::UPDATE_AFTER
43 | */
44 | private $consistency = null;
45 |
46 | /**
47 | * View constructor.
48 | *
49 | * @param Bucket $bucket
50 | * @param Dispatcher|null $dispatcher
51 | */
52 | public function __construct(Bucket $bucket, Dispatcher $dispatcher = null)
53 | {
54 | $this->bucket = $bucket;
55 | $this->dispatcher = $dispatcher;
56 | }
57 |
58 | /**
59 | * @param string $designDoc
60 | * @param string $name
61 | *
62 | * @return ViewQuery
63 | */
64 | public function from(string $designDoc, string $name): ViewQuery
65 | {
66 | return ViewQuery::from($designDoc, $name);
67 | }
68 |
69 | /**
70 | * @param string $designDoc
71 | * @param string $name
72 | *
73 | * @return SpatialViewQuery
74 | */
75 | public function fromSpatial(string $designDoc, string $name): SpatialViewQuery
76 | {
77 | return ViewQuery::fromSpatial($designDoc, $name);
78 | }
79 |
80 | /**
81 | * @param ViewQuery $viewQuery
82 | * @param bool $jsonAsArray
83 | *
84 | * @return mixed
85 | */
86 | public function execute(ViewQuery $viewQuery, bool $jsonAsArray = false)
87 | {
88 | if (isset($this->dispatcher)) {
89 | $this->dispatcher->dispatch(new ViewQuerying($viewQuery));
90 | }
91 | if (!is_null($this->consistency)) {
92 | $viewQuery = $viewQuery->consistency($this->consistency);
93 | }
94 |
95 | return $this->bucket->query($viewQuery, $jsonAsArray);
96 | }
97 |
98 | /**
99 | * @param int $consistency
100 | */
101 | public function consistency(int $consistency): void
102 | {
103 | $this->consistency = $consistency;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/Queue/CouchbaseConnector.php:
--------------------------------------------------------------------------------
1 |
25 | */
26 | class CouchbaseConnector implements ConnectorInterface
27 | {
28 | /** @var ConnectionResolverInterface */
29 | protected $connectionResolver;
30 |
31 | /**
32 | * CouchbaseConnector constructor.
33 | *
34 | * @param ConnectionResolverInterface $connectionResolver
35 | */
36 | public function __construct(ConnectionResolverInterface $connectionResolver)
37 | {
38 | $this->connectionResolver = $connectionResolver;
39 | }
40 |
41 | /**
42 | * @param array $config
43 | *
44 | * @return CouchbaseQueue|\Illuminate\Contracts\Queue\Queue
45 | */
46 | public function connect(array $config)
47 | {
48 | /** @var CouchbaseConnection $connection */
49 | $connection = $this->connectionResolver->connection($config['driver']);
50 |
51 | return new CouchbaseQueue(
52 | $connection,
53 | $config['bucket'],
54 | $config['queue'],
55 | Arr::get($config, 'retry_after', 60)
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Queue/CouchbaseQueue.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | class CouchbaseQueue extends DatabaseQueue
28 | {
29 | /**
30 | * The couchbase bucket that holds the jobs.
31 | *
32 | * @var string
33 | */
34 | protected $table;
35 |
36 | /** @var CouchbaseConnection */
37 | protected $database;
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | public function pop($queue = null)
43 | {
44 | $queue = $this->getQueue($queue);
45 | if ($job = $this->getNextAvailableJob($queue)) {
46 | return $this->marshalJob($queue, $job);
47 | }
48 |
49 | return null;
50 | }
51 |
52 | /**
53 | * {@inheritdoc}
54 | */
55 | protected function marshalJob($queue, $job)
56 | {
57 | $job = $this->markJobAsReserved($job);
58 |
59 | return new DatabaseJob(
60 | $this->container, $this, $job, $this->connectionName, $queue
61 | );
62 | }
63 |
64 | /**
65 | * {@inheritdoc}
66 | */
67 | protected function getNextAvailableJob($queue)
68 | {
69 | $job = $this->database->table($this->table)
70 | ->where('queue', $this->getQueue($queue))
71 | ->where(function (Builder $query) {
72 | $this->isAvailable($query);
73 | $this->isReservedButExpired($query);
74 | })
75 | ->orderBy('id', 'asc')
76 | ->first(['*', 'meta().id']);
77 |
78 | return $job ? new DatabaseJobRecord((object)$job) : null;
79 | }
80 |
81 | /**
82 | * {@inheritdoc}
83 | */
84 | protected function markJobAsReserved($job)
85 | {
86 | $bucket = $this->table;
87 | /** @var \Couchbase\Bucket $openBucket */
88 | $openBucket = $this->database->openBucket($bucket);
89 | // lock bucket
90 | $meta = $openBucket->getAndLock($job->id, 10);
91 | $meta->value->attempts = $job->$bucket->attempts + 1;
92 | $meta->value->reserved_at = $job->touch();
93 | $openBucket->replace($job->id, $meta->value, ['cas' => $meta->cas]);
94 |
95 | return $meta->value;
96 | }
97 |
98 | /**
99 | * {@inheritdoc}
100 | */
101 | public function bulk($jobs, $data = '', $queue = null)
102 | {
103 | foreach ((array)$jobs as $job) {
104 | $this->push($job, $data, $queue);
105 | }
106 | }
107 |
108 | /**
109 | * {@inheritdoc}
110 | */
111 | public function deleteReserved($queue, $id)
112 | {
113 | $this->database->table($this->table)->where('id', $id)->delete();
114 | }
115 |
116 | /**
117 | * {@inheritdoc}
118 | */
119 | protected function pushToDatabase($queue, $payload, $delay = 0, $attempts = 0)
120 | {
121 | $attributes = $this->buildDatabaseRecord(
122 | $this->getQueue($queue), $payload, $this->availableAt($delay), $attempts
123 | );
124 | $increment = $this->incrementKey();
125 | $attributes['id'] = $increment;
126 | $result = $this->database->table($this->table)
127 | ->key($this->uniqueKey($attributes))->insert($attributes);
128 | if ($result) {
129 | return $increment;
130 | }
131 |
132 | return false;
133 | }
134 |
135 | /**
136 | * generate increment key
137 | *
138 | * @param int $initial
139 | *
140 | * @return int
141 | */
142 | protected function incrementKey($initial = 1)
143 | {
144 | $result = $this->database->openBucket($this->table)
145 | ->counter($this->identifier(), $initial, ['initial' => abs($initial)]);
146 |
147 | return $result->value;
148 | }
149 |
150 | /**
151 | * @param array $attributes
152 | *
153 | * @return string
154 | */
155 | protected function uniqueKey(array $attributes): string
156 | {
157 | $array = array_only($attributes, ['queue', 'attempts', 'id']);
158 |
159 | return implode(':', $array);
160 | }
161 |
162 | /**
163 | * @return string
164 | */
165 | protected function identifier(): string
166 | {
167 | return __CLASS__ . ':sequence';
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/Schema/Blueprint.php:
--------------------------------------------------------------------------------
1 |
21 | */
22 | class Blueprint extends \Illuminate\Database\Schema\Blueprint
23 | {
24 | use NotSupportedTrait;
25 |
26 | /** @var CouchbaseConnection */
27 | protected $connection;
28 |
29 | /** @var string[] */
30 | protected $options = [
31 | 'bucketType' => 'couchbase',
32 | 'saslPassword' => '',
33 | 'flushEnabled' => true,
34 | ];
35 |
36 | /**
37 | * @param CouchbaseConnection $connection
38 | */
39 | public function connector(CouchbaseConnection $connection)
40 | {
41 | $this->connection = $connection;
42 | }
43 |
44 | /**
45 | * @param array $options
46 | */
47 | public function setOptions(array $options)
48 | {
49 | $this->options = array_merge($this->options, $options);
50 | }
51 |
52 | /**
53 | * @return bool
54 | */
55 | public function create()
56 | {
57 | $this->connection->manager()->createBucket($this->table, $this->options);
58 | }
59 |
60 | /**
61 | * {@inheritdoc}
62 | */
63 | public function drop()
64 | {
65 | $this->connection->manager()->removeBucket($this->table);
66 | }
67 |
68 | /**
69 | * drop for N1QL primary index
70 | *
71 | * @param string $index
72 | * @param bool $ignoreIfNotExist
73 | *
74 | * @return mixed
75 | */
76 | public function dropPrimary($index = null, $ignoreIfNotExist = false)
77 | {
78 | $this->connection->openBucket($this->getTable())
79 | ->manager()->dropN1qlPrimaryIndex($this->detectIndexName($index), $ignoreIfNotExist);
80 | }
81 |
82 | /**
83 | * drop for N1QL secondary index
84 | *
85 | * @param string $index
86 | * @param bool $ignoreIfNotExist
87 | *
88 | * @return mixed
89 | */
90 | public function dropIndex($index, $ignoreIfNotExist = false)
91 | {
92 | $this->connection->openBucket($this->getTable())
93 | ->manager()->dropN1qlIndex($index, $ignoreIfNotExist);
94 | }
95 |
96 | /**
97 | * Specify the primary index for the current bucket.
98 | *
99 | * @param string|null $name
100 | * @param boolean $ignoreIfExist if a primary index already exists, an exception will be thrown unless this is
101 | * set to true.
102 | * @param boolean $defer true to defer building of the index until buildN1qlDeferredIndexes()}is
103 | * called (or a direct call to the corresponding query service API).
104 | */
105 | public function primaryIndex($name = null, $ignoreIfExist = false, $defer = false)
106 | {
107 | $this->connection->openBucket($this->getTable())
108 | ->manager()->createN1qlPrimaryIndex(
109 | $this->detectIndexName($name),
110 | $ignoreIfExist,
111 | $defer
112 | );
113 | }
114 |
115 | /**
116 | * Specify a secondary index for the current bucket.
117 | *
118 | * @param array $columns the JSON fields to index.
119 | * @param string $name the name of the index.
120 | * @param string $whereClause the WHERE clause of the index.
121 | * @param boolean $ignoreIfExist if a secondary index already exists with that name, an exception will be
122 | * thrown unless this is set to true.
123 | * @param boolean $defer true to defer building of the index until buildN1qlDeferredIndexes() is
124 | * called (or a direct call to the corresponding query service API).
125 | *
126 | * @return mixed
127 | */
128 | public function index($columns, $name = null, $whereClause = '', $ignoreIfExist = false, $defer = false)
129 | {
130 | $name = (is_null($name)) ? $this->getTable() . "_secondary_index" : $name;
131 |
132 | return $this->connection->openBucket($this->getTable())
133 | ->manager()->createN1qlIndex(
134 | $name,
135 | $columns,
136 | $whereClause,
137 | $ignoreIfExist,
138 | $defer
139 | );
140 | }
141 |
142 | /**
143 | * Get the table the blueprint describes.
144 | *
145 | * @return string
146 | */
147 | public function getTable()
148 | {
149 | return $this->table;
150 | }
151 |
152 | /**
153 | * @param $index
154 | *
155 | * @return string
156 | */
157 | protected function detectIndexName($index)
158 | {
159 | $index = (is_null($index)) ? "" : $index;
160 |
161 | return $index;
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/Schema/Builder.php:
--------------------------------------------------------------------------------
1 |
23 | */
24 | class Builder extends \Illuminate\Database\Schema\Builder
25 | {
26 | /**
27 | * The database connection instance.
28 | *
29 | * @var \Illuminate\Database\Connection|CouchbaseConnection
30 | */
31 | protected $connection;
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function hasTable($table)
37 | {
38 | try {
39 | $bucketInfo = $this->connection->openBucket($table)->manager()->info();
40 | if (!is_null($bucketInfo['name'])) {
41 | return true;
42 | }
43 |
44 | return true;
45 | } catch (Exception $e) {
46 | return false;
47 | }
48 | }
49 |
50 | /**
51 | * {@inheritdoc}
52 | */
53 | public function hasColumn($table, $column)
54 | {
55 | return true;
56 | }
57 |
58 | /**
59 | * {@inheritdoc}
60 | */
61 | public function hasColumns($table, array $columns)
62 | {
63 | return true;
64 | }
65 |
66 | /**
67 | * needs administrator password, user
68 | *
69 | * @param string $collection
70 | * @param Closure|null $callback
71 | *
72 | * @return void
73 | */
74 | public function create($collection, Closure $callback = null)
75 | {
76 | $blueprint = $this->createBlueprint($collection);
77 | $blueprint->create();
78 | sleep(10);
79 | if ($callback) {
80 | $callback($blueprint);
81 | }
82 | }
83 |
84 | /**
85 | * {@inheritdoc}
86 | */
87 | public function drop($collection)
88 | {
89 | $blueprint = $this->createBlueprint($collection);
90 | $blueprint->drop();
91 | sleep(10);
92 |
93 | return true;
94 | }
95 |
96 | /**
97 | * {@inheritdoc}
98 | */
99 | protected function createBlueprint($table, Closure $callback = null): Blueprint
100 | {
101 | $blueprint = new Blueprint($table, $callback);
102 | $blueprint->connector($this->connection);
103 |
104 | return $blueprint;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/Schema/NotSupportedTrait.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | trait NotSupportedTrait
28 | {
29 | /**
30 | * {@inheritdoc}
31 | */
32 | public function toSql(Connection $connection, Grammar $grammar)
33 | {
34 | throw new NotSupportedException(__METHOD__);
35 | }
36 |
37 | /**
38 | * {@inheritdoc}
39 | */
40 | protected function createIndexName($type, array $columns)
41 | {
42 | throw new NotSupportedException(__METHOD__);
43 | }
44 |
45 | /**
46 | * {@inheritdoc}
47 | */
48 | public function addColumn($type, $name, array $parameters = [])
49 | {
50 | throw new NotSupportedException(__METHOD__);
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function removeColumn($name)
57 | {
58 | throw new NotSupportedException(__METHOD__);
59 | }
60 |
61 | /**
62 | * {@inheritdoc}
63 | */
64 | protected function addCommand($name, array $parameters = [])
65 | {
66 | throw new NotSupportedException(__METHOD__);
67 | }
68 |
69 | /**
70 | * {@inheritdoc}
71 | */
72 | protected function createCommand($name, array $parameters = [])
73 | {
74 | throw new NotSupportedException(__METHOD__);
75 | }
76 |
77 | /**
78 | * {@inheritdoc}
79 | */
80 | public function getChangedColumns()
81 | {
82 | throw new NotSupportedException(__METHOD__);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/config/couchbase.php:
--------------------------------------------------------------------------------
1 | [
20 | /*
21 | 'Your Design Document Name' => [
22 | 'views' => [
23 | 'Your View Name' => [
24 | 'map' => file_get_contents(__DIR__ . '/../resources/sample.ddoc'),
25 | ],
26 | ],
27 | ],
28 | */
29 | ]
30 | ];
31 |
--------------------------------------------------------------------------------
/src/resources/sample.ddoc:
--------------------------------------------------------------------------------
1 | function (doc, meta) {
2 | emit(meta.id, null);
3 | }
4 |
--------------------------------------------------------------------------------
/src/transfer.php:
--------------------------------------------------------------------------------
1 | COUCHBASE_SERTYPE_PHP,
23 | 'cmprtype' => COUCHBASE_CMPRTYPE_NONE,
24 | 'cmprthresh' => 0,
25 | 'cmprfactor' => 0,
26 | ]);
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Console/DesignCreatorCommandTest.php:
--------------------------------------------------------------------------------
1 | databaseManager = $this->app['db'];
29 | $this->config = $this->app['config'];
30 | $this->command = new DesignCreatorCommand(
31 | $this->databaseManager,
32 | $this->config->get('couchbase.design')
33 | );
34 | $this->command->setLaravel(new MockApplication);
35 | }
36 |
37 | public function testCreateSecondaryIndex()
38 | {
39 | /** @var \Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
40 | $connection = $this->databaseManager->connection('couchbase');
41 | $bucket = $connection->openBucket($this->bucket);
42 | $bucket->manager()->removeDesignDocument('dev_testing');
43 | $bucket->manager()->removeDesignDocument('dev_testing_name');
44 | sleep(4);
45 | $output = new BufferedOutput();
46 | $this->command->run(
47 | new ArrayInput([
48 | 'bucket' => $this->bucket,
49 | ]),
50 | $output
51 | );
52 | $output->fetch();
53 | $lists = $bucket->manager()->listDesignDocuments();
54 | $documents = [];
55 | foreach ($lists['rows'] as $row) {
56 | $documents[] = $row['doc']['meta']['id'];
57 | }
58 | $this->assertContains('_design/dev_testing_name', $documents);
59 | $this->assertContains('_design/dev_testing', $documents);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tests/Console/IndexCreatorCommandTest.php:
--------------------------------------------------------------------------------
1 | databaseManager = $this->app['db'];
19 | $this->command = new \Ytake\LaravelCouchbase\Console\IndexCreatorCommand($this->databaseManager);
20 | $this->command->setLaravel(new MockApplication);
21 | }
22 |
23 | public function testCreateSecondaryIndex()
24 | {
25 | /** @var \Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
26 | $connection = $this->databaseManager->connection('couchbase');
27 | $connection->manager();
28 | $bucket = $connection->openBucket($this->bucket);
29 | try {
30 | $bucket->manager()->dropN1qlPrimaryIndex('#primary');
31 | } catch (\Couchbase\Exception $e) {
32 | // none
33 | }
34 | $bucket->manager()->createN1qlPrimaryIndex();
35 | sleep(4);
36 | $output = new \Symfony\Component\Console\Output\BufferedOutput();
37 | $this->command->run(
38 | new \Symfony\Component\Console\Input\ArrayInput([
39 | 'bucket' => $this->bucket,
40 | 'name' => 'testing_gsi',
41 | 'fields' => ['params1', 'params2'],
42 | ]),
43 | $output
44 | );
45 | $fetch = $output->fetch();
46 | $this->assertSame("created SECONDARY INDEX [testing_gsi] fields [params1,params2], for [index_testing] bucket.", trim($fetch));
47 | /** @var \Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
48 | $connection = $this->databaseManager->connection('couchbase');
49 | $bucket = $connection->openBucket($this->bucket);
50 | $indexes = $bucket->manager()->listN1qlIndexes();
51 | foreach ($indexes as $index) {
52 | if (!$index->isPrimary && $index->keyspace === 'keyspace') {
53 | $this->assertSame("testing_gsi", $index->name);
54 | $this->assertInstanceOf('CouchbaseN1qlIndex', $index);
55 | }
56 | }
57 | $bucket->manager()->dropN1qlPrimaryIndex();
58 | $bucket->manager()->dropN1qlIndex('testing_gsi');
59 | sleep(5);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tests/Console/IndexFinderCommandTest.php:
--------------------------------------------------------------------------------
1 | app['db'];
16 | $this->command = new \Ytake\LaravelCouchbase\Console\IndexFinderCommand($cluster);
17 | $this->command->setLaravel(new MockApplication());
18 | }
19 |
20 | /**
21 | *
22 | */
23 | public function testShouldReturnDatabaseInformation()
24 | {
25 | $output = new \Symfony\Component\Console\Output\BufferedOutput();
26 | $this->command->run(
27 | new \Symfony\Component\Console\Input\ArrayInput([
28 | 'bucket' => 'testing',
29 | ]),
30 | $output
31 | );
32 | $fetch = $output->fetch();
33 | $this->assertNotNull($fetch);
34 | $this->assertContains('primary', $fetch);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/Console/IndexRemoverCommandTest.php:
--------------------------------------------------------------------------------
1 | databaseManager = $this->app['db'];
19 | $this->command = new \Ytake\LaravelCouchbase\Console\IndexRemoverCommand($this->databaseManager);
20 | $this->command->setLaravel(new MockApplication);
21 | }
22 |
23 | public function testDropSecondaryIndex()
24 | {
25 | /** @var \Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
26 | $connection = $this->databaseManager->connection('couchbase');
27 | $bucket = $connection->openBucket($this->bucket);
28 | $bucket->manager()->createN1qlPrimaryIndex();
29 | $bucket->manager()->createN1qlIndex('testing_gsi', ['params1', 'params2']);
30 | $output = new \Symfony\Component\Console\Output\BufferedOutput();
31 | $this->command->run(
32 | new \Symfony\Component\Console\Input\ArrayInput([
33 | 'bucket' => $this->bucket,
34 | 'name' => 'testing_gsi',
35 | ]),
36 | $output
37 | );
38 | $fetch = $output->fetch();
39 | $this->assertSame("dropped SECONDARY INDEX [testing_gsi] for [index_testing] bucket.", trim($fetch));
40 | sleep(5);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/Console/PrimaryIndexCreatorCommandTest.php:
--------------------------------------------------------------------------------
1 | databaseManager = $this->app['db'];
19 | $this->command = new \Ytake\LaravelCouchbase\Console\PrimaryIndexCreatorCommand($this->databaseManager);
20 | $this->command->setLaravel(new MockApplication);
21 | }
22 |
23 | public function testCreatePrimaryIndex()
24 | {
25 | /** @var \Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
26 | $connection = $this->databaseManager->connection('couchbase');
27 | $bucket = $connection->openBucket($this->bucket);
28 | $output = new \Symfony\Component\Console\Output\BufferedOutput();
29 | $this->command->run(
30 | new \Symfony\Component\Console\Input\ArrayInput([
31 | 'bucket' => $this->bucket,
32 | '--ignore' => true,
33 | ]),
34 | $output
35 | );
36 | $fetch = $output->fetch();
37 | $this->assertNotNull($fetch);
38 | $this->assertSame("created PRIMARY INDEX [#primary] for [index_testing] bucket.", trim($fetch));
39 | $bucket->manager()->dropN1qlPrimaryIndex();
40 | sleep(5);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/Console/PrimaryIndexRemoverCommandTest.php:
--------------------------------------------------------------------------------
1 | databaseManager = $this->app['db'];
19 | $this->command = new \Ytake\LaravelCouchbase\Console\PrimaryIndexRemoverCommand($this->databaseManager);
20 | $this->command->setLaravel(new MockApplication);
21 | }
22 |
23 | public function testDropPrimaryIndex()
24 | {
25 | /** @var \Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
26 | $connection = $this->databaseManager->connection('couchbase');
27 | $connection->manager();
28 | $bucket = $connection->openBucket($this->bucket);
29 | $bucket->manager()->createN1qlPrimaryIndex();
30 | $output = new \Symfony\Component\Console\Output\BufferedOutput();
31 | $this->command->run(
32 | new \Symfony\Component\Console\Input\ArrayInput([
33 | 'bucket' => $this->bucket,
34 | ]),
35 | $output
36 | );
37 | $fetch = $output->fetch();
38 | $this->assertNotNull($fetch);
39 | $this->assertSame("dropped PRIMARY INDEX [#primary] for [index_testing] bucket.", trim($fetch));
40 | sleep(5);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/CouchbaseConnectorTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(Cluster::class, $connector->connect([]));
15 | }
16 |
17 | public function testShouldBeClusterWithAuthenticator()
18 | {
19 | $connector = new CouchbaseConnector;
20 | $this->assertInstanceOf(Cluster::class, $connector->connect([
21 | 'host' => 'couchbase://127.0.0.1',
22 | 'user' => 'testing',
23 | 'password' => 'testing',
24 | ]));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/CouchbaseGrammerTest.php:
--------------------------------------------------------------------------------
1 | app['db'];
17 | $this->grammer = new \Ytake\LaravelCouchbase\Query\Grammar;
18 | $processor = new \Ytake\LaravelCouchbase\Query\Processor();
19 | $this->builder = new \Ytake\LaravelCouchbase\Query\Builder(
20 | $databaseManager->connection(),
21 | $this->grammer,
22 | $processor
23 | );
24 | }
25 |
26 | public function testShouldReturnDeleteQueryNotUseKey()
27 | {
28 | $this->builder->from('testing')->where('arg', 1);
29 | $this->assertSame(
30 | 'delete from testing where arg = ? RETURNING *',
31 | $this->grammer->compileDelete($this->builder)
32 | );
33 | }
34 |
35 | public function testShouldReturnDeleteQueryUseKey()
36 | {
37 | $this->builder->from('testing')->where('arg', 1)->key('testing');
38 | $this->assertSame(
39 | 'delete from testing USE KEYS "testing" where arg = ? RETURNING *',
40 | $this->grammer->compileDelete($this->builder)
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/CouchbaseReconnectionTest.php:
--------------------------------------------------------------------------------
1 | app['db'];
15 | /** @var \Ytake\LaravelCouchbase\Database\CouchbaseConnection $couchbase */
16 | $couchbase = $database->connection('couchbase');
17 | $result = $couchbase->table('testing')
18 | ->where('reconnector_testing', 'should return null')->returning(['click'])->get();
19 | $this->assertCount(0, $result);
20 | $this->assertInstanceOf(
21 | \CouchbaseCluster::class,
22 | $couchbase->getCouchbase()
23 | );
24 | $database->disconnect('couchbase');
25 | $property = $this->getProtectProperty($couchbase, 'connection');
26 | $this->assertNull($property->getValue($couchbase));
27 | $couchbase = $database->reconnect('couchbase');
28 | $property = $this->getProtectProperty($couchbase, 'connection');
29 | $this->assertInstanceOf(\CouchbaseCluster::class, $property->getValue($couchbase));
30 | }
31 |
32 | public function testShouldReturnedReconnectableConnectionInstance()
33 | {
34 | /** @var \Illuminate\Database\DatabaseManager $database */
35 | $database = $this->app['db'];
36 | $reConnection = $database->reconnect('couchbase');
37 | $this->assertInstanceOf(\Ytake\LaravelCouchbase\Database\CouchbaseConnection::class, $reConnection);
38 | $result = $reConnection->table('testing')
39 | ->where('reconnector_testing', 'should return null')->returning(['click'])->get();
40 | $this->assertCount(0, $result);
41 | }
42 |
43 | /**
44 | * @param $class
45 | * @param $name
46 | *
47 | * @return ReflectionProperty
48 | * @throws ReflectionException
49 | */
50 | protected function getProtectProperty($class, $name): \ReflectionProperty
51 | {
52 | $class = new \ReflectionClass($class);
53 | $property = $class->getProperty($name);
54 | $property->setAccessible(true);
55 | return $property;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/CouchbaseStoreSerializeTest.php:
--------------------------------------------------------------------------------
1 | app['db']->connection('couchbase')->getCouchbase();
12 | $this->store = new \Ytake\LaravelCouchbase\Cache\CouchbaseStore(
13 | $cluster, 'testing', '', 'testing', 'php'
14 | );
15 | }
16 |
17 | public function testShouldBeArrayWithChangedDecoder()
18 | {
19 | $this->store->add('serialize', ['sample' => 'testing', 'need' => 'array']);
20 | $this->assertInternalType('array', $this->store->get('serialize'));
21 | $this->store->forget('serialize');
22 | }
23 |
24 | public function testShouldBeObjectWithChangedDecoder()
25 | {
26 | $object = new stdClass;
27 | $this->store->add('serialize', $object);
28 | $this->assertInstanceOf('stdClass', $this->store->get('serialize'));
29 | $this->store->forget('serialize');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/CouchbaseStoreTest.php:
--------------------------------------------------------------------------------
1 | app['db']->connection('couchbase')->getCouchbase();
12 | $this->store = new \Ytake\LaravelCouchbase\Cache\CouchbaseStore(
13 | $cluster, 'testing', '', 'testing'
14 | );
15 | }
16 |
17 | public function testAddAlreadyKey()
18 | {
19 | $this->assertTrue($this->store->add('test', 'test', 120));
20 | $this->assertFalse($this->store->add('test', 'test', 120));
21 | $this->store->forget('test');
22 | }
23 |
24 | public function testAddArrayableKey()
25 | {
26 | $this->store->add(['test', 'test2'], 'test', 120);
27 | $result = $this->store->get(['test', 'test2']);
28 | foreach ($result as $row) {
29 | $this->assertSame('test', $row);
30 | }
31 |
32 | $this->store->forget(['test', 'test2']);
33 | }
34 |
35 | public function testPrefix()
36 | {
37 | $this->assertSame('testing:', $this->store->getPrefix());
38 | }
39 |
40 | public function testNotFoundKey()
41 | {
42 | $this->assertNull($this->store->get('notFoundTest'));
43 | }
44 |
45 | public function testFlushException()
46 | {
47 | $this->store->add('test1234', 'test', 120);
48 | $this->store->flush();
49 | $this->assertNull($this->store->get('test1234'));
50 | }
51 |
52 | public function testIncrement()
53 | {
54 | $this->assertSame(1, $this->store->increment('test', 1));
55 | $this->assertSame(11, $this->store->increment('test', 10));
56 | $this->store->forget('test');
57 | }
58 |
59 | public function testDecrement()
60 | {
61 | $this->assertSame(-1, $this->store->decrement('test', 1));
62 | $this->assertSame(-11, $this->store->decrement('test', 10));
63 | $this->assertSame(-21, $this->store->decrement('test', -10));
64 | $this->store->forget('test');
65 | }
66 |
67 | public function testUpsert()
68 | {
69 | $value = ['message' => 'testing'];
70 | $this->store->put('test', json_encode($value), 400);
71 | $this->assertSame(json_encode($value), $this->store->get('test'));
72 | $value = ['message' => 'testing2'];
73 | $this->store->put('test', json_encode($value), 400);
74 | $this->assertSame(json_encode($value), $this->store->get('test'));
75 | $this->store->forget('test');
76 | }
77 |
78 | public function testCacheableComponentInstance()
79 | {
80 | /** @var Illuminate\Cache\Repository $cache */
81 | $cache = $this->app['cache']->driver('couchbase');
82 | $this->assertInstanceOf(get_class($this->store), $cache->getStore());
83 | $cache->add('test', 'testing', 400);
84 | $this->assertSame('testing', $this->store->get('test'));
85 | $this->store->forget('test');
86 | }
87 |
88 | public function testShouldBeLockedTheCache()
89 | {
90 | $this->store->forget('cache:lock');
91 | $result = $this->store->lock('cache:lock', 600)->get();
92 | $this->assertTrue($result);
93 | $resultSecond = $this->store->lock('cache:lock', 600)->get();
94 | $this->assertFalse($resultSecond);
95 |
96 | $this->store->lock('cache:lock:two', 600)->get(function () {});
97 | $this->assertNull($this->store->get('cache:lock:two'));
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/tests/CouchbaseTestCase.php:
--------------------------------------------------------------------------------
1 | createApplicationContainer();
18 | }
19 |
20 | /**
21 | * @return \Illuminate\Config\Repository
22 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
23 | */
24 | protected function registerConfigure()
25 | {
26 | $filesystem = new \Illuminate\Filesystem\Filesystem;
27 | $this->app['config']->set(
28 | "database",
29 | $filesystem->getRequire(__DIR__ . '/config/database.php')
30 | );
31 | $this->app['config']->set(
32 | "cache",
33 | $filesystem->getRequire(__DIR__ . '/config/cache.php')
34 | );
35 | $this->app['config']->set(
36 | "session",
37 | $filesystem->getRequire(__DIR__ . '/config/session.php')
38 | );
39 | $this->app['config']->set(
40 | "queue",
41 | $filesystem->getRequire(__DIR__ . '/config/queue.php')
42 | );
43 | $this->app['config']->set(
44 | 'couchbase',
45 | $filesystem->getRequire(__DIR__ . '/config/couchbase.php')
46 | );
47 | $this->app['files'] = $filesystem;
48 | }
49 |
50 | protected function registerDatabase()
51 | {
52 | Model::clearBootedModels();
53 | $this->app->singleton('db.factory', function ($app) {
54 | return new ConnectionFactory($app);
55 | });
56 | $this->app->singleton('db', function ($app) {
57 | return new DatabaseManager($app, $app['db.factory']);
58 | });
59 | $this->app->bind('db.connection', function ($app) {
60 | return $app['db']->connection();
61 | });
62 | }
63 |
64 | protected function registerCache()
65 | {
66 | $this->app->singleton('cache', function ($app) {
67 | return new \Illuminate\Cache\CacheManager($app);
68 | });
69 | $this->app->singleton('cache.store', function ($app) {
70 | return $app['cache']->driver();
71 | });
72 |
73 | $this->app->singleton('memcached.connector', function () {
74 | return new \Illuminate\Cache\MemcachedConnector();
75 | });
76 | }
77 |
78 | protected function createApplicationContainer()
79 | {
80 | $this->app = new \TestContainer();
81 |
82 | $this->app->singleton('config', function () {
83 | return new \Illuminate\Config\Repository;
84 | });
85 | $this->registerConfigure();
86 | $queueProvider = new \Illuminate\Queue\QueueServiceProvider($this->app);
87 | $queueProvider->register();
88 | $sessionProvider = new \Illuminate\Session\SessionServiceProvider($this->app);
89 | $sessionProvider->register();
90 | $this->registerDatabase();
91 | $this->registerCache();
92 | $couchbaseProvider = new ServiceProvider($this->app);
93 | $couchbaseProvider->register();
94 | $couchbaseProvider->boot();
95 | $this->app->bind(
96 | \Illuminate\Container\Container::class,
97 | function () {
98 | return $this->app;
99 | }
100 | );
101 | (new \Illuminate\Events\EventServiceProvider($this->app))->register();
102 | \Illuminate\Container\Container::setInstance($this->app);
103 | }
104 |
105 | protected function tearDown()
106 | {
107 | $this->app = null;
108 | }
109 |
110 | /**
111 | * @param string $bucket
112 | *
113 | * @return Couchbase\ClusterManager
114 | */
115 | protected function createBucket($bucket)
116 | {
117 | $cluster = new \Couchbase\Cluster('127.0.0.1');
118 | $clusterManager = $cluster->manager('Administrator', 'Administrator');
119 | $clusterManager->createBucket($bucket,
120 | ['bucketType' => 'couchbase', 'saslPassword' => '', 'flushEnabled' => true]);
121 | sleep(5);
122 | return $clusterManager;
123 | }
124 |
125 | /**
126 | * @param CouchbaseClusterManager $clusterManager
127 | * @param string $bucket
128 | */
129 | protected function removeBucket(\CouchbaseClusterManager $clusterManager, $bucket)
130 | {
131 | $clusterManager->removeBucket($bucket);
132 | }
133 | }
134 |
135 | class TestContainer extends \Illuminate\Container\Container
136 | {
137 | public function version()
138 | {
139 | return '5.5.1';
140 | }
141 | }
142 |
143 | class ServiceProvider extends \Ytake\LaravelCouchbase\CouchbaseServiceProvider
144 | {
145 | public function register()
146 | {
147 | $this->registerCouchbaseComponent();
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/tests/DatabaseTest.php:
--------------------------------------------------------------------------------
1 | connection = new \Ytake\LaravelCouchbase\Database\CouchbaseConnection(
12 | $this->app['config']->get('database.connections.couchbase'),
13 | 'couchbase'
14 | );
15 | }
16 |
17 | /**
18 | * @expectedException \Ytake\LaravelCouchbase\Exceptions\NotSupportedException
19 | */
20 | public function testNotSupportedRollback()
21 | {
22 | $this->connection->rollBack(1);
23 | }
24 |
25 | /**
26 | * @expectedException \Ytake\LaravelCouchbase\Exceptions\NotSupportedException
27 | */
28 | public function testNotSupportedTransaction()
29 | {
30 | $this->connection->transaction(function () {
31 |
32 | });
33 | }
34 |
35 | /**
36 | * @expectedException \Ytake\LaravelCouchbase\Exceptions\NotSupportedException
37 | */
38 | public function testNotSupportedBeginTransaction()
39 | {
40 | $this->connection->beginTransaction();
41 | }
42 |
43 | /**
44 | * @expectedException \Ytake\LaravelCouchbase\Exceptions\NotSupportedException
45 | */
46 | public function testNotSupportedCommit()
47 | {
48 | $this->connection->commit();
49 | }
50 |
51 | public function testCallableChangeToConsistency()
52 | {
53 | $this->connection->callableConsistency(\Couchbase\N1qlQuery::REQUEST_PLUS,
54 | function (\Ytake\LaravelCouchbase\Database\CouchbaseConnection $con) {
55 | \Closure::bind(function () {
56 | \PHPUnit\Framework\Assert::assertSame(\Couchbase\N1qlQuery::REQUEST_PLUS, $this->consistency);
57 | }, $con, get_class($con))->__invoke();
58 | }
59 | );
60 | \Closure::bind(function () {
61 | \PHPUnit\Framework\Assert::assertSame(\Couchbase\N1qlQuery::NOT_BOUNDED, $this->consistency);
62 | }, $this->connection, get_class($this->connection))->__invoke();
63 | }
64 |
65 | public function testShouldReturnConfigurationArray()
66 | {
67 | $bucket = $this->connection->openBucket('testing');
68 | static::assertInternalType('array', $this->connection->getOptions($bucket));
69 | }
70 |
71 | public function testShouldBeCouchbaseInstanceForReconnection()
72 | {
73 | /** @var Ytake\LaravelCouchbase\Database\CouchbaseConnection $db */
74 | $db = $this->app['db']->connection();
75 | $this->assertSame('couchbase', $db->getName());
76 | $bucket = $db->bucket('testing');
77 | $db->disconnect();
78 | $this->app['db']->reconnect();
79 | $this->assertInstanceOf(get_class($bucket), $this->app['db']->connection()->bucket('testing'));
80 | /** @var \Illuminate\Database\DatabaseManager $manager */
81 | $manager = $this->app['db'];
82 | $this->assertInstanceOf(Ytake\LaravelCouchbase\Database\CouchbaseConnection::class, $manager->reconnect());
83 | $this->assertInstanceOf(Ytake\LaravelCouchbase\Database\CouchbaseConnection::class, $db->setPdo(null));
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/tests/DeleteQueryTest.php:
--------------------------------------------------------------------------------
1 | connection = new \Ytake\LaravelCouchbase\Database\CouchbaseConnection(
12 | $this->app['config']->get('database.connections.couchbase'),
13 | 'couchbase'
14 | );
15 | }
16 |
17 | public function testInsertAndDeleteQueries()
18 | {
19 | $value = [
20 | 'click' => 'to edit',
21 | 'content' => 'testing'
22 | ];
23 | $key = 'insert:and:delete';
24 | /** @var Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
25 | $connection = $this->app['db']->connection('couchbase');
26 | $result = $connection->table('testing')->key($key)->insert($value);
27 | $this->assertInstanceOf('stdClass', $result);
28 | sleep(1);
29 | $deleteReturning = $connection->table('testing')->key($key)
30 | ->where('click', 'to edit')->returning(['click'])->delete();
31 | $this->assertSame('to edit', $deleteReturning->click);
32 | }
33 |
34 | public function testInsertAndNotDeleteQueries()
35 | {
36 | $value = [
37 | 'click' => 'to edit',
38 | 'content' => 'testing'
39 | ];
40 | $key = 'insert:and:delete';
41 | /** @var Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
42 | $connection = $this->app['db']->connection('couchbase');
43 | $connection->table('testing')->key($key)->insert($value);
44 | $this->assertInternalType('array', $connection->metrics());
45 | $connection->openBucket('testing')->manager()->flush();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/DesignDocumentTest.php:
--------------------------------------------------------------------------------
1 | assertArrayHasKey('testing', $decodeDocument);
25 | $this->assertArrayHasKey('map', $decodeDocument['testing']);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/MemcachedBucketTest.php:
--------------------------------------------------------------------------------
1 | repository = $this->app['cache']->driver('couchbase-memcached');
13 | }
14 |
15 | public function testShouldReturnRepositoryInstance()
16 | {
17 | $this->assertInstanceOf('Illuminate\Cache\Repository', $this->repository);
18 | }
19 |
20 | public function testShouldReturnSameCacheAccess()
21 | {
22 | $this->repository->add('memcached-testing', 'couchbase', 60);
23 | $this->assertSame('couchbase', $this->repository->get('memcached-testing'));
24 | $this->repository->forget('memcached-testing');
25 | $this->assertNull($this->repository->get('memcached-testing'));
26 | }
27 |
28 | public function testShouldReturnIncrementalValues()
29 | {
30 | $this->repository->increment('memcached-testing');
31 | $this->assertSame(1, $this->repository->get('memcached-testing'));
32 |
33 | $this->repository->increment('memcached-testing', 100);
34 | $this->assertSame(101, $this->repository->get('memcached-testing'));
35 | $this->repository->decrement('memcached-testing', 100);
36 | $this->assertSame(1, $this->repository->get('memcached-testing'));
37 | $this->repository->decrement('memcached-testing', 100);
38 | $this->assertSame(0, $this->repository->get('memcached-testing'));
39 | $this->repository->forget('memcached-testing');
40 |
41 | $this->repository->decrement('memcached-testing', 100);
42 | $this->assertSame(0, $this->repository->get('memcached-testing'));
43 | $this->repository->forget('memcached-testing');
44 | }
45 |
46 | public function testShouldReturnNullFlushRecord()
47 | {
48 | $this->repository->add('memcached-testing', 'couchbase', 60);
49 | $this->repository->decrement('memcached-testing-decrement', 100);
50 | $this->repository->increment('memcached-testing-increment', 100);
51 | $this->repository->flush();
52 | $this->assertNull($this->repository->get('memcached-testing'));
53 | $this->assertNull($this->repository->get('memcached-testing-decrement'));
54 | $this->assertNull($this->repository->get('memcached-testing-increment'));
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/tests/MemcachedConnectorTest.php:
--------------------------------------------------------------------------------
1 | connect(
9 | [
10 | ['host' => '127.0.0.1', 'port' => '11255', 'weight' => 100],
11 | ['host' => '127.0.0.1', 'port' => '11255', 'weight' => 100],
12 | ]
13 | );
14 |
15 | $this->assertInstanceOf(\Memcached::class, $memcached);
16 | }
17 |
18 | public function testShouldReturnMemcachedInstanceForBucket()
19 | {
20 | /** @var \Illuminate\Cache\Repository $cache */
21 | $cache = $this->app['cache']->driver('couchbase-memcached');
22 | $this->assertInstanceOf('Illuminate\Cache\Repository', $cache);
23 | $cache->add('testing', 'testing', 20);
24 | $this->assertEquals('testing', $cache->get('testing'));
25 | $cache->add('testing-array', ['testing'], 20);
26 | $this->assertInternalType('array', $cache->get('testing-array'));
27 | $cache = $this->app['cache']->driver('memcached');
28 | $this->assertInstanceOf('Illuminate\Cache\Repository', $cache);
29 | $cache->flush();
30 | $this->assertNull($cache->get('testing-array'));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/MockApplication.php:
--------------------------------------------------------------------------------
1 | app['session'];
9 | /** @var \Illuminate\Session\Store $driver */
10 | $driver = $session->driver('couchbase');
11 | $this->assertInstanceOf(\Illuminate\Session\Store::class, $driver);
12 | $driver->put('session:data', 'hello');
13 | $this->assertSame('hello', $driver->get('session:data'));
14 | $driver->flush();
15 | $this->assertNull($driver->get('session:data'));
16 | }
17 |
18 | public function testCacheDriver()
19 | {
20 | /** @var Illuminate\Cache\CacheManager $cache */
21 | $cache = $this->app['cache'];
22 | /** @var Illuminate\Cache\Repository $repository */
23 | $repository = $cache->driver('couchbase');
24 | $this->assertInstanceOf(get_class($repository), $cache->driver('couchbase2'));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Query/ViewTest.php:
--------------------------------------------------------------------------------
1 | connection = $this->app['db']->connection();
34 |
35 | $this->databaseManager = $this->app['db'];
36 | $this->config = $this->app['config'];
37 | $this->command = new DesignCreatorCommand(
38 | $this->databaseManager,
39 | $this->config->get('couchbase.design')
40 | );
41 | $this->command->setLaravel(new MockApplication);
42 | }
43 |
44 | /**
45 | * @see \Ytake\LaravelCouchbase\Query\View::from()
46 | * @see \Ytake\LaravelCouchbase\Query\View::execute()
47 | */
48 | public function testItShouldBeStdClass()
49 | {
50 | /** @var \Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
51 | $connection = $this->databaseManager->connection('couchbase');
52 | $bucket = $connection->openBucket($this->bucket);
53 | $bucket->manager()->removeDesignDocument('dev_testing');
54 | $bucket->manager()->removeDesignDocument('dev_testing_name');
55 | sleep(6);
56 | $output = new BufferedOutput();
57 | $this->command->run(
58 | new ArrayInput([
59 | 'bucket' => $this->bucket,
60 | ]),
61 | $output
62 | );
63 | sleep(4);
64 | /** @var Illuminate\Events\Dispatcher $dispatcher */
65 | $dispatcher = $this->app['events'];
66 | $dispatcher->listen(\Ytake\LaravelCouchbase\Events\ViewQuerying::class, function ($instance) {
67 | $this->assertInstanceOf(\Ytake\LaravelCouchbase\Events\ViewQuerying::class, $instance);
68 | });
69 | $view = $this->connection->view("testing");
70 | $query = $view->from("dev_testing", "testing");
71 | $result = $view->execute($query);
72 | $this->assertInstanceOf('stdClass', $result);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/tests/Queue/QueueCouchbaseConnectorTest.php:
--------------------------------------------------------------------------------
1 | app['db']->connection('couchbase');
19 |
20 | $schema = $connection->getSchemaBuilder();
21 | $schema->create('jobs', function (\Ytake\LaravelCouchbase\Schema\Blueprint $blueprint) {
22 | $blueprint->primaryIndex();
23 | });
24 | $connection->openBucket(self::BUCKET)->manager()->flush();
25 | }
26 |
27 | public function testQueueConnect()
28 | {
29 | /** @var \Illuminate\Queue\QueueManager $queue */
30 | $queue = $this->app['queue'];
31 | $connect = $queue->connection('couchbase');
32 | $this->assertInstanceOf(\Ytake\LaravelCouchbase\Queue\CouchbaseQueue::class, $connect);
33 | }
34 |
35 | public function testShouldAppendQueueWorkTasks()
36 | {
37 | /** @var \Illuminate\Queue\QueueManager $queue */
38 | $queue = $this->app['queue'];
39 | /** @var \Ytake\LaravelCouchbase\Queue\CouchbaseQueue $connect */
40 | $connect = $queue->connection('couchbase');
41 | /** @var CouchbaseConnection $database */
42 | $database = $connect->getDatabase();
43 | $database->openBucket(self::BUCKET)->manager()->flush();
44 | sleep(4);
45 | $database->openBucket(self::BUCKET);
46 | $this->assertNull($connect->pop());
47 | $connect->bulk(['testing:queue1', 'testing:queue2']);
48 | sleep(5);
49 | /** @var Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
50 | $connection = $this->app['db']->connection('couchbase');
51 | $this->assertSame(2, $connection->table(self::BUCKET)->where('queue', 'default')->count());
52 | /** @var Illuminate\Queue\Jobs\DatabaseJob $databaseJob */
53 | $databaseJob = $connect->pop();
54 | $this->assertInstanceOf(Illuminate\Queue\Jobs\DatabaseJob::class, $databaseJob);
55 | $databaseJob->delete();
56 | sleep(1);
57 | $this->assertSame(1, $connection->table(self::BUCKET)->where('queue', 'default')->count());
58 | }
59 |
60 | public function tearDown()
61 | {
62 | /** @var Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
63 | $connection = $this->app['db']->connection('couchbase');
64 | $this->removeBucket($connection->manager(), self::BUCKET);
65 | parent::tearDown();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/tests/Schema/BlueprintTest.php:
--------------------------------------------------------------------------------
1 | connection = $this->app['db']->connection();
17 | }
18 |
19 | public function testBlueprintSchemaBuild()
20 | {
21 | $schema = $this->connection->getSchemaBuilder();
22 | $schema->create('sample', function (\Ytake\LaravelCouchbase\Schema\Blueprint $blueprint) {
23 | try {
24 | $blueprint->dropPrimary();
25 | }catch (\Exception $e) {
26 |
27 | }
28 | try {
29 | $blueprint->dropIndex("secondary");
30 | }catch (\Exception $e) {
31 |
32 | }
33 | $blueprint->primaryIndex();
34 | $blueprint->index(["message"], "secondary");
35 | });
36 | $indexes = $this->connection->openBucket('sample')->manager()->listN1qlIndexes();
37 | $this->assertNotCount(0, $indexes);
38 | $this->removeBucket($this->connection->manager(), 'sample');
39 | sleep(5);
40 | }
41 |
42 | public function testBlueprintSchemaBuildAndDropIndexes()
43 | {
44 | $schema = $this->connection->getSchemaBuilder();
45 | $schema->create('sample', function (\Ytake\LaravelCouchbase\Schema\Blueprint $blueprint) {
46 | try {
47 | $blueprint->dropPrimary();
48 | }catch (\Exception $e) {
49 |
50 | }
51 | try {
52 | $blueprint->dropIndex("secondary");
53 | }catch (\Exception $e) {
54 |
55 | }
56 | $blueprint->primaryIndex();
57 | $blueprint->index(["message"], "secondary");
58 | $blueprint->dropPrimary();
59 | $blueprint->dropIndex("secondary");
60 | });
61 | $indexes = $this->connection->openBucket('sample')->manager()->listN1qlIndexes();
62 | $this->assertCount(0, $indexes);
63 | $this->removeBucket($this->connection->manager(), 'sample');
64 | sleep(5);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/Schema/BuilderTest.php:
--------------------------------------------------------------------------------
1 | connection = $this->app['db']->connection();
17 | }
18 |
19 | public function testShouldReturnSchemaBuilderInstance()
20 | {
21 | $schemaBuilder = $this->connection->getSchemaBuilder();
22 | $this->assertInstanceOf(\Ytake\LaravelCouchbase\Schema\Builder::class, $schemaBuilder);
23 | }
24 |
25 | public function testShouldReturnFalseSpecifiedNotExistsBucket()
26 | {
27 | $this->assertFalse($this->connection->getSchemaBuilder()->hasTable("sample1"));
28 | }
29 |
30 | public function testShouldReturnTrueSpecifiedExistsBucket()
31 | {
32 | $clusterManager = $this->createBucket("sample1");
33 | $this->assertTrue($this->connection->getSchemaBuilder()->hasTable("sample1"));
34 | $this->removeBucket($clusterManager, "sample1");
35 | }
36 |
37 | public function testShouldReturnTrue()
38 | {
39 | $clusterManager = $this->createBucket("sample1");
40 | $schemaBuilder = $this->connection->getSchemaBuilder();
41 | $this->assertTrue($schemaBuilder->hasColumn("sample1", "testing"));
42 | $this->assertTrue($schemaBuilder->hasColumns("sample1", ["testing"]));
43 | $this->removeBucket($clusterManager, "sample1");
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/TaggingCacheStoreTest.php:
--------------------------------------------------------------------------------
1 | app['db']->connection('couchbase')->getCouchbase();
15 | $this->store = new \Ytake\LaravelCouchbase\Cache\CouchbaseStore(
16 | $cluster, 'testing', '', 'testing'
17 | );
18 | }
19 |
20 | public function testAddTaggableKeys()
21 | {
22 | $this->store->tags(['testing1', 'testing2'])->add('tagging', 'test', 20);
23 | $this->assertSame('test', $this->store->tags(['testing1', 'testing2'])->get('tagging'));
24 | $this->store->tags(['testing4'])->add('tagging2', 'test2', 20);
25 | $this->store->tags(['testing1', 'testing2'])->flush();
26 | $this->assertNull($this->store->tags(['testing1', 'testing2'])->get('tagging'));
27 | $this->assertSame('test2', $this->store->tags(['testing4'])->get('tagging2'));
28 | $this->store->tags(['testing4'])->flush();
29 | $this->assertNull($this->store->tags(['testing4'])->get('tagging'));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/UpdateQueryTest.php:
--------------------------------------------------------------------------------
1 | connection = new \Ytake\LaravelCouchbase\Database\CouchbaseConnection(
16 | $this->app['config']->get('database.connections.couchbase'),
17 | 'couchbase'
18 | );
19 | }
20 |
21 | public function testInsertAndUpdateQueries()
22 | {
23 | $value = [
24 | 'click' => 'to edit',
25 | 'content' => 'testing',
26 | ];
27 | $key = 'insert';
28 | /** @var Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
29 | $connection = $this->app['db']->connection('couchbase');
30 | $cluster = $connection->getCouchbase();
31 | $store = new \Ytake\LaravelCouchbase\Cache\CouchbaseStore(
32 | $cluster, 'testing', '', 'testing'
33 | );
34 | $store->flush();
35 | $result = $connection->table('testing')->key($key)->insert($value);
36 | $this->assertInstanceOf('stdClass', $result);
37 |
38 | $result = $connection->table('testing')->key($key)
39 | ->where('click', 'to edit')->update(
40 | ['click' => 'testing edit']
41 | );
42 | sleep(10);
43 | $this->assertInstanceOf(\Illuminate\Support\Collection::class, $connection->table('testing')->get());
44 | $generator = $connection->table('testing')->cursor();
45 | $this->assertInstanceOf(\Generator::class, $generator);
46 | $this->assertInstanceOf('stdClass', $result);
47 | $this->assertSame('testing edit', $result->click);
48 | $connection->openBucket('testing')->manager()->flush();
49 | }
50 |
51 | public function testInsertAndNotUpdateQueries()
52 | {
53 | $value = [
54 | 'click' => 'to edit',
55 | 'content' => 'testing',
56 | ];
57 | $key = 'insert:no';
58 | /** @var Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
59 | $connection = $this->app['db']->connection('couchbase');
60 | $result = $connection->table('testing')->key($key)->insert($value);
61 | $this->assertInstanceOf('stdClass', $result);
62 | sleep(1);
63 | /** @var Illuminate\Events\Dispatcher $dispatcher */
64 | $dispatcher = $this->app['events'];
65 | $dispatcher->listen(QueryPrepared::class, function ($instance) {
66 | /** @var QueryPrepared $instance */
67 | static::assertInstanceOf(QueryPrepared::class, $instance);
68 | static::assertInstanceOf(\Couchbase\N1qlQuery::class, $instance->getQuery());
69 | });
70 | $dispatcher->listen(ResultReturning::class, function ($instance) {
71 | /** @var ResultReturning $instance */
72 | static::assertInstanceOf(ResultReturning::class, $instance);
73 | static::assertInstanceOf(\stdClass::class, $instance->returning());
74 | });
75 | $this->assertSame(null, $connection->table('testing')->key($key)->where('clicking', 'to edit')->first());
76 | $connection->openBucket('testing')->manager()->flush();
77 | }
78 |
79 | public function testUpsertQuery()
80 | {
81 | $value = [
82 | 'click' => 'to edit',
83 | 'content' => 'testing',
84 | ];
85 | $key = 'upsert:click:content';
86 | /** @var Ytake\LaravelCouchbase\Database\CouchbaseConnection $connection */
87 | $connection = $this->app['db']->connection('couchbase');
88 | $result = $connection->table('testing')->key($key)->upsert($value);
89 | $this->assertInstanceOf('stdClass', $result);
90 | $result = $connection->table('testing')->key($key)->upsert([
91 | 'click' => 'to',
92 | 'content' => 'testing for upsert',
93 | ]);
94 | $this->assertSame('testing for upsert', $result->content);
95 | $connection->openBucket('testing')->manager()->flush();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/tests/bin/memcached.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | if (php --version | grep -i HipHop > /dev/null); then
4 | echo "skipping memcache on HHVM"
5 | else
6 | mkdir -p ~/.phpenv/versions/$(phpenv version-name)/etc
7 | echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
8 | fi
9 |
--------------------------------------------------------------------------------
/tests/config/app.php:
--------------------------------------------------------------------------------
1 | 'testing1testing1testing1testing1',
5 |
6 | 'cipher' => 'AES-256-CBC',
7 | ];
8 |
--------------------------------------------------------------------------------
/tests/config/cache.php:
--------------------------------------------------------------------------------
1 | 'couchbase',
5 | 'stores' => [
6 | 'couchbase' => [
7 | 'driver' => 'couchbase',
8 | 'bucket' => 'testing',
9 | 'bucket_password' => '',
10 | ],
11 | 'couchbase2' => [
12 | 'driver' => 'couchbase',
13 | 'bucket' => 'testing',
14 | 'bucket_password' => '',
15 | ],
16 | 'couchbase-memcached' => [
17 | 'driver' => 'couchbase-memcached',
18 | 'servers' => [
19 | [
20 | 'host' => '127.0.0.1',
21 | 'port' => 11255,
22 | 'weight' => 100,
23 | 'bucket' => 'memcache-couch',
24 | 'options' => [
25 |
26 | ],
27 | ],
28 | ],
29 | 'sasl' => [
30 | 'Administrator',
31 | 'Administrator',
32 | ],
33 | ],
34 | 'couchbase-memcached_second' => [
35 | 'driver' => 'couchbase-memcached',
36 | 'servers' => [
37 | [
38 | 'host' => '127.0.0.1',
39 | 'port' => 11255,
40 | 'weight' => 100,
41 | 'bucket' => 'memcache-couch',
42 | 'options' => [
43 |
44 | ],
45 | ],
46 | ],
47 | 'sasl' => [
48 | 'Administrator',
49 | 'Administrator',
50 | ],
51 | ],
52 | 'memcached' => [
53 | 'driver' => 'memcached',
54 | 'servers' => [
55 | [
56 | 'host' => '127.0.0.1',
57 | 'port' => 11211,
58 | 'weight' => 100,
59 | ],
60 | ],
61 | ],
62 | ],
63 | 'prefix' => 'testing',
64 | ];
65 |
--------------------------------------------------------------------------------
/tests/config/couchbase.php:
--------------------------------------------------------------------------------
1 | [
20 | 'dev_testing_name' => [
21 | 'views' => [
22 | 't' => [
23 | 'map' => file_get_contents(__DIR__ . '/../resources/sample.ddoc'),
24 | ],
25 | ],
26 | ],
27 | 'dev_testing' => [
28 | 'views' => [
29 | 'testing' => [
30 | 'map' => file_get_contents(__DIR__ . '/../resources/sample.ddoc'),
31 | ],
32 | ],
33 | ],
34 | ],
35 | ];
36 |
--------------------------------------------------------------------------------
/tests/config/database.php:
--------------------------------------------------------------------------------
1 | PDO::FETCH_CLASS,
4 | 'default' => 'couchbase',
5 | 'connections' => [
6 | 'couchbase' => [
7 | 'driver' => 'couchbase',
8 | 'host' => 'couchbase://127.0.0.1?dnssrv=false',
9 | // 'bucket_password' => null,
10 | // 'bucket' => '',
11 | 'administrator' => [
12 | 'user' => 'Administrator',
13 | 'password' => 'Administrator',
14 | ],
15 | 'user' => 'Administrator',
16 | 'password' => 'Administrator',
17 | ],
18 | /*
19 | 'testing' => [
20 | 'driver' => 'couchbase',
21 | 'host' => 'couchbase://127.0.0.1?detailed_errcodes=1&http_poolsize=0&operation_timeout=4',
22 | // 'bucket_password' => null,
23 | // 'bucket' => '',
24 | 'administrator' => [
25 | 'user' => 'Administrator',
26 | 'password' => 'Administrator',
27 | ],
28 | 'user' => 'testing',
29 | 'password' => 'testing',
30 | ],
31 | */
32 | ],
33 | 'migrations' => 'migrations',
34 | ];
35 |
--------------------------------------------------------------------------------
/tests/config/queue.php:
--------------------------------------------------------------------------------
1 | 'couchbase',
6 |
7 | 'connections' => [
8 |
9 | 'couchbase' => [
10 | 'driver' => 'couchbase',
11 | 'bucket' => 'jobs',
12 | 'queue' => 'default',
13 | 'retry_after' => 90,
14 | ],
15 | ],
16 | ];
17 |
--------------------------------------------------------------------------------
/tests/config/session.php:
--------------------------------------------------------------------------------
1 | 'couchbase',
6 |
7 | 'lifetime' => 120,
8 |
9 | 'expire_on_close' => false,
10 |
11 | 'encrypt' => false,
12 |
13 | 'connection' => null,
14 |
15 | 'table' => 'sessions',
16 |
17 | 'lottery' => [2, 100],
18 |
19 | 'cookie' => 'laravel_session',
20 |
21 | 'path' => '/',
22 |
23 | 'domain' => null,
24 |
25 | 'secure' => false,
26 |
27 | ];
28 |
--------------------------------------------------------------------------------
/tests/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/tests/resources/sample.ddoc:
--------------------------------------------------------------------------------
1 | function (doc, meta) {
2 | emit(meta.id, null);
3 | }
4 |
--------------------------------------------------------------------------------