├── .github
└── workflows
│ └── php.yml
├── .gitignore
├── Changelog.md
├── Hacking.md
├── LICENSE
├── Makefile
├── README.md
├── composer.json
├── composer.lock
├── docs
├── 404.html
├── class-LeanCloud.ACL.html
├── class-LeanCloud.AppRouter.html
├── class-LeanCloud.BatchRequestError.html
├── class-LeanCloud.Bytes.html
├── class-LeanCloud.Client.html
├── class-LeanCloud.CloudException.html
├── class-LeanCloud.Engine.Cloud.html
├── class-LeanCloud.Engine.FunctionError.html
├── class-LeanCloud.Engine.LaravelEngine.html
├── class-LeanCloud.Engine.LeanEngine.html
├── class-LeanCloud.Engine.SlimEngine.html
├── class-LeanCloud.File.html
├── class-LeanCloud.GeoPoint.html
├── class-LeanCloud.LeanObject.html
├── class-LeanCloud.MIMEType.html
├── class-LeanCloud.Operation.ArrayOperation.html
├── class-LeanCloud.Operation.DeleteOperation.html
├── class-LeanCloud.Operation.IOperation.html
├── class-LeanCloud.Operation.IncrementOperation.html
├── class-LeanCloud.Operation.RelationOperation.html
├── class-LeanCloud.Operation.SetOperation.html
├── class-LeanCloud.Push.html
├── class-LeanCloud.Query.html
├── class-LeanCloud.Region.html
├── class-LeanCloud.Relation.html
├── class-LeanCloud.Role.html
├── class-LeanCloud.RouteCache.html
├── class-LeanCloud.SMS.html
├── class-LeanCloud.SaveOption.html
├── class-LeanCloud.Storage.CookieStorage.html
├── class-LeanCloud.Storage.IStorage.html
├── class-LeanCloud.Storage.SessionStorage.html
├── class-LeanCloud.Uploader.QCloudUploader.html
├── class-LeanCloud.Uploader.QiniuUploader.html
├── class-LeanCloud.Uploader.S3Uploader.html
├── class-LeanCloud.Uploader.SimpleUploader.html
├── class-LeanCloud.User.html
├── elementlist.js
├── index.html
├── namespace-LeanCloud.Engine.html
├── namespace-LeanCloud.Operation.html
├── namespace-LeanCloud.Storage.html
├── namespace-LeanCloud.Uploader.html
├── namespace-LeanCloud.html
├── resources
│ ├── collapsed.png
│ ├── combined.js
│ ├── footer.png
│ ├── inherit.png
│ ├── resize.png
│ ├── sort.png
│ ├── style.css
│ ├── tree-cleaner.png
│ ├── tree-hasnext.png
│ ├── tree-last.png
│ └── tree-vertical.png
├── source-class-LeanCloud.ACL.html
├── source-class-LeanCloud.AppRouter.html
├── source-class-LeanCloud.BatchRequestError.html
├── source-class-LeanCloud.Bytes.html
├── source-class-LeanCloud.Client.html
├── source-class-LeanCloud.CloudException.html
├── source-class-LeanCloud.Engine.Cloud.html
├── source-class-LeanCloud.Engine.FunctionError.html
├── source-class-LeanCloud.Engine.LaravelEngine.html
├── source-class-LeanCloud.Engine.LeanEngine.html
├── source-class-LeanCloud.Engine.SlimEngine.html
├── source-class-LeanCloud.File.html
├── source-class-LeanCloud.GeoPoint.html
├── source-class-LeanCloud.LeanObject.html
├── source-class-LeanCloud.MIMEType.html
├── source-class-LeanCloud.Operation.ArrayOperation.html
├── source-class-LeanCloud.Operation.DeleteOperation.html
├── source-class-LeanCloud.Operation.IOperation.html
├── source-class-LeanCloud.Operation.IncrementOperation.html
├── source-class-LeanCloud.Operation.RelationOperation.html
├── source-class-LeanCloud.Operation.SetOperation.html
├── source-class-LeanCloud.Push.html
├── source-class-LeanCloud.Query.html
├── source-class-LeanCloud.Region.html
├── source-class-LeanCloud.Relation.html
├── source-class-LeanCloud.Role.html
├── source-class-LeanCloud.RouteCache.html
├── source-class-LeanCloud.SMS.html
├── source-class-LeanCloud.SaveOption.html
├── source-class-LeanCloud.Storage.CookieStorage.html
├── source-class-LeanCloud.Storage.IStorage.html
├── source-class-LeanCloud.Storage.SessionStorage.html
├── source-class-LeanCloud.Uploader.QCloudUploader.html
├── source-class-LeanCloud.Uploader.QiniuUploader.html
├── source-class-LeanCloud.Uploader.S3Uploader.html
├── source-class-LeanCloud.Uploader.SimpleUploader.html
└── source-class-LeanCloud.User.html
├── fabfile.py
├── phpunit.xml
├── release.sh
├── src
├── LeanCloud
│ ├── ACL.php
│ ├── AppRouter.php
│ ├── BatchRequestError.php
│ ├── Bytes.php
│ ├── Client.php
│ ├── CloudException.php
│ ├── Engine
│ │ ├── Cloud.php
│ │ ├── FunctionError.php
│ │ ├── LaravelEngine.php
│ │ ├── LeanEngine.php
│ │ └── SlimEngine.php
│ ├── File.php
│ ├── GeoPoint.php
│ ├── LeanObject.php
│ ├── MIMEType.php
│ ├── Object.php
│ ├── Operation
│ │ ├── ArrayOperation.php
│ │ ├── DeleteOperation.php
│ │ ├── IOperation.php
│ │ ├── IncrementOperation.php
│ │ ├── RelationOperation.php
│ │ └── SetOperation.php
│ ├── Push.php
│ ├── Query.php
│ ├── Region.php
│ ├── Relation.php
│ ├── Role.php
│ ├── SMS.php
│ ├── SaveOption.php
│ ├── Storage
│ │ ├── CookieStorage.php
│ │ ├── IStorage.php
│ │ └── SessionStorage.php
│ ├── Uploader
│ │ ├── QCloudUploader.php
│ │ ├── QiniuUploader.php
│ │ ├── S3Uploader.php
│ │ └── SimpleUploader.php
│ └── User.php
└── autoload.php
└── test
├── ACLTest.php
├── APITest.php
├── AppRouterTest.php
├── ArrayOperationTest.php
├── BytesTest.php
├── ClientTest.php
├── CloudTest.php
├── DeleteOperationTest.php
├── FileTest.php
├── GeoPointTest.php
├── IncrementOperationTest.php
├── LeanObjectTest.php
├── MasterTest.php
├── Php72ObjectDeprecated.php
├── PushTest.php
├── QueryTest.php
├── RelationOperationTest.php
├── RelationTest.php
├── RoleTest.php
├── SetOperationTest.php
├── StorageTest.php
├── UserTest.php
└── engine
├── LeanEngineTest.php
└── index.php
/.github/workflows/php.yml:
--------------------------------------------------------------------------------
1 | name: PHP Composer
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | paths-ignore:
7 | - '**.md'
8 | - 'doc/**'
9 | pull_request:
10 | branches: [ master ]
11 | paths-ignore:
12 | - '**.md'
13 | - 'doc/**'
14 |
15 | jobs:
16 | build:
17 |
18 | runs-on: ubuntu-latest
19 | strategy:
20 | max-parallel: 1
21 | matrix:
22 | php-versions: [7.2, 7.4]
23 | name: PHP ${{ matrix.php-versions }} Test
24 | steps:
25 | - name: Checkout
26 | uses: actions/checkout@v2
27 |
28 | - name: Setup PHP Action
29 | uses: shivammathur/setup-php@2.9.0
30 | with:
31 | php-version: ${{ matrix.php-versions }}
32 | coverage: xdebug
33 |
34 | - name: Validate composer.json and composer.lock
35 | run: composer validate --no-check-lock
36 | - name: Get composer cache directory
37 | id: composer-cache
38 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
39 | - name: Cache dependencies
40 | uses: actions/cache@v2
41 | with:
42 | path: ${{ steps.composer-cache.outputs.dir }}
43 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
44 | restore-keys: ${{ runner.os }}-composer-
45 | - name: Install dependencies
46 | run: composer install --prefer-dist
47 |
48 | - name: Run test suite with phpunit
49 | env:
50 | LEANCLOUD_API_SERVER: https://wndg0lpt.api.lncldglobal.com
51 | LEANCLOUD_APP_ID: wnDg0lPt0wcYGJSiHRwHBhD4
52 | LEANCLOUD_APP_KEY: u9ekx9HFSFFBErWwyWHFmPDy
53 | LEANCLOUD_APP_MASTER_KEY: ${{ secrets.MASTER_KEY }}
54 | LEANCLOUD_REGION: US
55 | LEANCLOUD_APP_HOST: 127.0.0.1
56 | LEANCLOUD_APP_PORT: 8081
57 | LEANCLOUD_WILDCARD_DOMAIN: lncldglobal.com
58 | LEANCLOUD_APP_ENV: production
59 | run: |
60 | make test_engine &
61 | php -r 'exit(PHP_VERSION_ID >= 70200 ? 0 : 1);' || vendor/bin/phpunit test/Php72ObjectDeprecated.php
62 | vendor/bin/phpunit --coverage-text
63 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 |
--------------------------------------------------------------------------------
/Changelog.md:
--------------------------------------------------------------------------------
1 |
2 | 0.14.2 Released on 2024-05-11
3 | ----
4 |
5 | - Require phone number when verify sms code
6 |
7 | 0.14.1 Released on 2021-07-08
8 | ----
9 |
10 | - Fix a bug for uploading files at Chinese regions.
11 |
12 | 0.14.0 Released on 2020-12-15
13 | ----
14 |
15 | - Add `runRemote()` (invoking cloud function remotely).
16 | - Allow specifying the file key/path with `masterKey`.
17 | - Add license (Apache-2.0).
18 |
19 | 0.13.0 Released on 2020-07-15
20 | ----
21 |
22 | - Add `requestChangePhoneNumber` & `changePhoneNumber` to verify mobile number *before* updating it.
23 | - Add `_messageUpdate` hook.
24 | - Add `setApiTimeout` to specify request timeout.
25 |
26 | 0.12.0 发布日期:2020-04-21
27 | ----
28 |
29 | * 支持平滑推送(`flow_control`)
30 | * 支持即时通讯服务的 `_rtmClientSign`、`_conversationAdded`、`_conversationRemoved` hook
31 | * 支持 PHP 7.4
32 |
33 | 0.11.0 发布日期:2019-10-25
34 | ----
35 |
36 | * 支持即时通讯服务新增的 `_clientOnline`、`_clientOffline` 这两个 hook。
37 | * 支持 PHP 7.3。
38 |
39 | 0.10.3 发布日期:2019-08-30
40 | ----
41 |
42 | * 优化云引擎错误处理
43 | * 处理中间件中的异常,避免返回 500 内部错误。比如 sessionToken 不合法的异常。
44 | * 在云引擎错误栈中,打印请求到 API 的 method, url
45 |
46 | 0.10.2 发布日期:2019-06-24
47 | ----
48 |
49 | * 修复 signUpOrLoginByMobilePhone 登录问题
50 |
51 | 0.10.1 发布日期:2019-06-24
52 | ----
53 |
54 | * 修复 signUpOrLoginByMobilePhone 登录问题
55 |
56 | 0.10.0 发布日期:2019-06-24
57 | ----
58 |
59 | - 添加 `User::signUpOrLoginByMobilePhone` 支持手机注册或登录
60 |
61 | 0.9.0 发布日期:2019-05-23
62 | ----
63 |
64 | - 添加 `Cloud::start` 函数,更便捷地初始化云函数服务
65 | - 添加 `User::logInWithEmail` 函数,支持邮箱密码登录功能
66 |
67 | 0.8.1 发布日期:2018-09-25
68 | ----
69 |
70 | - 修复 `Client::useRegion`
71 |
72 | 0.8.0 发布日期:2018-06-21
73 | ----
74 |
75 | - `Object` 类更名为了 `LeanObject`,兼容 PHP 7.2
76 |
77 | 当 SDK 运行在 PHP 7.2 以下版本时,会为 `LeanObject` 创建一个别名,继续支持之前使用 `Object` 类的代码,这两个名字实际上指向同一个类,两个类名也可以混用。我们会在 PHP 7.2 以下继续支持 `Object` 一段时间,希望开发者尽快将代码中的 `Object` 改为 `LeanObject`。
78 |
79 | 0.7.0 发布日期:2018-03-19
80 | ----
81 |
82 | * 添加 `Client::setServerUrl` 接口
83 | * 非云引擎环境下支持 app-router
84 |
85 | 0.6.0 发布日期:2017-09-06
86 | ----
87 |
88 | * 更新 `LEANCLOUD_*` 环境变量
89 | * 根据环境变量设置是否以生产环境请求
90 |
91 | 0.5.6 发布日期:2017-04-13
92 | ----
93 |
94 | * 修复: 用户定义的 class hook 不需要返回对象,
95 | 而是由中间件来返回被修改的对象
96 |
97 | 0.5.5 发布日期:2017-04-12
98 | ----
99 |
100 | * 云引擎中输出错误栈
101 |
102 | 0.5.4 发布日期:2017-02-27
103 | ----
104 |
105 | * 修复推送请求中的格式不兼容问题
106 |
107 | 0.5.3 发布日期:2017-02-13
108 | ----
109 |
110 | * 支持小写的 region
111 |
112 | 0.5.2 发布日期:2017-01-22
113 | ----
114 |
115 | * 修复 pointer 对象序列化为 object
116 | * 创建本地文件时支持传入文件名
117 |
118 | 0.5.1 发布日期:2016-11-25
119 | ----
120 |
121 | * 修复 PHP 5.6 一下版本不能定义 array 常量的 bug
122 |
123 | 0.5.0 发布日期:2016-11-18
124 | ----
125 |
126 | * 添加 User#getRoles 方法获取角色
127 | * 添加 User#isAuthenticated 方法检测用户是否登录
128 | * 添加 User#refreshSessionToken 方法重置 token
129 |
130 | 0.4.2 发布日期:2016-11-03
131 | ----
132 |
133 | * 修复毫秒丢失的问题 #114
134 | * 修复 Relation 不能编码的异常 #110
135 | * Push 设置默认的 prod 参数 #111
136 | * 增加 `Client::setDebug(true)` 支持调试模式 #108
137 | * 添加 OptionSave 类支持 fetchWhenSave 以及 where #49 #83
138 |
139 | 0.4.1 发布日期:2016-09-13
140 | ----
141 |
142 | * 支持实时通信的相关 hook 及校验
143 | * 支持通用短信发送接口
144 |
145 | 0.4.0 发布日期:2016-08-10
146 | ----
147 |
148 | **不兼容改动**
149 |
150 | 为了与其它语言 SDK 类型名保持一致,将主要类型名称的 Lean 前缀去掉。如
151 | 果升级,请注意同步修改代码。
152 |
153 | 以下是去掉 `Lean` 前缀的类型列表:
154 |
155 | ```
156 | LeanACL LeanBytes LeanClient LeanFile LeanObject LeanPush
157 | LeanQuery LeanRelation LeanRole LeanUser
158 | ```
159 |
160 | 0.3.0 发布日期:2016-06-30
161 | ----
162 |
163 | * 支持云引擎,及 Slim 框架的中间件
164 |
165 | 0.2.6 发布日期:2016-05-16
166 | ----
167 |
168 | * LeanPush 支持同时向多平台发送推送
169 | * LeanObject::save, fetch, destroy 不再返回批量查询错误
170 | * 修复 LeanACL 为空时被编码为 array 的问题
171 | - LeanACL::encode 将返回 object (不兼容)
172 | * 修复 LeanRole 查询不能正常初识化
173 | - LeanRole 构造函数接收两个可选参数 className, objectId (不兼容)
174 |
175 | 0.2.5 发布日期:2016-02-01
176 | ----
177 | * 支持手机号码和密码登录
178 | * 修复查询 `_User` 未传递 sessionToken 导致查询失败
179 |
180 | 0.2.4 发布日期:2016-01-26
181 | ----
182 |
183 | * 修复短信验证码登录后 current user 为空的问题
184 |
185 | 0.2.3 发布日期:2016-01-12
186 | ----
187 |
188 | * 修复 getCurrentUser 循环调用问题 close #48
189 |
190 | 0.2.2 发布日期:2016-01-06
191 | ----
192 |
193 | * 修复保存关联文件的对象时的语法错误 close #46
194 |
195 | 0.2.1 发布日期:2015-12-31
196 | ----
197 |
198 | * 修复类型不安全的字符串比较 close #43
199 |
200 | 0.2.0 发布日期:2015-11-13
201 | ----
202 | * 支持 CQL 查询:LeanQuery::doCloudQuery
203 | * 支持发送 Push 推送消息 (#23)
204 | * 支持 GeoPoint 类型及地理位置查询 (#25)
205 | * 支持 Role 和 ACL 权限管理 (#19)
206 | * 修复: `LeanClient::useMasterKey()` 没有生效的问题 #21
207 | * `LeanClient::decode()` 添加第二个参数以识别 ACL
208 | (**与上一版本不兼容**)
209 |
210 | 0.1.0 发布日期: 2015-10-30
211 | ----
212 |
--------------------------------------------------------------------------------
/Hacking.md:
--------------------------------------------------------------------------------
1 | # Hacking
2 |
3 | ## Pull Request
4 |
5 | * Get and install [composer](https://getcomposer.org)
6 | * Fork the SDK from leancloud/php-sdk
7 | * Run `composer install` to get dependencies
8 | * Setup app credential in env variables:
9 |
10 | ```sh
11 | export LC_APP_ID=...
12 | export LC_APP_KEY=...
13 | export LC_APP_MASTER_KEY=...
14 | export LC_API_REGION=US
15 | export LEANCLOUD_APP_HOST="127.0.0.1"
16 | export LEANCLOUD_APP_PORT=8081
17 | export LEANCLOUD_WILDCARD_DOMAIN="lncldglobal.com"
18 | ```
19 |
20 | * Run tests:
21 |
22 | ```sh
23 | make test_engine &
24 | make test
25 | ```
26 |
27 | Run one single test:
28 |
29 | ```sh
30 | vendor/bin/phpunit --filter testInitializeWithString test/QueryTest.php
31 | ```
32 |
33 | * `make doc` to build documentation.
34 | The make task uses PHP 5.6, to install it on recent versions of macOS,
35 | see https://github.com/eXolnet/homebrew-deprecated/pull/25
36 |
37 | * Send a pull request at leancloud/php-sdk
38 |
39 | Thanks for your contribution!
40 |
41 | ## Prepare a Release
42 |
43 | Make sure all tests are passed.
44 |
45 | Run `make release V=MAJOR.MINOR.PATCH` (e.g. `make release V=0.11.0`),
46 | and edit `Changelog.md` (git log subjects are for reference only, do not leave them unchanged).
47 |
48 | Commit changes and send a pull request at leancloud/php-sdk.
49 |
50 | If everything is O.K., the maintainer will merge the pull request, create a new tag, and publish a new release at GitHub.
51 | Then a new version will be published at Packagist automatically.
52 | It is recommended for the maintainer to create the tag when drafting a new release on GitHub web interface.
53 | If you prefer creating a tag locally, do not forget to pull from origin before creating a new tag.
54 | Then a new version will be published at Packagist automatically.
55 |
56 | ## Run Tests with Coverage
57 |
58 | To run tests with coverage, you need to have xdebug enabled.
59 | In other words, make sure "with Xdebug" is in the output of `php -v`.
60 |
61 | ```sh
62 | php -v
63 | PHP 7.2.34 (cli) (built: Nov 30 2020 14:07:08) ( NTS )
64 | Copyright (c) 1997-2018 The PHP Group
65 | Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
66 | with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans
67 | with Zend OPcache v7.2.34, Copyright (c) 1999-2018, by Zend Technologies
68 | ```
69 |
70 | By default, PHP installed via Homebrew does not enable xdebug.
71 | You can install xdebug with pecl to enable it.
72 | For example, install xdebug for PHP 7.2 on macOS:
73 |
74 | ```sh
75 | brew install php@7.2
76 | $(brew --prefix php@7.2)/bin/pecl install --force xdebug
77 | ```
78 |
79 | Once xdebug is enabled, run tests with coverage with the following commands:
80 |
81 | ```sh
82 | # export environment variables as usual
83 | make test_engine &
84 | XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-text
85 | ```
86 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | test:
2 | vendor/bin/phpunit test
3 | php -r 'exit(PHP_VERSION_ID >= 70200 ? 0 : 1);' || vendor/bin/phpunit test/Php72ObjectDeprecated.php
4 |
5 | release:
6 | ./release.sh $V
7 | make doc
8 |
9 | doc:
10 | @rm -rf docs
11 | @php5.6 vendor/bin/apigen generate --source src --destination docs
12 |
13 | test_engine:
14 | php -S ${LEANCLOUD_APP_HOST}:${LEANCLOUD_APP_PORT} test/engine/index.php
15 |
16 | .PHONY: test doc test_engine
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | LeanCloud PHP SDK
2 | ====
3 |
4 | [
5 | ](https://travis-ci.org/leancloud/php-sdk)
6 | [
7 | ](https://packagist.org/packages/leancloud/leancloud-sdk)
8 | [](https://codecov.io/github/leancloud/php-sdk)
9 |
10 | LeanCloud 为应用提供了从数据存储,消息推送,实时通信到离线分析等全方位
11 | 的一站式云端服务,帮助应用开发者降低后端开发及维护成本,为应用开发加速。
12 | PHP SDK 提供了对数据存储,用户管理等模块的 PHP 实现及接口,以方便 PHP
13 | 应用的开发。
14 |
15 | 安装
16 | ----
17 |
18 | 运行环境要求 PHP 5.6 及以上版本,以及
19 | [cURL](http://php.net/manual/zh/book.curl.php)。
20 |
21 | #### composer 安装
22 |
23 | 如果使用标准的包管理器 composer,你可以很容易的在项目中添加依赖并下载:
24 |
25 | ```bash
26 | composer require leancloud/leancloud-sdk
27 | ```
28 |
29 | #### 手动下载安装
30 |
31 | 你也可以前往[发布页面](https://github.com/leancloud/php-sdk/releases)
32 | 手动下载安装包。假设你的应用位于 `$APP_ROOT` 目录下:
33 |
34 | ```bash
35 | cd $APP_ROOT
36 | wget https://github.com/leancloud/php-sdk/archive/vX.X.X.zip
37 |
38 | # 解压并置于 vendor 目录
39 | unzip vX.X.X.zip
40 | mv php-sdk-X.X.X vendor/leancloud
41 | ```
42 |
43 | 初始化
44 | ----
45 |
46 | 完成上述安装后,需要对 SDK 初始化。如果已经创建应用,可以在 LeanCloud
47 | [**控制台** > **应用设置**]里找到应用的 ID 和 key。然后在项目中加载 SDK,
48 | 并初始化:
49 |
50 | ```php
51 | // 如果是 composer 安装
52 | // require_once("vendor/autoload.php");
53 |
54 | // 如果是手动安装
55 | require_once("vendor/leancloud/src/autoload.php");
56 |
57 | // 参数依次为 app-id, app-key, master-key
58 | LeanCloud\Client::initialize("app_id", "app_key", "master_key");
59 | ```
60 |
61 | 使用示例
62 | ----
63 |
64 | #### 用户注册及管理
65 |
66 | 注册一个用户:
67 |
68 | ```php
69 | use LeanCloud\User;
70 | use LeanCloud\CloudException;
71 |
72 | $user = new User();
73 | $user->setUsername("alice");
74 | $user->setEmail("alice@example.net");
75 | $user->setPassword("passpass");
76 | try {
77 | $user->signUp();
78 | } catch (CloudException $ex) {
79 | // 如果 LeanCloud 返回错误,这里会抛出异常 CloudException
80 | // 如用户名已经被注册:202 Username has been taken
81 | }
82 |
83 | // 注册成功后,用户被自动登录。可以通过以下方法拿到当前登录用户和
84 | // 授权码。
85 | User::getCurrentUser();
86 | User::getCurrentSessionToken();
87 | ```
88 |
89 | 登录一个用户:
90 |
91 | ```php
92 | User::logIn("alice", "passpass");
93 | $user = User::getCurrentUser();
94 | $token = User::getCurrentSessionToken();
95 |
96 | // 给定一个 token 可以很容易的拿到用户
97 | User::become($token);
98 |
99 | // 我们还支持短信验证码,及第三方授权码登录
100 | User::logInWithSmsCode("phone number", "sms code");
101 | User::logInWith("weibo", array("openid" => "..."));
102 | ```
103 |
104 | #### 对象存储
105 |
106 | ```php
107 | use LeanCloud\LeanObject;
108 | use LeanCloud\CloudException;
109 |
110 | $obj = new LeanObject("TestObject");
111 | $obj->set("name", "alice");
112 | $obj->set("height", 60.0);
113 | $obj->set("weight", 4.5);
114 | $obj->set("birthdate", new \DateTime());
115 | try {
116 | $obj->save();
117 | } catch (CloudException $ex) {
118 | // CloudException 会被抛出,如果保存失败
119 | }
120 |
121 | // 获取字段值
122 | $obj->get("name");
123 | $obj->get("height");
124 | $obj->get("birthdate");
125 |
126 | // 原子增加一个数
127 | $obj->increment("age", 1);
128 |
129 | // 在数组字段中添加,添加唯一,删除
130 | // 注意: 由于API限制,不同数组操作之间必须保存,否则会报错
131 | $obj->addIn("colors", "blue");
132 | $obj->save();
133 | $obj->addUniqueIn("colors", "orange");
134 | $obj->save();
135 | $obj->removeIn("colors", "blue");
136 | $obj->save();
137 |
138 | // 在云存储上删除数据
139 | $obj->destroy();
140 | ```
141 |
142 | 我们同样支持子类继承,子类中需要定义静态变量 `$className` ,并注册到存储类:
143 |
144 | ```php
145 | class TestObject extends LeanObject {
146 | protected static $className = "TestObject";
147 | public setName($name) {
148 | $this->set("name", $name);
149 | return $this;
150 | }
151 | }
152 | // register it as storage class
153 | TestObject::registerClass();
154 |
155 | $obj = new TestObject();
156 | $obj->setName();
157 | $obj->set("eyeColor", "blue");
158 | ...
159 | ```
160 |
161 | #### 对象查询
162 |
163 | 给定一个 objectId,可以如下获取对象。
164 |
165 | ```php
166 | use LeanCloud\Query;
167 |
168 | $query = new Query("TestObject");
169 | $obj = $query->get($objectId);
170 | ```
171 |
172 | 更为复杂的条件查询:
173 |
174 | ```php
175 | $query = new Query("TestObject");
176 | $query->lessThan("height", 100.0); // 小于
177 | $query->greaterThanOrEqualTo("weight", 5.0); // 大于等于
178 | $query->addAscend("birthdate"); // 递增排序
179 | $query->addDescend("name"); // 递减排序
180 | $query->count();
181 | $query->first(); // 返回第一个对象
182 |
183 | $query->skip(100);
184 | $query->limit(20);
185 | $objects = $query->find(); // 返回查询到的对象
186 | ```
187 |
188 | #### 文件存储
189 |
190 | 直接创建文件:
191 |
192 | ```php
193 | use LeanCloud\File;
194 | $file = File::createWithData("hello.txt", "Hello LeanCloud!");
195 | try {
196 | $file->save();
197 | } catch (CloudException $ex) {
198 | // 云存储返回错误,保存失败
199 | }
200 |
201 | $file->getSize();
202 | $file->getName();
203 | $file->getUrl();
204 | ```
205 |
206 | 由本地文件创建:
207 |
208 | ```php
209 | $file = File::createWithLocalFile("/tmp/myfile.png");
210 | try {
211 | $file->save();
212 | } catch (CloudException $ex) {
213 | // 云存储返回错误,保存失败
214 | }
215 |
216 | // 获取文件缩略图的链接
217 | $url = $file->getThumbUrl();
218 | ```
219 |
220 | 由已知的 URL 创建文件:
221 |
222 | ```php
223 | $file = File::createWithUrl("image.png", "http://example.net/image.png");
224 | try {
225 | $file->save();
226 | } catch (CloudException $ex) {
227 | // 云存储返回错误,保存失败
228 | }
229 | ```
230 |
231 | 更多文档请参考
232 | [PHP 数据存储开发指南](https://leancloud.cn/docs/leanstorage_guide-php.html)
233 |
234 | 贡献
235 | ----
236 |
237 | See Hacking.md if you'd like to contribute.
238 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "leancloud/leancloud-sdk",
3 | "description": "LeanCloud PHP SDK",
4 | "type": "library",
5 | "keywords": ["leancloud"],
6 | "homepage": "https://github.com/leancloud/php-sdk",
7 | "authors": [
8 | {
9 | "name": "Juvenn Woo",
10 | "email": "yun.wu@leancloud.rocks"
11 | }
12 | ],
13 | "license": "Apache-2.0",
14 | "require": {
15 | "php": ">=5.6",
16 | "ext-curl": "*"
17 | },
18 | "require-dev": {
19 | "phpunit/phpunit": "^5.7",
20 | "apigen/apigen": "^4.1",
21 | "doctrine/instantiator": "<1.1.0"
22 | },
23 | "autoload": {
24 | "psr-4": {"LeanCloud\\": "src/LeanCloud"}
25 | },
26 | "minimum-stability": "stable"
27 | }
28 |
--------------------------------------------------------------------------------
/docs/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Page not found
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
120 |
121 |
122 |
123 |
124 | Overview
125 |
126 |
127 | Namespace
128 |
129 | Class
130 |
131 |
133 |
135 |
136 |
137 |
138 |
Page not found
139 |
The requested page could not be found.
140 |
You have probably clicked on a link that is outdated and points to a page that does not exist any more or you have made an typing error in the address.
141 |
To continue please try to find requested page in the menu, or use search field on the top.
142 |
143 |
144 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/docs/class-LeanCloud.Engine.FunctionError.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Class LeanCloud\Engine\FunctionError
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
84 |
85 |
101 |
102 |
103 |
Class FunctionError
104 |
105 |
106 |
107 |
Error thrown when invoking function error
108 |
109 |
110 |
111 |
112 | Exception
113 |
114 |
115 |
116 |
117 |
118 | LeanCloud\Engine\FunctionError
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
140 |
141 |
142 |
143 |
144 | Methods summary
145 |
146 |
147 |
148 | public
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
#
157 |
__construct ( $message , $code = 1 , $status = 400 )
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
Overrides
172 |
Exception::__construct()
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 | public
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
#
189 |
__toString ( )
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
Overrides
204 |
Exception::__toString()
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 | Methods inherited from Exception
213 |
214 |
215 | __wakeup(),
216 | getCode(),
217 | getFile(),
218 | getLine(),
219 | getMessage(),
220 | getPrevious(),
221 | getTrace(),
222 | getTraceAsString()
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 | Properties summary
239 |
240 |
241 | public
242 |
243 |
244 |
245 |
246 | $status
247 |
248 |
249 |
Http status code
250 |
251 |
252 |
253 |
Http status code
254 |
255 |
256 |
257 |
258 |
262 |
263 |
264 |
265 |
266 |
267 | Properties inherited from Exception
268 |
269 |
270 | $code ,
271 | $file ,
272 | $line ,
273 | $message
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
--------------------------------------------------------------------------------
/docs/class-LeanCloud.RouteCache.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Class LeanCloud\RouteCache
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
98 |
99 |
115 |
116 |
117 |
Class RouteCache
118 |
119 |
120 |
121 |
Route cache
122 |
123 |
Ideally we should use ACPu for caching, but it can be inconvenient to
124 | install, esp. on Windows1 , thus we implement a naive file based
125 | cache.
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
145 |
146 |
147 |
148 |
149 | Methods summary
150 |
151 |
152 |
153 | public static
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
#
162 |
create ( $id )
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 | public
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
#
192 |
write ( $array )
193 |
194 |
195 |
Serialize array and store in file, array must be json_encode safe.
196 |
197 |
198 |
199 |
Serialize array and store in file, array must be json_encode safe.
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 | public
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
#
222 |
read ( )
223 |
224 |
225 |
Read routes either from cache or file, return json_decoded array.
226 |
227 |
228 |
229 |
Read routes either from cache or file, return json_decoded array.
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
--------------------------------------------------------------------------------
/docs/class-LeanCloud.SMS.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Class LeanCloud\SMS
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
98 |
99 |
115 |
116 |
117 |
Class SMS
118 |
119 |
120 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
141 |
142 |
143 |
144 |
145 | Methods summary
146 |
147 |
148 |
149 | public static
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
#
158 |
requestSmsCode ( string $phoneNumber , array $options = array () )
159 |
160 |
161 |
Request SMS code
162 |
163 |
164 |
165 |
Request SMS code
166 |
167 |
Besides sending default message with sms code, you can also
168 | send with a customized template, which though must be submitted
169 | and approved before sending.
170 |
171 |
The available of options are:
172 |
173 |
174 | $smsType
(string): "sms" or "voice"
175 | $template
(string): Template name that has been approved
176 | $name
(string): App name
177 | $ttl
(int): Number of minutes before sms code expires
178 | $op
(string): Operation name for the sms code
179 |
180 |
181 |
182 |
Parameters
183 |
184 | $phoneNumber
185 |
186 | $options
187 |
188 |
189 |
190 |
191 |
192 |
Link
193 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 | public static
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
#
213 |
verifySmsCode ( string $phoneNumber , string $smsCode )
214 |
215 |
216 |
Verify SMS code
217 |
218 |
219 |
220 |
Verify SMS code
221 |
222 |
223 |
Parameters
224 |
225 | $phoneNumber
226 |
227 | $smsCode
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
--------------------------------------------------------------------------------
/docs/class-LeanCloud.SaveOption.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Class LeanCloud\SaveOption
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
98 |
99 |
115 |
116 |
117 |
Class SaveOption
118 |
119 |
120 |
121 |
LeanObject save option builder
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
141 |
142 |
143 |
144 |
145 | Methods summary
146 |
147 |
148 |
149 | public
150 |
151 | array
152 |
153 |
154 |
155 |
156 |
157 |
#
158 |
encode ( )
159 |
160 |
161 |
Encode a save option as array
162 |
163 |
164 |
165 |
Encode a save option as array
166 |
167 |
168 |
169 |
Returns
170 |
171 | array
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 | Properties summary
195 |
196 |
197 | public
198 | boolean
199 |
200 |
201 |
202 | $fetchWhenSave
203 |
204 |
205 |
Fetch object when save if set to true
206 |
207 |
208 |
209 |
Fetch object when save if set to true
210 |
211 |
212 |
213 |
214 |
218 |
219 |
220 |
221 |
222 | public
223 | LeanCloud\Query
224 |
225 |
226 |
227 | $where
228 |
229 |
230 |
Update object only when where query matches
231 |
232 |
233 |
234 |
Update object only when where query matches
235 |
236 |
237 |
238 |
239 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
--------------------------------------------------------------------------------
/docs/class-LeanCloud.Uploader.QCloudUploader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Class LeanCloud\Uploader\QCloudUploader
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
80 |
81 |
97 |
98 |
99 |
Class QCloudUploader
100 |
101 |
102 |
103 |
QCloud COS file uploader
104 |
105 |
106 |
107 |
108 | LeanCloud\Uploader\SimpleUploader
109 |
110 |
111 |
112 |
113 |
114 |
115 | LeanCloud\Uploader\QCloudUploader
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
139 |
140 |
141 |
142 |
143 | Methods summary
144 |
145 |
146 |
147 | protected static
148 |
149 | string
150 |
151 |
152 |
153 |
154 |
155 |
#
156 |
getFileFieldName ( )
157 |
158 |
159 |
The form field name of file content in multipart encoded data
160 |
161 |
162 |
163 |
The form field name of file content in multipart encoded data
164 |
165 |
166 |
167 |
Returns
168 |
169 | string
170 |
171 |
172 |
173 |
174 |
Overrides
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 | public
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
#
192 |
upload ( $content , $mimeType , $key )
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
--------------------------------------------------------------------------------
/docs/class-LeanCloud.Uploader.S3Uploader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Class LeanCloud\Uploader\S3Uploader
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
80 |
81 |
97 |
98 |
99 |
Class S3Uploader
100 |
101 |
102 |
103 |
Pre-signed URL Uploader for S3
104 |
105 |
106 |
107 |
108 | LeanCloud\Uploader\SimpleUploader
109 |
110 |
111 |
112 |
113 |
114 |
115 | LeanCloud\Uploader\S3Uploader
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
139 |
140 |
141 |
142 |
143 | Methods summary
144 |
145 |
146 |
147 | public
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
#
156 |
upload ( $content , $mimeType , $name = null )
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
--------------------------------------------------------------------------------
/docs/elementlist.js:
--------------------------------------------------------------------------------
1 |
2 | var ApiGen = ApiGen || {};
3 | ApiGen.elements = [["c","LeanCloud\\ACL"],["c","LeanCloud\\AppRouter"],["c","LeanCloud\\BatchRequestError"],["c","LeanCloud\\Bytes"],["c","LeanCloud\\Client"],["c","LeanCloud\\CloudException"],["c","LeanCloud\\Engine\\Cloud"],["c","LeanCloud\\Engine\\FunctionError"],["c","LeanCloud\\Engine\\LaravelEngine"],["c","LeanCloud\\Engine\\LeanEngine"],["c","LeanCloud\\Engine\\SlimEngine"],["c","LeanCloud\\File"],["c","LeanCloud\\GeoPoint"],["c","LeanCloud\\LeanObject"],["c","LeanCloud\\MIMEType"],["c","LeanCloud\\Operation\\ArrayOperation"],["c","LeanCloud\\Operation\\DeleteOperation"],["c","LeanCloud\\Operation\\IncrementOperation"],["c","LeanCloud\\Operation\\IOperation"],["c","LeanCloud\\Operation\\RelationOperation"],["c","LeanCloud\\Operation\\SetOperation"],["c","LeanCloud\\Push"],["c","LeanCloud\\Query"],["c","LeanCloud\\Region"],["c","LeanCloud\\Relation"],["c","LeanCloud\\Role"],["c","LeanCloud\\RouteCache"],["c","LeanCloud\\SaveOption"],["c","LeanCloud\\SMS"],["c","LeanCloud\\Storage\\CookieStorage"],["c","LeanCloud\\Storage\\IStorage"],["c","LeanCloud\\Storage\\SessionStorage"],["c","LeanCloud\\Uploader\\QCloudUploader"],["c","LeanCloud\\Uploader\\QiniuUploader"],["c","LeanCloud\\Uploader\\S3Uploader"],["c","LeanCloud\\Uploader\\SimpleUploader"],["c","LeanCloud\\User"]];
4 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Overview
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
118 |
119 |
120 |
121 |
122 | Overview
123 |
124 | Namespace
125 |
126 | Class
127 |
128 |
130 |
132 |
133 |
134 |
135 |
Overview
136 |
137 |
138 |
156 |
157 |
158 |
159 |
160 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/docs/namespace-LeanCloud.Engine.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Namespace LeanCloud\Engine
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
84 |
85 |
86 |
87 |
88 | Overview
89 |
90 |
91 | Namespace
92 |
93 | Class
94 |
95 |
97 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Classes summary
108 |
109 | Cloud
110 | Cloud functions and hooks repository
111 |
112 |
113 | LaravelEngine
114 | LeanEngine as Laravel middleware
115 |
116 |
117 | LeanEngine
118 |
119 |
120 |
121 | SlimEngine
122 | LeanEngine as Slim middleware
123 |
124 |
125 |
126 |
127 |
128 |
129 | Exceptions summary
130 |
131 | FunctionError
132 | Error thrown when invoking function error
133 |
134 |
135 |
136 |
137 |
138 |
139 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/docs/namespace-LeanCloud.Operation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Namespace LeanCloud\Operation
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
85 |
86 |
87 |
88 |
89 | Overview
90 |
91 |
92 | Namespace
93 |
94 | Class
95 |
96 |
98 |
100 |
101 |
102 |
103 |
Namespace LeanCloud \Operation
104 |
105 |
106 |
107 |
130 |
131 |
132 | Interfaces summary
133 |
134 | IOperation
135 | Operation Interface
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/docs/namespace-LeanCloud.Storage.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Namespace LeanCloud\Storage
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
82 |
83 |
84 |
85 |
86 | Overview
87 |
88 |
89 | Namespace
90 |
91 | Class
92 |
93 |
95 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | Classes summary
106 |
107 | CookieStorage
108 | Cookie Storage
109 |
110 |
111 | SessionStorage
112 | Session Based Storage
113 |
114 |
115 |
116 |
117 | Interfaces summary
118 |
119 | IStorage
120 | Storage Interface
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/docs/namespace-LeanCloud.Uploader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Namespace LeanCloud\Uploader
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
80 |
81 |
82 |
83 |
84 | Overview
85 |
86 |
87 | Namespace
88 |
89 | Class
90 |
91 |
93 |
95 |
96 |
97 |
98 |
Namespace LeanCloud \Uploader
99 |
100 |
101 |
102 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/docs/namespace-LeanCloud.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Namespace LeanCloud
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
98 |
99 |
100 |
101 |
102 | Overview
103 |
104 |
105 | Namespace
106 |
107 | Class
108 |
109 |
111 |
113 |
114 |
115 |
116 |
Namespace LeanCloud
117 |
118 |
133 |
134 |
135 |
136 | Classes summary
137 |
138 | ACL
139 | Access Control List representation on LeanCloud
140 |
141 |
142 | AppRouter
143 |
144 |
145 |
146 | Bytes
147 | Byte array data type for LeanObject
148 |
149 |
150 | Client
151 | Client interfacing with LeanCloud REST API
152 |
153 |
154 | File
155 | File object on LeanCloud
156 |
157 |
158 | GeoPoint
159 | GeoPoint type representation
160 |
161 |
162 | LeanObject
163 | LeanObject interface to LeanCloud storage API
164 |
165 |
166 | MIMEType
167 |
168 |
169 |
170 | Push
171 | Send Push notification to mobile devices
172 |
173 |
174 | Query
175 | Query representation for finding objects on LeanCloud
176 |
177 |
178 | Region
179 |
180 |
181 |
182 | Relation
183 | Many-to-many relationship for LeanObject
184 |
185 |
186 | Role
187 | Role representation on LeanCloud
188 |
189 |
190 | RouteCache
191 | Route cache
192 |
193 |
194 | SaveOption
195 | LeanObject save option builder
196 |
197 |
198 | SMS
199 | SMS
200 |
201 |
202 | User
203 | User representation for LeanCloud User
204 |
205 |
206 |
207 |
208 |
209 |
210 | Exceptions summary
211 |
212 | BatchRequestError
213 | BatchRequestError
214 |
215 |
216 | CloudException
217 | Exception thrown when cloud API returns error
218 |
219 |
220 |
221 |
222 |
223 |
224 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
--------------------------------------------------------------------------------
/docs/resources/collapsed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/collapsed.png
--------------------------------------------------------------------------------
/docs/resources/footer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/footer.png
--------------------------------------------------------------------------------
/docs/resources/inherit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/inherit.png
--------------------------------------------------------------------------------
/docs/resources/resize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/resize.png
--------------------------------------------------------------------------------
/docs/resources/sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/sort.png
--------------------------------------------------------------------------------
/docs/resources/tree-cleaner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/tree-cleaner.png
--------------------------------------------------------------------------------
/docs/resources/tree-hasnext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/tree-hasnext.png
--------------------------------------------------------------------------------
/docs/resources/tree-last.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/tree-last.png
--------------------------------------------------------------------------------
/docs/resources/tree-vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leancloud/php-sdk/66f57f0132c83bd91bd13d8ebdabb7d977cf5095/docs/resources/tree-vertical.png
--------------------------------------------------------------------------------
/fabfile.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | # Usage:
4 | # fab -H username@hostname deploy_docs:local_dir='folder',platform='php'
5 | #
6 | #
7 |
8 | from fabric.api import run, sudo, env, cd, local, prefix, put, lcd, settings
9 | from fabric.contrib.files import exists, sed
10 | from fabric.contrib.project import rsync_project
11 |
12 | env.use_ssh_config = True
13 |
14 | user = 'deploy'
15 | doc_dir = '/var/www/avoscloud-api-docs'
16 |
17 | project_dir = "."
18 | dist = 'debian'
19 | host_count = len(env.hosts)
20 |
21 | def _set_user_dir():
22 | global dist,user,doc_dir
23 | with settings(warn_only=True):
24 | issue = run('id ubuntu').lower()
25 | if 'id: ubuntu' in issue:
26 | dist = 'debian'
27 | elif 'uid=' in issue:
28 | dist = 'ubuntu'
29 | user = 'ubuntu'
30 | doc_dir = '/mnt/avos/avoscloud-api-docs'
31 |
32 | def prepare_remote_dirs(remote_dir):
33 | _set_user_dir()
34 | if not exists(remote_dir):
35 | sudo('mkdir -p %s' % remote_dir)
36 | sudo('chown %s %s' % (user, remote_dir))
37 |
38 | def deploy_docs(local_dir='', platform='unknown'):
39 | global host_count
40 | _set_user_dir()
41 | remote_dir = '%s/%s/' % (doc_dir, platform)
42 |
43 | prepare_remote_dirs(remote_dir)
44 | rsync_project(local_dir=local_dir + '/',
45 | remote_dir=remote_dir,
46 | delete=True)
47 | host_count -= 1
48 | if (host_count == 0):
49 | print("Finished to public api docs!")
50 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | test
8 | tests/engine
9 |
10 |
11 |
12 |
13 |
14 | src
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #### it requires new version number
4 | if [ -z "$1" ]; then
5 | echo "Error: please provide a version string"
6 | exit 1
7 | fi
8 | version="$1"
9 |
10 | #### Build new changelog
11 | echo "" >> Changelog.md.0
12 | echo "$version Released on `date +%Y-%m-%d`" >> Changelog.md.0
13 | echo "----" >> Changelog.md.0
14 | git log `git describe --tags --abbrev=0`..HEAD --pretty=%s >> Changelog.md.0
15 |
16 | #### prepend changelog
17 | cat Changelog.md >> Changelog.md.0
18 | mv Changelog.md.0 Changelog.md
19 |
20 | #### update version string client
21 | perl -pi -e "s/const VERSION = .*\;/const VERSION = \'$version\'\;/" \
22 | src/LeanCloud/Client.php
23 |
24 | echo "Done! Ready to commit and release $version!"
25 |
26 |
--------------------------------------------------------------------------------
/src/LeanCloud/AppRouter.php:
--------------------------------------------------------------------------------
1 | "us-api.leancloud.cn",
21 | Region::CN_E1 => "e1-api.leancloud.cn",
22 | Region::CN_N1 => "api.leancloud.cn"
23 | );
24 |
25 | private static $DEFAULT_REGION_RTM_ROUTE = array(
26 | Region::US => "router-a0-push.leancloud.cn",
27 | Region::CN_E1 => "router-q0-push.leancloud.cn",
28 | Region::CN_N1 => "router-g0-push.leancloud.cn"
29 | );
30 |
31 | private function __construct($appId) {
32 | $this->appId = $appId;
33 | $region = getenv("LEANCLOUD_REGION");
34 | if (!$region) {
35 | $region = Region::CN;
36 | }
37 | $this->setRegion($region);
38 | $this->routeCache = RouteCache::create($appId);
39 | }
40 |
41 | /**
42 | * Get instance of AppRouter.
43 | */
44 | public static function getInstance($appId) {
45 | if (isset(self::$INSTANCES[$appId])) {
46 | return self::$INSTANCES[$appId];
47 | } else {
48 | $router = new AppRouter($appId);
49 | self::$INSTANCES[$appId] = $router;
50 | return $router;
51 | }
52 | }
53 |
54 | /**
55 | * Get app region default route host
56 | */
57 | public function getRegionDefaultRoute($server_key) {
58 | $this->validate_server_key($server_key);
59 | return $this->getDefaultRoutes()[$server_key];
60 | }
61 |
62 | /**
63 | * Set region
64 | *
65 | * See `LeanCloud\Region` for available regions.
66 | *
67 | * @param mixed $region
68 | */
69 | public function setRegion($region) {
70 | if (is_numeric($region)) {
71 | $this->region = $region;
72 | } else {
73 | $this->region = Region::fromName($region);
74 | }
75 | }
76 |
77 | /**
78 | * Get and return route host by server type, or null if not found.
79 | */
80 | public function getRoute($server_key) {
81 | $this->validate_server_key($server_key);
82 | $routes = $this->routeCache->read();
83 | if (isset($routes[$server_key])) {
84 | return $routes[$server_key];
85 | }
86 | $routes = $this->getRoutes();
87 | if (!$routes) {
88 | $routes = $this->getDefaultRoutes();
89 | }
90 | $this->routeCache->write($routes);
91 | return isset($routes[$server_key]) ? $routes[$server_key] : null;
92 | }
93 |
94 | private function getRouterUrl() {
95 | $url = getenv("LEANCLOUD_APP_ROUTER");
96 | if (!$url) {
97 | $url = "https://app-router.leancloud.cn/2/route?appId=";
98 | }
99 | return "{$url}{$this->appId}";
100 | }
101 |
102 | private function validate_server_key($server_key) {
103 | $routes = $this->getDefaultRoutes();
104 | if (!isset($routes[$server_key])) {
105 | throw new IllegalArgumentException("Invalid server key.");
106 | }
107 | }
108 |
109 | /**
110 | * Detect region by app-id
111 | */
112 | private function detectRegion() {
113 | if (!$this->appId) {
114 | return Region::CN_N1;
115 | }
116 | $parts = explode("-", $this->appId);
117 | if (count($parts) <= 1) {
118 | return Region::CN_N1;
119 | } else if ($parts[1] === "MdYXbMMI") {
120 | return Region::US;
121 | } else if ($parts[1] === "9Nh9j0Va") {
122 | return Region::CN_E1;
123 | } else {
124 | $this->region = Region::CN_N1;
125 | }
126 | }
127 |
128 | /**
129 | * Get routes remotely from app router, return array.
130 | */
131 | private function getRoutes() {
132 | $routes = @json_decode(file_get_contents($this->getRouterUrl()), true);
133 | if (isset($routes[self::TTL_KEY])) {
134 | return $routes;
135 | }
136 | return null;
137 | }
138 |
139 | /**
140 | * Fallback default routes, if app router not available.
141 | */
142 | private function getDefaultRoutes() {
143 | $host = self::$DEFAULT_REGION_ROUTE[$this->region];
144 |
145 | return array(
146 | self::API_SERVER_KEY => $host,
147 | self::PUSH_SERVER_KEY => $host,
148 | self::STATS_SERVER_KEY => $host,
149 | self::ENGINE_SERVER_KEY => $host,
150 | self::RTM_ROUTER_SERVER_KEY => self::$DEFAULT_REGION_RTM_ROUTE[$this->region],
151 | self::TTL_KEY => 3600
152 | );
153 | }
154 |
155 |
156 | }
157 |
158 |
159 | /**
160 | * Route cache
161 | *
162 | * Ideally we should use ACPu for caching, but it can be inconvenient to
163 | * install, esp. on Windows[1], thus we implement a naive file based
164 | * cache.
165 | *
166 | * [1]: https://stackoverflow.com/a/28124144/108112
167 | */
168 | class RouteCache {
169 | private $filename;
170 | private $_cache;
171 |
172 | private function __construct($id) {
173 | $this->filename = sys_get_temp_dir() . "/route_{$id}.json";
174 | }
175 |
176 | public static function create($id) {
177 | return new RouteCache($id);
178 | }
179 |
180 | /**
181 | * Serialize array and store in file, array must be json_encode safe.
182 | */
183 | public function write($array) {
184 | $body = json_encode($array);
185 | if (file_put_contents($this->filename, $body, LOCK_EX) === false) {
186 | error_log("WARNING: failed to write route cache ({$this->filename}), performance may be degraded.");
187 | } else {
188 | $this->_cache = $array;
189 | }
190 | }
191 |
192 | /**
193 | * Read routes either from cache or file, return json_decoded array.
194 | */
195 | public function read() {
196 | if ($this->_cache) {
197 | return $this->_cache;
198 | }
199 | $data = $this->readFile();
200 | if (!empty($data)) {
201 | $this->_cache = $data;
202 | return $data;
203 | }
204 | return null;
205 | }
206 |
207 | private function readFile() {
208 | if (file_exists($this->filename)) {
209 | $fp = fopen($this->filename, "rb");
210 | $body = null;
211 | if (flock($fp, LOCK_SH)) {
212 | $body = fread($fp, filesize($this->filename));
213 | flock($fp, LOCK_UN);
214 | }
215 | fclose($fp);
216 | if (!empty($body)) {
217 | $data = @json_decode($body, true);
218 | if (!empty($data)) {
219 | return $data;
220 | }
221 | }
222 | }
223 | return null;
224 | }
225 | }
--------------------------------------------------------------------------------
/src/LeanCloud/BatchRequestError.php:
--------------------------------------------------------------------------------
1 | errors[] = $error;
39 | return $this;
40 | }
41 |
42 | /**
43 | * Get all error response
44 | *
45 | * @return array
46 | */
47 | public function getAll() {
48 | return $this->errors;
49 | }
50 |
51 | /**
52 | * Get first error response as map
53 | *
54 | * Returns associative array of following format:
55 | *
56 | * `{"code": 101, "error": "error message", "request": {...}}`
57 | *
58 | * @return array|null
59 | */
60 | public function getFirst() {
61 | return isset($this->errors[0]) ? $this->errors[0] : null;
62 | }
63 |
64 | /**
65 | * Contains error response or not
66 | *
67 | * @return bool
68 | */
69 | public function isEmpty() {
70 | return count($this->errors) == 0;
71 | }
72 |
73 | public function __toString() {
74 | $message = $this->message;
75 | if (!$this->isEmpty()) {
76 | $message .= json_encode($this->errors);
77 | }
78 | return __CLASS__ . ": [{$this->code}]: {$message}\n";
79 | }
80 | }
81 |
82 |
--------------------------------------------------------------------------------
/src/LeanCloud/Bytes.php:
--------------------------------------------------------------------------------
1 | byteArray = $byteArray;
25 | return $bytes;
26 | }
27 |
28 | /**
29 | * Create Bytes from base64 encoded string
30 | *
31 | * @param string $data Base64 encoded string
32 | * @return Bytes
33 | */
34 | public static function createFromBase64Data($data) {
35 | $bytes = new Bytes();
36 |
37 | // convert unpacked associative array to sequence array
38 | $byteMap = unpack('C*', base64_decode($data));
39 | forEach($byteMap as $byte) {
40 | $bytes->byteArray[] .= $byte;
41 | }
42 | return $bytes;
43 | }
44 |
45 | /**
46 | * Get byte array
47 | *
48 | * @return array
49 | */
50 | public function getByteArray() {
51 | return $this->byteArray;
52 | }
53 |
54 | /**
55 | * Get string representation of byte array
56 | *
57 | * @return string
58 | */
59 | public function asString() {
60 | $str = "";
61 | forEach($this->byteArray as $byte) {
62 | $str .= chr($byte);
63 | }
64 | return $str;
65 | }
66 |
67 | /**
68 | * Encode to LeanCloud bytes type
69 | *
70 | * @return array
71 | */
72 | public function encode() {
73 | return array(
74 | "__type" => "Bytes",
75 | "base64" => base64_encode($this->asString()));
76 | }
77 |
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/src/LeanCloud/CloudException.php:
--------------------------------------------------------------------------------
1 | status = $status;
34 | $this->method = $method;
35 | $this->url = $url;
36 | }
37 |
38 | public function __toString() {
39 | $req = $this->method ? ": {$this->method} {$this->url}": "";
40 | return __CLASS__ . ": [{$this->code}] {$this->message}{$req}\n";
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/LeanCloud/Engine/FunctionError.php:
--------------------------------------------------------------------------------
1 | status = $status;
17 | }
18 |
19 | public function __toString() {
20 | return __CLASS__ . ": [{$this->code}] {$this->message}\n";
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/LeanCloud/Engine/LaravelEngine.php:
--------------------------------------------------------------------------------
1 | request->header($key);
29 | }
30 |
31 | /**
32 | * Get request body string
33 | *
34 | * @return string
35 | */
36 | protected function getBody() {
37 | return $this->request->getContent();
38 | }
39 |
40 | /**
41 | * Laravel middleware entry point
42 | *
43 | * @param \Illuminate\Http\Reuqest $request Laravel request
44 | * @param \Closure $next Laravel closure
45 | * @return mixed
46 | */
47 | public function handle($request, $next) {
48 | $this->request = $request;
49 | $this->dispatch($request->method(),
50 | $request->url());
51 | return $next($this->request);
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/src/LeanCloud/Engine/SlimEngine.php:
--------------------------------------------------------------------------------
1 | add(new SlimEngine());
13 | * ```
14 | *
15 | * @link http://www.slimframework.com/docs/concepts/middleware.html
16 | */
17 | class SlimEngine extends LeanEngine {
18 |
19 | /**
20 | * Get request header value
21 | *
22 | * @param string $key Header key
23 | * @return string
24 | */
25 | protected function getHeaderLine($key) {
26 | return $this->request->getHeaderLine($key);
27 | }
28 |
29 | /**
30 | * Get request body string
31 | *
32 | * @return string
33 | */
34 | protected function getBody() {
35 | return $this->request->getBody()->getContents();
36 | }
37 |
38 | /*
39 | * Ideally we would like to write to Slim response and send
40 | * the response to client. But we did not yet find a good way
41 | * to end the request as Slime middleware. As a work around,
42 | * we fallback to PHP native functions to do that. Pull request
43 | * is welcome.
44 | *
45 | * @see LeanEngine::withHeader LeanEngine::send
46 | */
47 | // protected function withHeader($key, $val) {}
48 | // protected function send($key, $val) {}
49 |
50 | /**
51 | * Slim middleware entry point
52 | *
53 | * @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
54 | * @param \Psr\Http\Message\ResponseInterface $response PSR7 response
55 | * @param callable $next Next middleware
56 | * @return \Psr\Http\Message\ResponseInterface
57 | */
58 | public function __invoke($request, $response, $next) {
59 | $this->request = $request;
60 | $this->response = $response;
61 | $this->dispatch($request->getMethod(),
62 | $request->getUri());
63 | return $next($this->request, $this->response);
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/src/LeanCloud/GeoPoint.php:
--------------------------------------------------------------------------------
1 | = -90.0 &&
34 | $longitude <= 180.0 && $longitude >= -180.0) {
35 | $this->latitude = $latitude;
36 | $this->longitude = $longitude;
37 | } else {
38 | throw new \InvalidArgumentException("Invalid latitude or " .
39 | "longitude for geo point");
40 | }
41 | }
42 |
43 | /**
44 | * @return number
45 | */
46 | public function getLatitude() {
47 | return $this->latitude;
48 | }
49 |
50 | /**
51 | * @return number
52 | */
53 | public function getLongitude() {
54 | return $this->longitude;
55 | }
56 |
57 | /**
58 | * Compute distance (in radians) to a geo point
59 | *
60 | * @param GeoPoint $point Other geo point
61 | * @return number
62 | */
63 | public function radiansTo(GeoPoint $point) {
64 | $d2r = M_PI / 180.0;
65 | $lat1rad = $this->getLatitude() * $d2r;
66 | $lon1rad = $this->getLongitude() * $d2r;
67 | $lat2rad = $point->getLatitude() * $d2r;
68 | $lon2rad = $point->getLongitude() * $d2r;
69 | $deltaLat = $lat1rad - $lat2rad;
70 | $deltaLon = $lon1rad - $lon2rad;
71 | $sinLat = sin($deltaLat / 2);
72 | $sinLon = sin($deltaLon / 2);
73 | $a = $sinLat * $sinLat +
74 | cos($lat1rad) * cos($lat2rad) * $sinLon * $sinLon;
75 | $a = min(1.0, $a);
76 | return 2 * asin(sqrt($a));
77 | }
78 |
79 | /**
80 | * Compute distance (in kilometers) to other geo point
81 | *
82 | * @param GeoPoint $point Other geo point
83 | * @return number
84 | */
85 | public function kilometersTo(GeoPoint $point) {
86 | return $this->radiansTo($point) * 6371.0;
87 | }
88 |
89 | /**
90 | * Compute distance (in miles) to other geo point
91 | *
92 | * @param GeoPoint $point Other geo point
93 | * @return number
94 | */
95 | public function milesTo(GeoPoint $point) {
96 | return $this->radiansTo($point) * 3958.8;
97 | }
98 |
99 | public function encode() {
100 | return array(
101 | '__type' => 'GeoPoint',
102 | 'latitude' => $this->latitude,
103 | 'longitude' => $this->longitude
104 | );
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/LeanCloud/Object.php:
--------------------------------------------------------------------------------
1 | = 70200) {
5 | throw new \RuntimeException("'Object` was reserved by PHP 7.2, use 'LeanObject' instead, see https://url.leanapp.cn/php72-object-deprecated");
6 | } else {
7 | $filename = sys_get_temp_dir() . "/php72-object-deprecated";
8 |
9 | if (!file_exists($filename)) {
10 | touch($filename);
11 | error_log("Warning: 'Object' was deprecated, use 'LeanObject' instead, see https://url.leanapp.cn/php72-object-deprecated");
12 | }
13 |
14 | class_alias('\LeanCloud\LeanObject', '\LeanCloud\Object');
15 | }
16 |
--------------------------------------------------------------------------------
/src/LeanCloud/Operation/ArrayOperation.php:
--------------------------------------------------------------------------------
1 | key = $key;
51 | $this->value = $val;
52 | $this->opType = $opType;
53 | }
54 |
55 | /**
56 | * Get key of field the operation applies to.
57 | *
58 | * @return string
59 | */
60 | public function getKey() {
61 | return $this->key;
62 | }
63 |
64 | /**
65 | * Get type of operation
66 | *
67 | * @return string
68 | */
69 | public function getOpType() {
70 | return $this->opType;
71 | }
72 |
73 | /**
74 | * Get value of operation
75 | *
76 | * @return mixed
77 | */
78 | public function getValue() {
79 | return $this->value;
80 | }
81 |
82 | /**
83 | * Encode to JSON represented operation
84 | *
85 | * @return array
86 | */
87 | public function encode() {
88 | return array(
89 | "__op" => $this->getOpType(),
90 | "objects" => Client::encode($this->value),
91 | );
92 | }
93 |
94 | /**
95 | * Add objects of this operation to old array
96 | *
97 | * @param array $oldval Old array of objects
98 | * @return array Merged new array
99 | */
100 | private function add($oldval) {
101 | return array_merge($oldval, $this->getValue());
102 | }
103 |
104 | /**
105 | * Add objects of this operation, uniquely, to old array.
106 | *
107 | * Note duplicated items in old array will remain duplicate.
108 | *
109 | * @param array $oldval Old array of objects
110 | * @return array
111 | */
112 | private function addUnique($oldval) {
113 | $newval = $oldval; // New result array
114 | $found = array(); // Hash map of objects with objectId as key
115 | forEach($oldval as $obj) {
116 | if (($obj instanceof LeanObject) && ($obj->getObjectId())) {
117 | $found[$obj->getObjectId()] = true;
118 | }
119 | }
120 | forEach($this->getValue() as $obj) {
121 | if (($obj instanceof LeanObject) && ($obj->getObjectId())) {
122 | if (isset($found[$obj->getObjectId()])) {
123 | // skip duplicate object
124 | } else {
125 | $found[$obj->getObjectId()] = true;
126 | $newval[] = $obj;
127 | }
128 | } else if (!in_array($obj, $newval)) {
129 | $newval[] = $obj;
130 | }
131 | }
132 | return $newval;
133 | }
134 |
135 | /**
136 | * Remove objects of this operation from old array.
137 | *
138 | * @param array $oldval Old array of objects
139 | * @return array
140 | */
141 | private function remove($oldval) {
142 | $newval = array();
143 | $remove = $this->getValue(); // items to remove
144 | forEach($oldval as $item) {
145 | if (!in_array($item, $remove)) {
146 | $newval[] = $item;
147 | }
148 | }
149 | return $newval;
150 | }
151 |
152 | /**
153 | * Apply this operation based on old array.
154 | *
155 | * @param array $oldval Old array
156 | * @return array
157 | * @throws RuntimeException
158 | */
159 | public function applyOn($oldval) {
160 | if (!$oldval) { $oldval = array();}
161 |
162 | if (!is_array($oldval)) {
163 | throw new \RuntimeException("Operation incompatible" .
164 | " with previous value.");
165 | }
166 |
167 | // TODO: Ensure behaviours of adding and removing associative array
168 | if ($this->getOpType() === "Add") {
169 | return $this->add($oldval);
170 | }
171 | if ($this->getOpType() === "AddUnique") {
172 | return $this->addUnique($oldval);
173 | }
174 | if ($this->getOpType() === "Remove") {
175 | return $this->remove($oldval);
176 | }
177 | throw new \RuntimeException("Operation type {$this->getOptype()}" .
178 | " not supported.");
179 | }
180 |
181 | /**
182 | * Merge this operation into a (previous) operation.
183 | *
184 | * @param IOperation $prevOp
185 | * @return IOperation
186 | */
187 | public function mergeWith($prevOp) {
188 | if (!$prevOp) {
189 | return $this;
190 | } else if ($prevOp instanceof SetOperation) {
191 | if (!is_array($prevOp->getValue())) {
192 | throw new \RuntimeException("Operation incompatible " .
193 | "with previous value.");
194 | }
195 | return new SetOperation($this->key,
196 | $this->applyOn($prevOp->getValue()));
197 | } else if (($prevOp instanceof ArrayOperation) &&
198 | ($this->getOpType() === $prevOp->getOpType())) {
199 | if ($this->getOpType() === "Remove") {
200 | $objects = array_merge($prevOp->getValue(), $this->getValue());
201 | } else {
202 | $objects = $this->applyOn($prevOp->getValue());
203 | }
204 | return new ArrayOperation($this->key,
205 | $objects,
206 | $this->getOpType());
207 | } else if ($prevOp instanceof DeleteOperation) {
208 | if ($this->getOpType() === "Remove") {
209 | return $prevOp;
210 | } else {
211 | return new SetOperation($this->getKey(), $this->applyOn(null));
212 | }
213 | } else {
214 | throw new \RuntimeException("Operation incompatible with" .
215 | " previous one.");
216 | }
217 | }
218 | }
219 |
220 |
--------------------------------------------------------------------------------
/src/LeanCloud/Operation/DeleteOperation.php:
--------------------------------------------------------------------------------
1 | key = $key;
19 | }
20 |
21 | /**
22 | * Get key of field the operation applies to.
23 | *
24 | * @return string
25 | */
26 | public function getKey() {
27 | return $this->key;
28 | }
29 |
30 | /**
31 | * Encode to JSON represented operation
32 | *
33 | * @return array
34 | */
35 | public function encode() {
36 | return array("__op" => "Delete");
37 | }
38 |
39 | /**
40 | * Apply this operation on an old value.
41 | *
42 | * @param mixed $oldval
43 | * @return null
44 | */
45 | public function applyOn($oldval=null) {
46 | return null;
47 | }
48 |
49 | /**
50 | * Merge this operation with (previous) operation.
51 | *
52 | * @param IOperation $prevOp
53 | * @return IOperation
54 | */
55 | public function mergeWith($prevOp) {
56 | return $this;
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/src/LeanCloud/Operation/IOperation.php:
--------------------------------------------------------------------------------
1 | key = $key;
34 | $this->value = $val;
35 | }
36 |
37 | /**
38 | * Get key of field the operation applies to
39 | *
40 | * @return string
41 | */
42 | public function getKey() {
43 | return $this->key;
44 | }
45 |
46 | /**
47 | * Get value of operation
48 | *
49 | * @return number
50 | */
51 | public function getValue() {
52 | return $this->value;
53 | }
54 |
55 | /**
56 | * Encode to JSON represented operation
57 | *
58 | * @return string json represented string
59 | */
60 | public function encode() {
61 | return array("__op" => "Increment",
62 | "amount" => $this->value);
63 | }
64 |
65 | /**
66 | * Apply operation on old value and returns new one
67 | *
68 | * @param mixed $oldval
69 | * @return mixed
70 | */
71 | public function applyOn($oldval) {
72 | $oldval = is_null($oldval) ? 0 : $oldval;
73 | if (is_numeric($oldval)) {
74 | return $this->value + $oldval;
75 | }
76 | throw new \RuntimeException("Operation incompatible with previous value.");
77 | }
78 |
79 | /**
80 | * Merge this operation into a (previous) operation.
81 | *
82 | * @param IOperation $prevOp
83 | * @return IOperation
84 | */
85 | public function mergeWith($prevOp) {
86 | if (!$prevOp) {
87 | return $this;
88 | } else if ($prevOp instanceof SetOperation) {
89 | return new SetOperation($this->getKey(),
90 | $this->applyOn($prevOp->getValue()));
91 | } else if ($prevOp instanceof IncrementOperation) {
92 | return new IncrementOperation($this->getKey(),
93 | $this->applyOn($prevOp->getValue()));
94 | } else if ($prevOp instanceof DeleteOperation){
95 | return new SetOperation($this->getKey(), $this->getValue());
96 | } else {
97 | throw new \RuntimeException("Operation incompatible with previous one.");
98 | }
99 | }
100 | }
101 |
102 |
--------------------------------------------------------------------------------
/src/LeanCloud/Operation/RelationOperation.php:
--------------------------------------------------------------------------------
1 | key = $key;
53 | // The op order here ensures add wins over remove
54 | $this->remove($removes);
55 | $this->add($adds);
56 | }
57 |
58 | /**
59 | * Get key of field the operation applies to.
60 | *
61 | * @return string
62 | */
63 | public function getKey() {
64 | return $this->key;
65 | }
66 |
67 | /**
68 | * Get target className of relation
69 | *
70 | * @return string
71 | */
72 | public function getTargetClassName() {
73 | return $this->targetClassName;
74 | }
75 |
76 | /**
77 | * Encode to JSON represented operation
78 | *
79 | * @return array
80 | */
81 | public function encode() {
82 | $adds = array("__op" => "AddRelation",
83 | "objects" => array());
84 | $removes = array("__op" => "RemoveRelation",
85 | "objects" => array());
86 | forEach($this->objects_to_add as $obj) {
87 | $adds["objects"][] = $obj->getPointer();
88 | }
89 | forEach($this->objects_to_remove as $obj) {
90 | $removes["objects"][] = $obj->getPointer();
91 | }
92 |
93 | if (empty($this->objects_to_remove)) {
94 | return $adds;
95 | }
96 | if (empty($this->objects_to_add)) {
97 | return $removes;
98 | }
99 | return array("__op" => "Batch",
100 | "ops" => array($adds, $removes));
101 | }
102 |
103 | /**
104 | * Add object(s) to relation
105 | *
106 | * @param array $objects LeanObject(s) to add
107 | */
108 | private function add($objects) {
109 | if (empty($objects)) { return; }
110 | if (!$this->targetClassName) {
111 | $this->targetClassName = current($objects)->getClassName();
112 | }
113 | forEach($objects as $obj) {
114 | if (!$obj->getObjectId()) {
115 | throw new \RuntimeException("Cannot add unsaved object" .
116 | " to relation.");
117 | }
118 | if ($obj->getClassName() !== $this->targetClassName) {
119 | throw new \RuntimeException("LeanObject type incompatible" .
120 | " with relation.");
121 | }
122 | if (isset($this->objects_to_remove[$obj->getObjectID()])) {
123 | unset($this->objects_to_remove[$obj->getObjectID()]);
124 | }
125 | $this->objects_to_add[$obj->getObjectId()] = $obj;
126 | }
127 | }
128 |
129 | /**
130 | * Remove object(s) from relation
131 | *
132 | * @param array $objects LeanObject(s) to remove
133 | */
134 | private function remove($objects) {
135 | if (empty($objects)) { return; }
136 | if (!$this->targetClassName) {
137 | $this->targetClassName = current($objects)->getClassName();
138 | }
139 | forEach($objects as $obj) {
140 | if (!$obj->getObjectId()) {
141 | throw new \RuntimeException("Cannot remove unsaved object" .
142 | " from relation.");
143 | }
144 | if ($obj->getClassName() !== $this->targetClassName) {
145 | throw new \RuntimeException("LeanObject type incompatible" .
146 | " with relation.");
147 | }
148 | if (isset($this->objects_to_add[$obj->getObjectID()])) {
149 | unset($this->objects_to_add[$obj->getObjectID()]);
150 | }
151 | $this->objects_to_remove[$obj->getObjectId()] = $obj;
152 | }
153 | }
154 |
155 | /**
156 | * Apply the operation on previous relation
157 | *
158 | * @param Relation $relation Previous relation
159 | * @param LeanObject $object Parent of relation
160 | * @return Relation
161 | * @throws RuntimeException
162 | */
163 | public function applyOn($relation, $object=null) {
164 | if (!$relation) {
165 | return new Relation($object, $this->getKey(),
166 | $this->getTargetClassName());
167 | }
168 | if (!($relation instanceof Relation)) {
169 | throw new \RuntimeException("Operation incompatible with " .
170 | "previous value.");
171 | }
172 | // TODO: check target class
173 | return $relation;
174 | }
175 |
176 | /**
177 | * Merge with (previous) operation
178 | *
179 | * @param IOperation $prevOp Previous operation
180 | * @return IOperation
181 | */
182 | public function mergeWith($prevOp) {
183 | if (!$prevOp) {
184 | return $this;
185 | }
186 | if ($prevOp instanceof RelationOperation) {
187 | $adds = array_merge($this->objects_to_add,
188 | $prevOp->objects_to_add);
189 | $removes = array_merge($this->objects_to_remove,
190 | $prevOp->objects_to_remove);
191 | return new RelationOperation($this->getKey(), $adds, $removes);
192 | } else {
193 | throw new \RuntimeException("Operation incompatible with " .
194 | "previous one.");
195 | }
196 | }
197 | }
198 |
199 |
--------------------------------------------------------------------------------
/src/LeanCloud/Operation/SetOperation.php:
--------------------------------------------------------------------------------
1 | key = $key;
35 | $this->value = $val;
36 | }
37 |
38 | /**
39 | * Get key of field the operation applies to
40 | *
41 | * @return string
42 | */
43 | public function getKey() {
44 | return $this->key;
45 | }
46 |
47 | /**
48 | * Get value of operation
49 | *
50 | * @return mixed
51 | */
52 | public function getValue() {
53 | return $this->value;
54 | }
55 |
56 | /**
57 | * Encode to JSON represented operation
58 | *
59 | * @return array
60 | */
61 | public function encode() {
62 | return Client::encode($this->value);
63 | }
64 |
65 | /**
66 | * Apply operation on old value and returns new one
67 | *
68 | * @param mixed $oldval
69 | * @return mixed
70 | */
71 | public function applyOn($oldval) {
72 | return $this->value;
73 | }
74 |
75 | /**
76 | * Merge this operation with (previous) operation
77 | *
78 | * @param IOperation $prevOp
79 | * @return IOperation
80 | */
81 | public function mergeWith($prevOp) {
82 | return $this;
83 | }
84 | }
85 |
86 |
--------------------------------------------------------------------------------
/src/LeanCloud/Push.php:
--------------------------------------------------------------------------------
1 | data = $data;
32 | $this->options = $options;
33 | $this->options["prod"] = Client::$isProduction ? "prod": "dev";
34 | }
35 |
36 | /**
37 | * Set notification data attributes
38 | *
39 | * Available attributes please see
40 | * https://leancloud.cn/docs/push_guide.html#%E6%8E%A8%E9%80%81%E6%B6%88%E6%81%AF
41 | *
42 | * @param string $key Attribute key
43 | * @param mixed $val Attribute value
44 | * @return self
45 | */
46 | public function setData($key, $val) {
47 | $this->data[$key] = $val;
48 | }
49 |
50 | /**
51 | * Set general option for notificiation
52 | *
53 | * Available options please see
54 | * https://leancloud.cn/docs/push_guide.html#%E6%8E%A8%E9%80%81%E6%B6%88%E6%81%AF
55 | *
56 | * There are helper methods for setting most of options, use those
57 | * if possible. Use this when no helper present, e.g. to enable
58 | * "dev" environment in iOS:
59 | *
60 | * ```php
61 | * $push->setOption("prod", "dev");
62 | * ```
63 | *
64 | * @param string $key Option key
65 | * @param mixed $val Option value
66 | * @return self
67 | * @see self::setWhere, self::setChannels, self::setPushTime ...
68 | */
69 | public function setOption($key, $val) {
70 | $this->options[$key] = $val;
71 | return $this;
72 | }
73 |
74 | /**
75 | * Set target channels
76 | *
77 | * @param array $channels List of channel names
78 | * @return self
79 | * @see self::setOption()
80 | */
81 | public function setChannels($channels) {
82 | return $this->setOption("channels", $channels);
83 | }
84 |
85 | /**
86 | * Filter target devices by query
87 | *
88 | * The query must be over _Installation table.
89 | *
90 | * @param Query $query A query over _Installation
91 | * @return self
92 | * @see self::setOption()
93 | */
94 | public function setWhere(Query $query) {
95 | if ($query->getClassName() != "_Installation") {
96 | throw new \RuntimeException("Query must be over " .
97 | "_Installation table.");
98 | }
99 | return $this->setOption("where", $query);
100 | }
101 |
102 | /**
103 | * Schedule a time to send message
104 | *
105 | * @param DateTime $time Time to send message to clients
106 | * @return self
107 | * @see self::setOption()
108 | */
109 | public function setPushTime(\DateTime $time) {
110 | return $this->setOption("push_time", $time);
111 | }
112 |
113 | /**
114 | * Set expiration interval for message
115 | *
116 | * When client received message after the interval, it will not be
117 | * displayed to user.
118 | *
119 | * @param int $interval Number of seconds (from now) to expire message
120 | * @return self
121 | * @see self::setOption()
122 | */
123 | public function setExpirationInterval($interval) {
124 | return $this->setOption("expiration_interval", $interval);
125 | }
126 |
127 | /**
128 | * Set expiration time for message
129 | *
130 | * When client received message after the specified time, it will
131 | * not be displayed to user.
132 | *
133 | * @param DateTime $time Time to expire message
134 | * @return self
135 | * @see self::setOption()
136 | */
137 | public function setExpirationTime(\DateTime $time) {
138 | return $this->setOption("expiration_time", $time);
139 | }
140 |
141 | /**
142 | * Enable smooth push for message
143 | *
144 | * @param int $flowControl clients to push per second,
145 | * a value <1000 is equivalent to 1000.
146 | * @return self
147 | * @see self::setOption()
148 | */
149 | public function setFlowControl($flowControl) {
150 | return $this->setOption("flow_control", $flowControl);
151 | }
152 |
153 | /**
154 | * Encode to JSON representation
155 | *
156 | * @return array
157 | */
158 | public function encode() {
159 | $out = $this->options;
160 | $out["data"] = $this->data;
161 | $expire = isset($this->options["expiration_time"]) ? $this->options["expiration_time"] : null;
162 | if (($expire instanceof \DateTime) ||
163 | ($expire instanceof \DateTimeImmutable)) {
164 | $out["expiration_time"] = Client::formatDate($expire);
165 | }
166 | $pushTime = isset($this->options["push_time"]) ? $this->options["push_time"] : null;
167 | if (($pushTime instanceof \DateTime) ||
168 | ($pushTime instanceof \DateTimeImmutable)){
169 | $out["push_time"] = Client::formatDate($pushTime);
170 | }
171 | if (isset($this->options["where"])) {
172 | $query = $this->options["where"]->encode();
173 | $out["where"] = json_decode($query["where"], true);
174 | }
175 | return $out;
176 | }
177 |
178 | /**
179 | * Send notification to LeanCloud
180 | *
181 | * @return array
182 | */
183 | public function send() {
184 | $out = $this->encode();
185 | $resp = Client::post("/push", $out);
186 | return $resp;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/LeanCloud/Region.php:
--------------------------------------------------------------------------------
1 | getRelation($key)` instead.
41 | *
42 | * @param LeanObject $parent Parent object
43 | * @param string $key Field key on parent object
44 | * @param string $className ClassName the object relatedTo
45 | */
46 | public function __construct($parent, $key, $className=null) {
47 | $this->parent = $parent;
48 | $this->key = $key;
49 | $this->targetClassName = $className;
50 | }
51 |
52 | /**
53 | * Encode to JSON representation of relation.
54 | *
55 | * @return array
56 | */
57 | public function encode() {
58 | return array("__type" => "Relation",
59 | "className" => $this->targetClassName);
60 | }
61 |
62 | /**
63 | * Attempt to set and validate parent of relation
64 | *
65 | * @param LeanObject $parent Parent object of relation
66 | * @param string $key Field key
67 | * @throws RuntimeException
68 | */
69 | public function setParentAndKey($parent, $key) {
70 | if ($this->parent && $this->parent != $parent) {
71 | throw new \RuntimeException("Relation does not belong to the object");
72 | }
73 | if ($this->key && $this->key != $key) {
74 | throw new \RuntimeException("Relation does not belong to the field");
75 | }
76 | $this->parent = $parent;
77 | $this->key = $key;
78 | }
79 |
80 | /**
81 | * Get target className of relation
82 | *
83 | * @return string
84 | */
85 | public function getTargetClassName() {
86 | return $this->targetClassName;
87 | }
88 |
89 | /**
90 | * Add object(s) to the field as relation
91 | *
92 | * @param object|array $objects LeanObject(s) to add
93 | */
94 | public function add($objects) {
95 | if (!is_array($objects)) { $objects = array($objects); }
96 | $op = new RelationOperation($this->key, $objects, null);
97 | $this->parent->set($this->key, $op);
98 | if (!$this->targetClassName) {
99 | $this->targetClassName = $op->getTargetClassName();
100 | }
101 | }
102 |
103 | /**
104 | * Remove object(s) from the field
105 | *
106 | * @param object|array $objects LeanObject(s) to remove
107 | */
108 | public function remove($objects) {
109 | if (!is_array($objects)) { $objects = array($objects); }
110 | $op = new RelationOperation($this->key, null, $objects);
111 | $this->parent->set($this->key, $op);
112 | if (!$this->targetClassName) {
113 | $this->targetClassName = $op->getTargetClassName();
114 | }
115 | }
116 |
117 | /**
118 | * Query on the target class of relation
119 | *
120 | * @return Query
121 | */
122 | public function getQuery() {
123 | if ($this->targetClassName) {
124 | $query = new Query($this->targetClassName);
125 | } else {
126 | $query = new Query($this->parent->getClassName());
127 | $query->addOption("redirectClassNameForKey", $this->key);
128 | }
129 | $query->relatedTo($this->key, $this->parent);
130 | return $query;
131 | }
132 |
133 | /**
134 | * Query on the parent class where child is in the relation
135 | *
136 | * @param LeanObject $child Child object
137 | * @return Query
138 | */
139 | public function getReverseQuery(LeanObject $child) {
140 | $query = new Query($this->parent->getClassName());
141 | $query->equalTo($this->key, $child->getPointer());
142 | return $query;
143 | }
144 |
145 | }
146 |
147 |
--------------------------------------------------------------------------------
/src/LeanCloud/Role.php:
--------------------------------------------------------------------------------
1 | getUsers()`, which
13 | * is an instance of Relation, where users can be added or
14 | * removed.
15 | *
16 | * Roles can belong to role as well, which can be got by
17 | * `$role->getRoles()`, where roles can be added or removed.
18 | *
19 | * @see ACL, Relation
20 | */
21 | class Role extends LeanObject {
22 | /**
23 | * Table name on LeanCloud
24 | * @var string
25 | */
26 | protected static $className = "_Role";
27 |
28 | /**
29 | * Set name of role
30 | *
31 | * The name can contain only alphanumeric characters, _, -, and
32 | * space. It cannot be changed after being saved.
33 | *
34 | * @return Role
35 | */
36 | public function setName($name) {
37 | $this->set("name", $name);
38 | return $this;
39 | }
40 |
41 | /**
42 | * Get name of role
43 | *
44 | * @return string
45 | */
46 | public function getName() {
47 | return $this->get("name");
48 | }
49 |
50 | /**
51 | * Get a relation of users that belongs to this role
52 | *
53 | * @return Relation
54 | */
55 | public function getUsers() {
56 | return $this->getRelation("users");
57 | }
58 |
59 | /**
60 | * Get a relation of roles that belongs to this role
61 | *
62 | * @return Relation
63 | */
64 | public function getRoles() {
65 | return $this->getRelation("roles");
66 | }
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/src/LeanCloud/SMS.php:
--------------------------------------------------------------------------------
1 | $v) {
34 | if (!isset($options[$k])) {
35 | unset($options[$k]);
36 | }
37 | }
38 | $options["mobilePhoneNumber"] = $phoneNumber;
39 | Client::post("/requestSmsCode", $options);
40 | }
41 |
42 | /**
43 | * Verify SMS code
44 | *
45 | * @param string $phoneNumber
46 | * @param string $smsCode
47 | */
48 | public static function verifySmsCode($phoneNumber, $smsCode) {
49 | Client::post("/verifySmsCode/{$smsCode}?mobilePhoneNumber={$phoneNumber}",
50 | null);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/LeanCloud/SaveOption.php:
--------------------------------------------------------------------------------
1 | fetchWhenSave)) {
32 | $params["fetchWhenSave"] = $this->fetchWhenSave ? true : false;
33 | }
34 | if (!is_null($this->where)) {
35 | if ($this->where instanceof Query) {
36 | $out = $this->where->encode();
37 | $params["where"] = $out["where"];
38 | } else {
39 | throw new \RuntimeException("where of SaveOption must be Query object.");
40 | }
41 | }
42 | return $params;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/LeanCloud/Storage/CookieStorage.php:
--------------------------------------------------------------------------------
1 | expireIn = time() + $seconds;
57 | $this->path = $path;
58 | $this->domain = $domain;
59 | }
60 |
61 | /**
62 | * Set value by key
63 | *
64 | * @param string $key
65 | * @param mixed $val
66 | * @param int $seconds Number of seconds to live
67 | * @return $this
68 | */
69 | public function set($key, $val, $seconds=null) {
70 | $expire = $seconds ? (time() + seconds) : $this->expireIn;
71 | setcookie($key, $val, $expire, $this->path, $this->domain);
72 | }
73 |
74 | /**
75 | * Get value by key
76 | *
77 | * @param string $key
78 | * @return mixed
79 | */
80 | public function get($key) {
81 | if (isset($_COOKIE[$key])) {
82 | return $_COOKIE[$key];
83 | }
84 | return null;
85 | }
86 |
87 | /**
88 | * Remove key from storage
89 | *
90 | * @param string $key
91 | */
92 | public function remove($key) {
93 | setcookie($key, false, 1);
94 | }
95 |
96 | /**
97 | * Clear all data in storage
98 | *
99 | * @throws RuntimeException
100 | */
101 | public function clear() {
102 | throw new \RuntimeException("Not implemented error.");
103 | }
104 | }
105 |
106 |
--------------------------------------------------------------------------------
/src/LeanCloud/Storage/IStorage.php:
--------------------------------------------------------------------------------
1 | multipartEncode(array(
22 | "name" => $key,
23 | "mimeType" => $mimeType,
24 | "content" => $content,
25 | ), array(
26 | "op" => "upload",
27 | "sha" => hash("sha1", $content)
28 | ), $boundary);
29 |
30 | $headers[] = "User-Agent: " . Client::getVersionString();
31 | $headers[] = "Content-Type: multipart/form-data;" .
32 | " boundary={$boundary}";
33 | // $headers[] = "Content-Length: " . strlen($body);
34 | $headers[] = "Authorization: {$this->getAuthToken()}";
35 | $url = $this->getUploadUrl();
36 | $ch = curl_init($url);
37 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
38 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
39 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
40 | curl_setopt($ch, CURLOPT_POST, 1);
41 | curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
42 | $resp = curl_exec($ch);
43 | $respCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
44 | $respType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
45 | $error = curl_error($ch);
46 | $errno = curl_errno($ch);
47 | curl_close($ch);
48 |
49 | /** type of error:
50 | * - curl error
51 | * - http status error 4xx, 5xx
52 | * - rest api error
53 | */
54 | if ($errno > 0) {
55 | throw new \RuntimeException("CURL ($url) error: " .
56 | "{$errno} {$error}",
57 | $errno);
58 | }
59 |
60 | $data = json_decode($resp, true);
61 | if ($data["code"] != 0) {
62 | throw new \RuntimeException("Upload to Qcloud ({$url}) failed: ".
63 | "{$data['code']} {$data['message']}",
64 | $data["code"]);
65 | }
66 | return $data;
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/LeanCloud/Uploader/QiniuUploader.php:
--------------------------------------------------------------------------------
1 | multipartEncode(array(
35 | "name" => $key,
36 | "mimeType" => $mimeType,
37 | "content" => $content,
38 | ), array(
39 | "token" => $this->getAuthToken(),
40 | "key" => $key,
41 | "crc32" => $this->crc32Data($content)
42 | ), $boundary);
43 |
44 | $headers[] = "User-Agent: " . Client::getVersionString();
45 | $headers[] = "Content-Type: multipart/form-data;" .
46 | " boundary={$boundary}";
47 | $headers[] = "Content-Length: " . strlen($body);
48 |
49 | $url = $this->getUploadUrl();
50 | $ch = curl_init($url);
51 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
52 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
53 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
54 | curl_setopt($ch, CURLOPT_POST, 1);
55 | curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
56 | $resp = curl_exec($ch);
57 | $respCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
58 | $respType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
59 | $error = curl_error($ch);
60 | $errno = curl_errno($ch);
61 | curl_close($ch);
62 |
63 | /** type of error:
64 | * - curl error
65 | * - http status error 4xx, 5xx
66 | * - rest api error
67 | */
68 | if ($errno > 0) {
69 | throw new \RuntimeException("CURL ($url) error: " .
70 | "{$errno} {$error}",
71 | $errno);
72 | }
73 |
74 | $data = json_decode($resp, true);
75 | if (isset($data["error"])) {
76 | $code = isset($data["code"]) ? $data["code"] : 1;
77 | throw new \RuntimeException("Upload to Qiniu ({$url}) failed: ".
78 | "{$code} {$data['error']}", $code);
79 | }
80 | return $data;
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/LeanCloud/Uploader/S3Uploader.php:
--------------------------------------------------------------------------------
1 | getUploadUrl()) {
16 | throw new \RuntimeException("Please initialize with pre-signed url.");
17 | }
18 | $headers[] = "User-Agent: " . Client::getVersionString();
19 | $headers[] = "Content-Type: $mimeType";
20 | $url = $this->getUploadUrl();
21 | $ch = curl_init($url);
22 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
23 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
24 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
25 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
26 | curl_setopt($ch, CURLOPT_POSTFIELDS, $content);
27 | $resp = curl_exec($ch);
28 | $respCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
29 | $respType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
30 | $error = curl_error($ch);
31 | $errno = curl_errno($ch);
32 | curl_close($ch);
33 |
34 | if ($errno > 0) {
35 | throw new \RuntimeException("CURL ({$url}) error: " .
36 | "{$errno} {$error}",
37 | $errno);
38 | }
39 |
40 | if ($respCode >= "300") {
41 | $S3Error = simplexml_load_string($resp);
42 | throw new \RuntimeException("Upload to S3 ({$url}) failed: " .
43 | "{$S3Error->Code} {$S3Error->Message}");
44 | }
45 | return true;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/LeanCloud/Uploader/SimpleUploader.php:
--------------------------------------------------------------------------------
1 | $val) {
47 | $body .= "--{$boundary}\r\n";
48 | $body .= "Content-Disposition: form-data; name=\"{$key}\"\r\n\r\n";
49 | $body .= "{$val}\r\n";
50 | }
51 |
52 | if (!empty($file)) {
53 | $mimeType = "application/octet-stream";
54 | if (isset($file["mimeType"])) {
55 | $mimeType = $file["mimeType"];
56 | }
57 | $fieldname = static::getFileFieldName();
58 | // escape quotes in file name
59 | $filename = filter_var($file["name"],
60 | FILTER_SANITIZE_MAGIC_QUOTES);
61 |
62 | $body .= "--{$boundary}\r\n";
63 | $body .= "Content-Disposition: form-data; name=\"{$fieldname}\"; filename=\"{$filename}\"\r\n";
64 | $body .= "Content-Type: {$mimeType}\r\n\r\n";
65 | $body .= "{$file['content']}\r\n";
66 | }
67 |
68 | // append end frontier
69 | $body .= "--{$boundary}--\r\n";
70 |
71 | return $body;
72 | }
73 |
74 | /**
75 | * Initialize uploader with url and auth token
76 | *
77 | * @param string $uploadUrl File provider url
78 | * @param string $authToken Auth token for file provider
79 | */
80 | public function initialize($uploadUrl, $authToken) {
81 | $this->uploadUrl = $uploadUrl;
82 | $this->authToken = $authToken;
83 | }
84 |
85 | public function getUploadUrl() {
86 | return $this->uploadUrl;
87 | }
88 |
89 | public function getAuthToken() {
90 | return $this->authToken;
91 | }
92 |
93 | abstract public function upload($content, $mimeType, $key);
94 | }
95 |
--------------------------------------------------------------------------------
/src/autoload.php:
--------------------------------------------------------------------------------
1 | encode();
22 | $this->assertEquals(true, $out["id123"]["read"]);
23 | $this->assertEquals(true, $out["id123"]["write"]);
24 | }
25 |
26 | /**
27 | * Empty ACL should be encoded as object, instead of array.
28 | *
29 | * @link https://github.com/leancloud/php-sdk/issues/84
30 | */
31 | public function testEmptyACL() {
32 | $acl = new ACL();
33 | $out = $acl->encode();
34 | $this->assertEquals("{}", json_encode($out));
35 | }
36 |
37 | public function testSetPublicAccess() {
38 | $acl = new ACL();
39 | $acl->setPublicReadAccess(true);
40 | $out = $acl->encode();
41 | $this->assertEquals(true, $out[ACL::PUBLIC_KEY]["read"]);
42 | $this->assertEquals(true, $acl->getPublicReadAccess());
43 |
44 | $acl->setPublicWriteAccess(false);
45 | $out = $acl->encode();
46 | $this->assertEquals(false, $out[ACL::PUBLIC_KEY]["write"]);
47 | $this->assertEquals(false, $acl->getPublicWriteAccess());
48 | }
49 |
50 | public function testSetUserAccess() {
51 | $user = new User(null, "id123");
52 | $acl = new ACL();
53 | $acl->setReadAccess($user, true);
54 | $out = $acl->encode();
55 | $this->assertEquals(true, $out[$user->getObjectId()]["read"]);
56 | $this->assertEquals(true, $acl->getReadAccess($user));
57 |
58 | $acl->setWriteAccess($user, false);
59 | $out = $acl->encode();
60 | $this->assertEquals(false, $out[$user->getObjectId()]["write"]);
61 | $this->assertEquals(false, $acl->getWriteAccess($user));
62 | }
63 |
64 | public function testSetRoleAccess() {
65 | $role = new Role();
66 | $role->setName("admin");
67 | $role->setACL(new ACL());
68 | $acl = new ACL();
69 | $acl->setRoleReadAccess($role, true);
70 | $out = $acl->encode();
71 | $this->assertEquals(true, $out["role:admin"]["read"]);
72 | $this->assertEquals(true, $acl->getRoleReadAccess($role));
73 |
74 | $acl->setRoleWriteAccess($role, false);
75 | $out = $acl->encode();
76 | $this->assertEquals(false, $out["role:admin"]["write"]);
77 | $this->assertEquals(false, $acl->getRoleWriteAccess($role));
78 | }
79 |
80 | public function testSetRoleAccessWithRoleName() {
81 | $acl = new ACL();
82 | $acl->setRoleReadAccess("admin", true);
83 | $out = $acl->encode();
84 | $this->assertEquals(true, $out["role:admin"]["read"]);
85 |
86 | $acl->setRoleWriteAccess("admin", false);
87 | $out = $acl->encode();
88 | $this->assertEquals(false, $out["role:admin"]["write"]);
89 | }
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/test/AppRouterTest.php:
--------------------------------------------------------------------------------
1 | genId(12));
20 | $router->setRegion("CN_E1");
21 | $router->setRegion("US");
22 | $router->setRegion(Region::CN_E1);
23 | $router->setRegion(Region::US);
24 | }
25 |
26 | public function testGetRoute() {
27 | $this->markTestSkipped("app-router no longer available");
28 | $appid = getenv("LEANCLOUD_APP_ID");
29 | $router = AppRouter::getInstance($appid);
30 | $host = $router->getRoute(AppRouter::API_SERVER_KEY);
31 | $domain = getenv("LEANCLOUD_WILDCARD_DOMAIN");
32 | $this->assertEquals("{$this->getShortAppId($appid)}.api.{$domain}", $host);
33 |
34 | $host = $router->getRoute(AppRouter::ENGINE_SERVER_KEY);
35 | $domain = getenv("LEANCLOUD_WILDCARD_DOMAIN");
36 | $this->assertEquals("{$this->getShortAppId($appid)}.engine.{$domain}", $host);
37 | }
38 |
39 | public function testGetRouteWhenAppRouterNotAvailable() {
40 | $appid = $this->genId(18);
41 | $router = AppRouter::getInstance($appid);
42 | $router_url = getenv("LEANCLOUD_APP_ROUTER");
43 | putenv("LEANCLOUD_APP_ROUTER=http://localhost:4000/route?appId=");
44 | $this->assertEquals($router->getRegionDefaultRoute(AppRouter::ENGINE_SERVER_KEY),
45 | $router->getRoute(AppRouter::ENGINE_SERVER_KEY));
46 |
47 | putenv("LEANCLOUD_APP_ROUTER={$router_url}");
48 | $host = $router->getRoute(AppRouter::API_SERVER_KEY);
49 | $this->assertEquals($router->getRegionDefaultRoute(AppRouter::API_SERVER_KEY),
50 | $host);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/test/BytesTest.php:
--------------------------------------------------------------------------------
1 | encode();
10 | $this->assertEquals("Bytes", $out["__type"]);
11 | $this->assertEquals("", $out["base64"]);
12 | }
13 |
14 | public function testEncodeArray() {
15 | $bytes = Bytes::createFromByteArray(array(72, 101, 108, 108, 111));
16 | $out = $bytes->encode();
17 | $this->assertEquals("Bytes", $out["__type"]);
18 | $this->assertEquals(base64_encode("Hello"), $out["base64"]);
19 | }
20 |
21 | public function testCreateFromEmptyString() {
22 | $bytes = Bytes::createFromBase64Data(base64_encode(""));
23 | $this->assertEmpty($bytes->getByteArray());
24 | $this->assertEquals("", $bytes->asString());
25 | }
26 |
27 | public function testCreateFromBase64() {
28 | $bytes = Bytes::createFromByteArray(array(72, 101, 108, 108, 111));
29 | $bytes1 = Bytes::createFromBase64Data(base64_encode("Hello"));
30 | $this->assertEquals($bytes->getByteArray(), $bytes1->getByteArray());
31 | $this->assertEquals("Hello", $bytes->asString());
32 | $this->assertEquals("Hello", $bytes1->asString());
33 | }
34 |
35 | public function testEncodeCreateFromBase64() {
36 | $bytes = Bytes::createFromBase64Data(base64_encode("Hello"));
37 | $out = $bytes->encode();
38 | $this->assertEquals(base64_encode("Hello"), $out["base64"]);
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/test/CloudTest.php:
--------------------------------------------------------------------------------
1 | setUsername("alice");
17 | $user->setPassword("blabla");
18 | $user->setEmail("alice@example.com");
19 | try {
20 | $user->signUp();
21 | } catch (CloudException $ex) {
22 | // skip
23 | }
24 | }
25 |
26 | public static function tearDownAfterClass() {
27 | // destroy default user if present
28 | try {
29 | $user = User::logIn("alice", "blabla");
30 | $user->destroy();
31 | } catch (CloudException $ex) {
32 | // skip
33 | }
34 | }
35 |
36 |
37 |
38 | public function testGetKeys() {
39 | $name = uniqid();
40 | Cloud::define($name, function($params, $user) {
41 | return "hello";
42 | });
43 | $this->assertContains($name, Cloud::getKeys());
44 | }
45 |
46 | public function testDefineFunctionWithoutArg() {
47 | // user function are free to accept positional arguments,
48 | // this one should not error out.
49 | Cloud::define("hello", function() {
50 | return "hello";
51 | });
52 | $result = Cloud::run("hello", array("name" => "alice"), null);
53 | $this->assertEquals("hello", $result);
54 | }
55 |
56 | public function testFunctionWithoutArg() {
57 | Cloud::define("hello", function($params, $user) {
58 | return "hello";
59 | });
60 |
61 | $result = Cloud::run("hello", array(), null);
62 | $this->assertEquals("hello", $result);
63 | }
64 |
65 | public function testFunctionWithArg() {
66 | Cloud::define("sayHello", function($params, $user) {
67 | return "hello {$params['name']}";
68 | });
69 |
70 | $result = Cloud::run("sayHello", array("name" => "alice"), null);
71 | $this->assertEquals("hello alice", $result);
72 | }
73 |
74 | public function testFunctionAcceptMeta() {
75 | Cloud::define("getMeta", function($params, $user, $meta) {
76 | return $meta['remoteAddress'];
77 | });
78 |
79 | $result = Cloud::run("getMeta",
80 | array("name" => "alice"),
81 | null,
82 | array("remoteAddress" => "10.0.0.1")
83 | );
84 | $this->assertEquals("10.0.0.1", $result);
85 | }
86 |
87 | public function testRemoteFunction() {
88 | // Assumes [LeanFunction] is deployed at this application's LeanEngine.
89 | // [LeanFunction]: https://github.com/leancloud/LeanFunction
90 | $response = Cloud::runRemote("hello", []);
91 | $result = $response["result"];
92 | $this->assertEquals("Hello world!", $result);
93 | }
94 |
95 | public function testRemoteFunctionWithSession() {
96 | // See testRemoteFunction for dependencies.
97 | try {
98 | User::logIn("alice", "blabla");
99 | } catch (\LeanCloud\CloudException $e) {
100 | // skip
101 | }
102 | $token = User::getCurrentSessionToken();
103 | $response = Cloud::runRemote("echo-session-token", [], $token);
104 | $result = $response["result"];
105 | $this->assertEquals($token, $result);
106 | }
107 |
108 | public function testClassHook() {
109 | forEach(array("beforeSave", "afterSave",
110 | "beforeUpdate", "afterUpdate",
111 | "beforeDelete", "afterDelete") as $hookName) {
112 | $count = 42;
113 | call_user_func(
114 | array("LeanCloud\Engine\Cloud", $hookName),
115 | "TestObject",
116 | function($obj, $user) use (&$count) {
117 | $count += 1;
118 | }
119 | );
120 | Cloud::runHook("TestObject", $hookName, null, null);
121 | $this->assertEquals(43, $count);
122 | }
123 | }
124 |
125 | public function testOnVerifiedHook() {
126 | // use a closure to ensure hook being executed
127 | $count = 42;
128 | Cloud::onVerified("sms", function($user) use (&$count) {
129 | $count += 1;
130 | });
131 | Cloud::runOnVerified("sms", null);
132 | $this->assertEquals(43, $count);
133 | }
134 |
135 | public function testOnLogin() {
136 | $count = 42;
137 | Cloud::onLogin(function($user) use (&$count) {
138 | $count += 1;
139 | });
140 | Cloud::runOnLogin(null);
141 | $this->assertEquals(43, $count);
142 | }
143 |
144 | public function testOnInsight() {
145 | $count = 42;
146 | Cloud::onInsight(function($job) use (&$count) {
147 | $count += 1;
148 | });
149 | Cloud::runOnInsight(null);
150 | $this->assertEquals(43, $count);
151 | }
152 |
153 | }
154 |
155 |
--------------------------------------------------------------------------------
/test/DeleteOperationTest.php:
--------------------------------------------------------------------------------
1 | encode();
13 | $this->assertEquals("Delete", $out["__op"]);
14 | }
15 |
16 | public function testApplyOperation() {
17 | $op = new DeleteOperation("tags");
18 | $this->assertNull($op->applyOn());
19 | }
20 |
21 | public function testMergeWithAnyOp() {
22 | $op = new DeleteOperation("tags");
23 |
24 | $op2 = $op->mergeWith(null);
25 | $this->assertTrue($op2 instanceof DeleteOperation);
26 |
27 | $op2 = $op->mergeWith(new SetOperation("tags", "foo"));
28 | $this->assertTrue($op2 instanceof DeleteOperation);
29 |
30 | $op2 = $op->mergeWith(new DeleteOperation("tags"));
31 | $this->assertTrue($op2 instanceof DeleteOperation);
32 |
33 | $op2 = $op->mergeWith(new IncrementOperation("tags", 1));
34 | $this->assertTrue($op2 instanceof DeleteOperation);
35 |
36 | $op2 = $op->mergeWith(new ArrayOperation("tags",
37 | array("frontend"),
38 | "Add"));
39 | $this->assertTrue($op2 instanceof DeleteOperation);
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/test/FileTest.php:
--------------------------------------------------------------------------------
1 | assertEquals("", $file->getName());
19 | }
20 |
21 | public function testInitializeMimeType() {
22 | $file = new File("test.txt");
23 | $this->assertEquals("text/plain", $file->getMimeType());
24 |
25 | $file = new File("test.txt", null, "image/png");
26 | $this->assertEquals("image/png", $file->getMimeType());
27 | }
28 |
29 | public function testCreateWithURL() {
30 | $file = File::createWithUrl("blabla.png", "https://leancloud.cn/favicon.png");
31 | $this->assertEquals("blabla.png", $file->getName());
32 | $this->assertEquals("https://leancloud.cn/favicon.png", $file->getUrl());
33 | $this->assertEquals("image/png", $file->getMimeType());
34 | }
35 |
36 | public function testCreateWithLocalFile() {
37 | $file = File::createWithLocalFile(__FILE__);
38 | $this->assertEquals("FileTest.php", $file->getName());
39 | }
40 |
41 | public function testSaveTextFile() {
42 | $file = File::createWithData("test.txt", "Hello World!");
43 | $this->assertNull($file->getKey());
44 | $file->save();
45 | $this->assertNotEmpty($file->getObjectId());
46 | $this->assertNotEmpty($file->getKey());
47 | $this->assertNotEmpty($file->getUrl());
48 | $this->assertNotEmpty($file->getName());
49 | $this->assertEquals("text/plain", $file->getMimeType());
50 | $content = file_get_contents($file->getUrl());
51 | $this->assertEquals("Hello World!", $content);
52 |
53 | $file->destroy();
54 | }
55 |
56 | public function testSaveUTF8TextFile() {
57 | $file = File::createWithData("testChinese.txt", "你好,中国!");
58 | $file->save();
59 | $this->assertNotEmpty($file->getUrl());
60 | $this->assertEquals("text/plain", $file->getMimeType());
61 | $content = file_get_contents($file->getUrl());
62 | $this->assertEquals("你好,中国!", $content);
63 |
64 | $file->destroy();
65 | }
66 |
67 | public function testSaveLocalFileWithMimeTypeAndName() {
68 | $file = File::createWithLocalFile(__FILE__, "application/x-php", "FileTest.php");
69 | $file->save();
70 | $this->assertNotEmpty($file->getUrl());
71 | $this->assertEquals("application/x-php", $file->getMimeType());
72 |
73 | $file->destroy();
74 | }
75 |
76 | public function testSaveWithSpecifiedKeyWithoutMasterKey() {
77 | $file = File::createWithData("test.txt", "Hello World!");
78 | $file->setKey("abc");
79 | $this->assertEquals("abc", $file->getKey());
80 | $unsupportedKeyError = "Unsupported file key. Please use masterKey to set file key.";
81 | $this->setExpectedException("LeanCloud\CloudException", $unsupportedKeyError, 1);
82 | $file->save();
83 | $this->assertEmpty($file->getObjectId());
84 | }
85 |
86 | public function testSaveExternalFile() {
87 | $file = File::createWithUrl("blabla.png", "https://leancloud.cn/favicon.png");
88 | $file->save();
89 | $this->assertNotEmpty($file->getObjectId());
90 | $this->assertEquals("blabla.png", $file->getName());
91 | $this->assertEquals("https://leancloud.cn/favicon.png", $file->getUrl());
92 | $this->assertEquals("image/png", $file->getMimeType());
93 |
94 | $file->destroy();
95 | }
96 |
97 | public function testFetchFile() {
98 | $file = File::createWithData("testFetch.txt", "你好,中国!");
99 | $file->save();
100 | $file2 = File::fetch($file->getObjectId());
101 | // `uploadResult.getUrl() != fetchResult.getUrl()` is a feature
102 | // $this->assertEquals($file->getUrl(), $file2->getUrl());
103 | $this->assertEquals($file->getName(), $file2->getName());
104 | $this->assertEquals($file->getSize(), $file2->getSize());
105 |
106 | $file->destroy();
107 | }
108 |
109 | public function testGetCreatedAtAndUpdatedAt() {
110 | $file = File::createWithData("testTimestamp.txt", "你好,中国!");
111 | $file->save();
112 | $this->assertNotEmpty($file->getUrl());
113 | $this->assertNotEmpty($file->getCreatedAt());
114 | $this->assertTrue($file->getCreatedAt() instanceof \DateTime);
115 |
116 | $file->destroy();
117 | }
118 |
119 | public function testMetaData() {
120 | $file = File::createWithData("testMetadata.txt", "你好,中国!");
121 | $file->setMeta("language", "zh-CN");
122 | $file->setMeta("bool", false);
123 | $file->setMeta("downloads", 100);
124 | $file->save();
125 | $file2 = File::fetch($file->getObjectId());
126 | $this->assertEquals("zh-CN", $file2->getMeta("language"));
127 | $this->assertEquals(false, $file2->getMeta("bool"));
128 | $this->assertEquals(100, $file2->getMeta("downloads"));
129 |
130 | $file->destroy();
131 | }
132 |
133 | /*
134 | * leancloud/php-sdk#46
135 | */
136 | public function testSaveObjectWithFile() {
137 | $obj = new LeanObject("TestObject");
138 | $obj->set("name", "alice");
139 |
140 | $file = File::createWithData("test.txt", "你好,中国!");
141 | $obj->addIn("files", $file);
142 | $obj->save();
143 |
144 | $this->assertNotEmpty($obj->getObjectId());
145 | $this->assertNotEmpty($file->getObjectId());
146 | $this->assertNotEmpty($file->getUrl());
147 |
148 | $file->destroy();
149 | $obj->destroy();
150 | }
151 |
152 | }
153 |
154 |
--------------------------------------------------------------------------------
/test/GeoPointTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(0.0, $point->getLatitude());
11 | $this->assertEquals(0.0, $point->getLongitude());
12 | }
13 |
14 | public function testInitializeGeoPoint() {
15 | $point = new GeoPoint(90, 180);
16 | $this->assertEquals(90, $point->getLatitude());
17 | $this->assertEquals(180, $point->getLongitude());
18 |
19 | $point = new GeoPoint(90, -180);
20 | $point = new GeoPoint(-90, 180);
21 | $point = new GeoPoint(-90, -180);
22 | }
23 |
24 | public function testEncodeGeoPoint() {
25 | $point = new GeoPoint(39.9, 116.4);
26 |
27 | $out = $point->encode();
28 | $this->assertEquals("GeoPoint", $out["__type"]);
29 | $this->assertEquals(39.9, $out["latitude"]);
30 | $this->assertEquals(116.4, $out["longitude"]);
31 | }
32 |
33 | public function testInvalidPoints() {
34 | $this->setExpectedException("InvalidArgumentException",
35 | "Invalid latitude or longitude " .
36 | "for geo point");
37 | new GeoPoint(180, 90);
38 | }
39 |
40 | public function testRadiansDistance() {
41 | $point = new GeoPoint(39.9, 116.4);
42 | $this->assertEquals(0, $point->radiansTo($point));
43 |
44 | // it should be equal to to M_PI
45 | $rad = $point->radiansTo(new GeoPoint(-39.9, -63.6));
46 | $this->assertEquals(M_PI, $rad, '', 0.0000001);
47 |
48 | $rad = $point->radiansTo(new GeoPoint(0, 116.4));
49 | $this->assertEquals(39.9 * M_PI / 180.0, $rad, '', 0.0000001);
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test/IncrementOperationTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($op->getKey(), "score");
11 | }
12 |
13 | public function testApplyOperation() {
14 | $op = new IncrementOperation("score", 20);
15 | $val = $op->applyOn(2);
16 | $this->assertEquals($val, 22);
17 |
18 | $val = $op->applyOn(22);
19 | $this->assertEquals($val, 42);
20 |
21 | $val = $op->applyOn("7");
22 | $this->assertEquals($val, 27);
23 | }
24 |
25 | public function testIncrementOnString() {
26 | $op = new IncrementOperation("score", 1);
27 | $this->setExpectedException("RuntimeException",
28 | "Operation incompatible with previous value.");
29 | $op->applyOn("alice");
30 | }
31 |
32 | public function testIncrementNonNumericAmount() {
33 | $this->setExpectedException("InvalidArgumentException",
34 | "Operand must be number.");
35 | $op = new IncrementOperation("score", "a");
36 | }
37 |
38 | public function testOperationEncode() {
39 | $op = new IncrementOperation("score", 2);
40 | $out = $op->encode();
41 | $this->assertEquals($out["__op"], "Increment");
42 | $this->assertEquals($out["amount"], 2);
43 |
44 | $op = new IncrementOperation("score", -2);
45 | $out = $op->encode();
46 | $this->assertEquals($out["__op"], "Increment");
47 | $this->assertEquals($out["amount"], -2);
48 | }
49 |
50 | public function testMergeWithNull() {
51 | $op = new IncrementOperation("score", 2);
52 | $op2 = $op->mergeWith(null);
53 | $out = $op2->encode();
54 | $this->assertEquals($out["__op"], "Increment");
55 | $this->assertEquals($out["amount"], 2);
56 | }
57 |
58 | public function testMergeWithSetOperation() {
59 | $op = new IncrementOperation("score", 2);
60 | $op2 = $op->mergeWith(new SetOperation("score", 40));
61 | $this->assertTrue($op2 instanceof SetOperation);
62 | $this->assertEquals($op2->getValue(), 42);
63 | }
64 |
65 | public function testMergeWithIncrementOperation() {
66 | $op = new IncrementOperation("score", 2);
67 | $op2 = $op->mergeWith(new IncrementOperation("score", 3));
68 | $this->assertTrue($op2 instanceof IncrementOperation);
69 | $this->assertEquals($op2->getValue(), 5);
70 | }
71 |
72 | public function testMergeWithDelete() {
73 | $op = new IncrementOperation("score", 2);
74 | $op2 = $op->mergeWith(new DeleteOperation("score"));
75 | $this->assertTrue($op2 instanceof SetOperation);
76 | $this->assertEquals($op2->getValue(), 2);
77 | }
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/test/MasterTest.php:
--------------------------------------------------------------------------------
1 | setKey("abc");
20 | $this->assertEquals("abc", $file->getKey());
21 | $file->save();
22 | $this->assertNotEmpty($file->getObjectId());
23 | $this->assertNotEmpty($file->getName());
24 |
25 | $this->assertStringEndsWith("abc", $file->getKey());
26 | $url = $file->getUrl();
27 | $parsedUrl = parse_url($url);
28 | $path = $parsedUrl["path"];
29 | $this->assertStringEndsWith("abc", $path);
30 |
31 | $this->assertEquals("text/plain", $file->getMimeType());
32 | $content = file_get_contents($url);
33 | $this->assertEquals("Hello World!", $content);
34 |
35 | $file->destroy();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/test/Php72ObjectDeprecated.php:
--------------------------------------------------------------------------------
1 | set("name", "Alice in wonderland");
25 | $obj->set("score", 81);
26 | $obj->save();
27 |
28 | $this->assertTrue($obj instanceof Object);
29 | $this->assertTrue($obj instanceof LeanObject);
30 | $this->assertNotEmpty($obj->getObjectId());
31 |
32 | LeanObject::destroyAll([$obj]);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/PushTest.php:
--------------------------------------------------------------------------------
1 | "Hello world!",
22 | "badge" => 20,
23 | "sound" => "APP/media/sound.mp3"
24 | );
25 | $push = new Push($data);
26 | $out = $push->encode();
27 | $this->assertEquals($data, $out["data"]);
28 | }
29 |
30 | public function testSetData() {
31 | $push = new Push(array(
32 | "alert" => "Hello world!"
33 | ));
34 | $push->setData("badge", 20);
35 | $push->setData("sound", "APP/media/sound.mp3");
36 | $out = $push->encode();
37 | $this->assertEquals(array(
38 | "alert" => "Hello world!",
39 | "badge" => 20,
40 | "sound" => "APP/media/sound.mp3"
41 | ), $out["data"]);
42 | }
43 |
44 | public function testSetPushForMultiplatform() {
45 | $data = array(
46 | "ios" => array(
47 | "alert" => "Hello world!",
48 | "badge" => 20,
49 | "sound" => "APP/media/sound.mp3"
50 | ),
51 | "android" => array(
52 | "alert" => "Hello world!",
53 | "title" => "Hello from app",
54 | "action" => "app.action"
55 | ),
56 | "wp" => array(
57 | "alert" => "Hello world!",
58 | "title" => "Hello from app",
59 | "wp-param" => "/chat.xaml?NavigatedFrom=Toast Notification"
60 | )
61 | );
62 | $push = new Push($data);
63 | $out = $push->encode();
64 | $this->assertEquals($data, $out["data"]);
65 | }
66 |
67 | public function testDefaultProd() {
68 | $push = new Push(array(
69 | "alert" => "Hello world!"
70 | ));
71 | $out = $push->encode();
72 | $this->assertEquals(Client::$isProduction, $out["prod"] == "prod");
73 | }
74 |
75 | public function testSetProd() {
76 | $push = new Push(array(
77 | "alert" => "Hello world!"
78 | ));
79 | $push->setOption("prod", "dev");
80 | $out = $push->encode();
81 | $this->assertEquals("dev", $out["prod"]);
82 | }
83 |
84 | public function testSetChannels() {
85 | $push = new Push(array(
86 | "alert" => "Hello world!"
87 | ));
88 | $channels = array("vip", "premium");
89 | $push->setChannels($channels);
90 | $out = $push->encode();
91 | $this->assertEquals($channels, $out["channels"]);
92 | }
93 |
94 | public function testSetPushTime() {
95 | $push = new Push(array(
96 | "alert" => "Hello world!"
97 | ));
98 | $time = new DateTime();
99 | $push->setPushTime($time);
100 | $out = $push->encode();
101 | $time2 = new DateTime($out["push_time"]);
102 | $this->assertEquals($time->getTimestamp(), $time2->getTimestamp());
103 | }
104 |
105 | public function testSetExpirationInterval() {
106 | $push = new Push(array(
107 | "alert" => "Hello world!"
108 | ));
109 | $push->setExpirationInterval(86400);
110 | $out = $push->encode();
111 | $this->assertEquals(86400, $out["expiration_interval"]);
112 | }
113 |
114 | public function testSetExpirationTime() {
115 | $push = new Push(array(
116 | "alert" => "Hello world!"
117 | ));
118 | $date = new DateTime();
119 | $push->setExpirationTime($date);
120 | $out = $push->encode();
121 | $date2 = new DateTime($out["expiration_time"]);
122 | $this->assertEquals($date->getTimestamp(), $date2->getTimestamp());
123 | }
124 |
125 | public function testSetWhere() {
126 | $push = new Push(array(
127 | "alert" => "Hello world!"
128 | ));
129 | $query = new Query("_Installation");
130 | $date = new DateTime();
131 | $query->lessThan("updatedAt", $date);
132 | $push->setWhere($query);
133 | $out = $push->encode();
134 | $this->assertEquals(array(
135 | "updatedAt" => array(
136 | '$lt' => Client::encode($date)
137 | )
138 | ), $out["where"]);
139 | }
140 |
141 | public function testSetFlowControl() {
142 | $push = new Push(array(
143 | "alert" => "Hello world!"
144 | ));
145 | $push->setFlowControl(3000);
146 | $out = $push->encode();
147 | $this->assertEquals(3000, $out["flow_control"]);
148 | }
149 |
150 | public function testSendPush() {
151 | $push = new Push(array(
152 | "alert" => "Hello world!"
153 | ));
154 | $query = new Query("_Installation");
155 | $query->equalTo("deviceType", "Android");
156 | $push->setWhere($query);
157 |
158 | $at = new DateTime();
159 | $at->add(new DateInterval("P1D"));
160 | $push->setPushTime($at);
161 |
162 | // $push->send();
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/test/RelationOperationTest.php:
--------------------------------------------------------------------------------
1 | setExpectedException("InvalidArgumentException",
20 | "Operands are empty.");
21 | $op = new RelationOperation("foo", array(), null);
22 | }
23 |
24 | public function testAddOpEncode() {
25 | $child1 = new LeanObject("TestObject", "ab123");
26 | $op = new RelationOperation("foo", array($child1), null);
27 | $out = $op->encode();
28 | $this->assertEquals("AddRelation", $out["__op"]);
29 | $this->assertEquals($child1->getPointer(), $out["objects"][0]);
30 | }
31 |
32 | public function testAddUnsavedObjects() {
33 | $child1 = new LeanObject("TestObject");
34 | $this->setExpectedException("RuntimeException",
35 | "Cannot add unsaved object to relation.");
36 | $op = new RelationOperation("foo", array($child1), null);
37 | }
38 |
39 | public function testAddDuplicateObjects() {
40 | $child1 = new LeanObject("TestObject", "ab123");
41 | $op = new RelationOperation("foo", array($child1, $child1), null);
42 | $out = $op->encode();
43 | $this->assertEquals("AddRelation", $out["__op"]);
44 | $this->assertEquals(1, count($out["objects"]));
45 | $this->assertEquals($child1->getPointer(), $out["objects"][0]);
46 | }
47 |
48 | public function testRemoveOpEncode() {
49 | $child1 = new LeanObject("TestObject", "ab123");
50 | $op = new RelationOperation("foo", null, array($child1));
51 | $out = $op->encode();
52 | $this->assertEquals("RemoveRelation", $out["__op"]);
53 | $this->assertEquals($child1->getPointer(), $out["objects"][0]);
54 | }
55 |
56 | public function testRemoveDuplicateObjects() {
57 | $child1 = new LeanObject("TestObject", "ab123");
58 | $op = new RelationOperation("foo", null, array($child1, $child1));
59 | $out = $op->encode();
60 | $this->assertEquals("RemoveRelation", $out["__op"]);
61 | $this->assertEquals(1, count($out["objects"]));
62 | $this->assertEquals($child1->getPointer(), $out["objects"][0]);
63 | }
64 |
65 | public function testAddWinsOverRemove() {
66 | $child1 = new LeanObject("TestObject", "ab101");
67 | $op = new RelationOperation("foo",
68 | array($child1),
69 | array($child1));
70 | $out = $op->encode();
71 | $this->assertEquals("AddRelation", $out["__op"]);
72 | $this->assertEquals(1, count($out["objects"]));
73 | $this->assertEquals($child1->getPointer(), $out["objects"][0]);
74 | }
75 |
76 | public function testAddAndRemove() {
77 | $child1 = new LeanObject("TestObject", "ab101");
78 | $child2 = new LeanObject("TestObject", "ab102");
79 | $child3 = new LeanObject("TestObject", "ab103");
80 | $op = new RelationOperation("foo",
81 | array($child1, $child2),
82 | array($child2, $child3));
83 | $out = $op->encode();
84 | $this->assertEquals("Batch", $out["__op"]);
85 |
86 | $adds = $out["ops"][0];
87 | $this->assertEquals("AddRelation", $adds["__op"]);
88 | $this->assertEquals(array($child1->getPointer(), $child2->getPointer()),
89 | $adds["objects"]);
90 | $removes = $out["ops"][1];
91 | $this->assertEquals("RemoveRelation", $removes["__op"]);
92 | $this->assertEquals(array($child3->getPointer()),
93 | $removes["objects"]);
94 | }
95 |
96 | public function testMultipleClassesNotAllowed() {
97 | $child1 = new LeanObject("TestObject", "abc101");
98 | $child2 = new LeanObject("Test2Object", "bac102");
99 | $this->setExpectedException("RuntimeException",
100 | "LeanObject type incompatible with " .
101 | "relation.");
102 | $op = new RelationOperation("foo",
103 | array($child1),
104 | array($child2));
105 | }
106 |
107 | public function testApplyOperation() {
108 | $child1 = new LeanObject("TestObject", "abc101");
109 | $op = new RelationOperation("foo", array($child1), null);
110 | $parent = new LeanObject("Test2Object");
111 | $val = $op->applyOn(null, $parent);
112 | $this->assertTrue($val instanceof Relation);
113 | $out = $val->encode();
114 | $this->assertEquals("TestObject", $out["className"]);
115 | }
116 |
117 | public function testMergeWithNull() {
118 | $child1 = new LeanObject("TestObject", "abc101");
119 | $op = new RelationOperation("foo", array($child1), null);
120 | $op2 = $op->mergeWith(null);
121 | $this->assertTrue($op2 instanceof RelationOperation);
122 | $this->assertEquals($op->encode(), $op2->encode());
123 | }
124 |
125 | public function testMergeWithRelationOperation() {
126 | $child1 = new LeanObject("TestObject", "abc101");
127 | $op = new RelationOperation("foo", array($child1), null);
128 |
129 | $child2 = new LeanObject("TestObject", "abc102");
130 | $op2 = new RelationOperation("foo", null, array($child2));
131 |
132 | $op3 = $op->mergeWith($op2);
133 | $this->assertTrue($op3 instanceof RelationOperation);
134 | $out = $op3->encode();
135 |
136 | // it adds child1, removes child2
137 | $this->assertEquals("Batch", $out["__op"]);
138 | $this->assertEquals(array($child1->getPointer()),
139 | $out["ops"][0]["objects"]);
140 | $this->assertEquals(array($child2->getPointer()),
141 | $out["ops"][1]["objects"]);
142 | }
143 |
144 | }
145 |
146 |
--------------------------------------------------------------------------------
/test/RelationTest.php:
--------------------------------------------------------------------------------
1 | getRelation("likes");
18 | $out = $rel->encode();
19 | $this->assertEquals("Relation", $out["__type"]);
20 | }
21 |
22 | public function testRelationClassEncode() {
23 | $obj = new LeanObject("TestObject");
24 | $rel = $obj->getRelation("likes");
25 | $out = $rel->encode();
26 | $this->assertEquals("Relation", $out["__type"]);
27 |
28 | $child1 = new LeanObject("User", "abc101");
29 | $rel->add($child1);
30 | $out = $rel->encode();
31 | $this->assertEquals("User", $out["className"]);
32 | }
33 |
34 | public function testGetRelationOnTargetClass() {
35 | $obj = new LeanObject("TestObject", "id123");
36 | $rel = new Relation($obj, "likes", "User");
37 | $query = $rel->getQuery();
38 | $this->assertEquals("User", $query->getClassName());
39 | }
40 |
41 | public function testGetRelationQueryWithoutTargetClass() {
42 | $obj = new LeanObject("TestObject", "id123");
43 | $rel = new Relation($obj, "likes");
44 | $query = $rel->getQuery();
45 |
46 | // the query should be made against the parent class, with
47 | // redirect key being set, so it will be redirected to target
48 | // class.
49 | $this->assertEquals("TestObject", $query->getClassName());
50 | $out = $query->encode();
51 | $this->assertEquals("likes", $out["redirectClassNameForKey"]);
52 | }
53 |
54 | public function getReverseQueryOnChildObject() {
55 | $obj = new LeanObject("TestObject", "id123");
56 | $rel = new Relation($obj, "likes", "User");
57 | $child = new LeanObject("User", "id124");
58 | $query = $rel->getReverseQuery($child);
59 | $this->assertEquals("TestObject", $query->getClassName());
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/test/RoleTest.php:
--------------------------------------------------------------------------------
1 | assertEquals("id123", $role->getObjectId());
26 | }
27 |
28 | public function testGetChildrenAsRelation() {
29 | $role = new Role();
30 | $this->assertTrue($role->getUsers() instanceof Relation);
31 | $this->assertTrue($role->getRoles() instanceof Relation);
32 | }
33 |
34 | public function testSaveRole() {
35 | $role = new Role();
36 | $role->setName("admin");
37 |
38 | $acl = new ACL();
39 | $acl->setPublicWriteAccess(true); // so it can be destroyed
40 | $role->setACL($acl);
41 |
42 | $role->save();
43 | $this->assertNotEmpty($role->getObjectId());
44 | $this->assertTrue($role->getUsers() instanceof Relation);
45 | $this->assertTrue($role->getRoles() instanceof Relation);
46 |
47 | $role->destroy();
48 | }
49 |
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/test/SetOperationTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($op->getKey(), "name");
14 |
15 | $op = new SetOperation("story", "in wonderland");
16 | $this->assertEquals($op->getKey(), "story");
17 | }
18 |
19 | public function testApplyOperation() {
20 | $op = new SetOperation("name", "alice");
21 | $val = $op->applyOn("alicia");
22 | $this->assertEquals($val, "alice");
23 |
24 | $val = $op->applyOn(42);
25 | $this->assertEquals($val, "alice");
26 | }
27 |
28 | public function testOperationEncode() {
29 | $op = new SetOperation("name", "alice");
30 | $this->assertEquals($op->encode(), "alice");
31 | $op = new SetOperation("score", 70.0);
32 | $this->assertEquals($op->encode(), 70.0);
33 |
34 | $date = new DateTime();
35 | $op = new SetOperation("released", $date);
36 | $out = $op->encode();
37 | $this->assertEquals($out['__type'], "Date");
38 | $this->assertEquals($out['iso'],
39 | Client::formatDate($date));
40 | }
41 |
42 | public function testMergeWithAnyOp() {
43 | $op = new SetOperation("name", "alice");
44 |
45 | $op2 = $op->mergeWith(null);
46 | $this->assertTrue($op2 instanceof SetOperation);
47 | $op2 = $op->mergeWith(new SetOperation("name", "jack"));
48 | $this->assertTrue($op2 instanceof SetOperation);
49 | $op2 = $op->mergeWith(new IncrementOperation("name", 1));
50 | $this->assertTrue($op2 instanceof SetOperation);
51 | $op2 = $op->mergeWith(new DeleteOperation("name"));
52 | $this->assertTrue($op2 instanceof SetOperation);
53 | $op2 = $op->mergeWith(new ArrayOperation("name", array("jack"), "Add"));
54 | $this->assertTrue($op2 instanceof SetOperation);
55 | }
56 |
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/test/StorageTest.php:
--------------------------------------------------------------------------------
1 | set("null", null);
12 | $this->assertNull($storage->get("null"));
13 |
14 | $storage->set("bool", true);
15 | $this->assertTrue(true === $storage->get("bool"));
16 |
17 | $storage->set("int", 42);
18 | $this->assertEquals(42, $storage->get("int"));
19 |
20 | $storage->set("string", "bar");
21 | $this->assertEquals("bar", $storage->get("string"));
22 |
23 | $date = new DateTime();
24 | $storage->set("date", $date);
25 | $this->assertEquals($date, $storage->get("date"));
26 |
27 | $arr = array("a", "b");
28 | $storage->set("array", $arr);
29 | $this->assertEquals($arr, $storage->get("array"));
30 | }
31 | }
32 |
33 |
34 |
--------------------------------------------------------------------------------
/test/engine/index.php:
--------------------------------------------------------------------------------
1 | false);
36 | } else {
37 | return array("drop" => true);
38 | }
39 | });
40 |
41 | Cloud::define("getMeta", function($params, $user, $meta) {
42 | return array("remoteAddress" => $meta["remoteAddress"]);
43 | });
44 |
45 | Cloud::define("updateObject", function($params, $user) {
46 | $obj = $params["object"];
47 | $obj->set("__testKey", 42);
48 | return $obj;
49 | });
50 |
51 | Cloud::onLogin(function($user) {
52 | error_log("Logging a user");
53 | return;
54 | });
55 |
56 | Cloud::onInsight(function($job) {
57 | return;
58 | });
59 |
60 | Cloud::onVerified("sms", function($user){
61 | return;
62 | });
63 |
64 | Cloud::beforeSave("TestObject", function($obj, $user) {
65 | $obj->set("__testKey", 42);
66 | });
67 |
68 | Cloud::afterSave("TestObject", function($obj, $user) {
69 | return;
70 | });
71 |
72 | Cloud::beforeDelete("TestObject", function($obj, $user) {
73 | return;
74 | });
75 |
76 | $engine = new LeanEngine();
77 | $engine->start();
78 |
79 |
--------------------------------------------------------------------------------