├── README.md ├── Trello ├── Client.php └── Model │ ├── Action.php │ ├── Board.php │ ├── Card.php │ ├── Lane.php │ ├── Member.php │ ├── Notification.php │ ├── Object.php │ └── Organization.php └── composer.json /README.md: -------------------------------------------------------------------------------- 1 | PHP-Trello-SDK 2 | ============== 3 | 4 | A PHP wrapper for the Trello API 5 | 6 | 7 | This is still under heavy development and is not recommended for production use. Many methods are missing as this is just scaffolding for now. 8 | 9 | 10 | Usage 11 | ====== 12 | 13 | Instantiate the client 14 | ```php 15 | $client = new \Trello\Client($api_key); 16 | ``` 17 | 18 | Get the authroization url to redrect the user to 19 | ```php 20 | $url = $client->getAuthorizationUrl('some app name', 'http://myapp.com/returnurl')); 21 | header("Location: {$url}"); 22 | ``` 23 | 24 | Set the access token 25 | ```php 26 | $client->setAccessToken($returned_token); 27 | ``` 28 | Get organizations 29 | ```php 30 | $member_obj = new \Trello\Model\Member($client); 31 | $member_obj->setId('userid'); 32 | $orgs = $member_obj->getOrganizations(); 33 | ``` 34 | 35 | Get a board 36 | ```php 37 | $board = $client->getBoard($board_id); 38 | ``` 39 | 40 | Another way to get a board (or any object) 41 | ```php 42 | $board = new \Trello\Model\Board($client); 43 | $board->setId($board_id); 44 | $board = $board->get(); 45 | ``` 46 | 47 | Get all cards for a board 48 | ```php 49 | $cards = $board->getCards(); 50 | ``` 51 | 52 | Get a specific card for this board 53 | ```php 54 | $card = $board->getCard($card_id); 55 | ``` 56 | 57 | Update the card 58 | ```php 59 | $card->name = 'some new name'; 60 | $card->save(); 61 | ``` 62 | 63 | Create a new card (or any object) 64 | ```php 65 | $card = new \Trello\Model\Card($client); 66 | $card->name = 'some card name'; 67 | $card->desc = 'some card desc'; 68 | $card->idList = $list_id; 69 | $card->save(); 70 | ``` -------------------------------------------------------------------------------- /Trello/Client.php: -------------------------------------------------------------------------------- 1 | _api_key = trim($api_key); 41 | 42 | if (!empty($secret)){ 43 | $this->_api_secret = trim($secret); 44 | } 45 | 46 | if (!empty($access_token)){ 47 | $this->setAccessToken($access_token); 48 | } 49 | 50 | } 51 | 52 | /** 53 | * Get's a URL to redirect the user to for them to login and authroize your app 54 | * 55 | * @param string $application_name 56 | * @param string $return_url 57 | * @param array $scope 58 | * @param string $expiration 59 | * @param string $callback_method 60 | * @throws \InvalidArgumentException 61 | * 62 | * @return string 63 | */ 64 | public function getAuthorizationUrl($application_name, $return_url, array $scope = array('read'), $expiration = "30days", $callback_method = 'fragment'){ 65 | 66 | $valid_expirations = array('1hour', '1day', '30days', 'never'); 67 | $valid_scopes = array('read', 'write', 'account'); 68 | $valid_callback_methods = array('postMessage', 'fragment'); 69 | 70 | if (!in_array($expiration, $valid_expirations)){ 71 | throw new \InvalidArgumentException("Invalid expiration {$expiration}. Valid expiration parameters are " . print_r($valid_expirations, true)); 72 | } 73 | 74 | foreach ($scope as $v){ 75 | if (!in_array($v, $valid_scopes)){ 76 | throw new \InvalidArgumentException("Invalid scope {$v}. Valid data scopes are " . print_r($valid_scopes, true)); 77 | } 78 | } 79 | 80 | if (!in_array($callback_method, $valid_callback_methods)){ 81 | throw new \InvalidArgumentException("Invalid callback method {$callback_method}. Valid callback methods are " . print_r($valid_callback_methods, true)); 82 | } 83 | 84 | $scope = implode(',', $scope); 85 | 86 | return $this->getApiBaseUrl() . "/authorize?callback_method={$callback_method}&return_url={$return_url}&scope={$scope}&expiration={$expiration}&name={$application_name}&key=" . $this->getApiKey(); 87 | 88 | } 89 | 90 | /** 91 | * After a user has authenticated and approved your app, they're presented with an access token. Set it here 92 | * 93 | * @param string $token 94 | * 95 | * @return \Trello\Client 96 | */ 97 | public function setAccessToken($token){ 98 | 99 | $this->_access_token = trim($token); 100 | 101 | return $this; 102 | 103 | } 104 | 105 | /** 106 | * Get the APIs base url 107 | * 108 | * @return string 109 | */ 110 | public function getApiBaseUrl(){ 111 | 112 | return $this->_api_url; 113 | 114 | } 115 | 116 | /** 117 | * Set the APIs base url 118 | * 119 | * @param string $url 120 | * 121 | * @return \Trello\Client 122 | */ 123 | public function setApiBaseUrl($url){ 124 | 125 | $this->_api_url = rtrim($url, ' /'); 126 | 127 | return $this; 128 | 129 | } 130 | 131 | /** 132 | * Get a board 133 | * 134 | * @param string $id 135 | * 136 | * @return \Trello\Model\Board 137 | */ 138 | public function getBoard($id){ 139 | 140 | $obj = new \Trello\Model\Board($this); 141 | $obj->setId($id); 142 | 143 | return $obj->get(); 144 | 145 | } 146 | 147 | /** 148 | * Get a card 149 | * 150 | * @param string $id 151 | * 152 | * @return \Trello\Model\Card 153 | */ 154 | public function getCard($id){ 155 | 156 | $obj = new \Trello\Model\Card($this); 157 | $obj->setId($id); 158 | 159 | return $obj->get(); 160 | 161 | } 162 | 163 | /** 164 | * Get an action 165 | * 166 | * @param string $id 167 | * 168 | * @return \Trello\Model\Action 169 | */ 170 | public function getAction($id){ 171 | 172 | $obj = new \Trello\Model\Action($this); 173 | $obj->setId($id); 174 | 175 | return $obj->get(); 176 | 177 | } 178 | 179 | /** 180 | * 181 | * @param string $id 182 | * @return \Trello\Model\Organization 183 | */ 184 | public function getOrganization($id){ 185 | 186 | $obj = new \Trello\Model\Organization($this); 187 | $obj->setId($id); 188 | 189 | return $obj->get(); 190 | 191 | } 192 | 193 | /** 194 | * Get the access token 195 | * 196 | * @return string 197 | */ 198 | public function getAccessToken(){ 199 | 200 | return $this->_access_token; 201 | 202 | } 203 | 204 | /** 205 | * Get the API secret 206 | * 207 | * @return string 208 | */ 209 | public function getApiSecret(){ 210 | 211 | return $this->_api_secret; 212 | 213 | } 214 | 215 | /** 216 | * Get the API eky 217 | * 218 | * @return string 219 | */ 220 | public function getApiKey(){ 221 | 222 | return $this->_api_key; 223 | 224 | } 225 | 226 | /** 227 | * Make a GET request 228 | * 229 | * @param string $path 230 | * @param array $payload 231 | * 232 | * @return array 233 | */ 234 | public function get($path, array $payload = array()){ 235 | 236 | return $this->_makeRequest($path, $payload); 237 | 238 | } 239 | 240 | /** 241 | * Make a POST request 242 | * 243 | * @param string $path 244 | * @param array $payload 245 | * @param array $headers 246 | * 247 | * @return array 248 | */ 249 | public function post($path, array $payload = array(), array $headers = array()){ 250 | 251 | return $this->_makeRequest($path, $payload, 'POST', $headers); 252 | 253 | } 254 | 255 | /** 256 | * Make a PUT request 257 | * 258 | * @param string $path 259 | * @param array $payload 260 | * @param array $headers 261 | * 262 | * @return array 263 | */ 264 | public function put($path, array $payload = array(), array $headers = array()){ 265 | 266 | return $this->_makeRequest($path, $payload, 'PUT', $headers); 267 | 268 | } 269 | 270 | /** 271 | * Make a DELETE request 272 | * 273 | * @param string $path 274 | * @param array $payload 275 | * @param array $headers 276 | * 277 | * @return array 278 | */ 279 | public function delete($path){ 280 | 281 | return $this->_makeRequest($path, array(), 'DELETE'); 282 | 283 | } 284 | 285 | /** 286 | * Make a CURL request 287 | * 288 | * @param string $url 289 | * @param array $payload 290 | * @param string $method 291 | * @param array $headers 292 | * @param array $curl_options 293 | * @throws \RuntimeException 294 | * 295 | * @return array 296 | */ 297 | protected function _makeRequest($url, array $payload = array(), $method = 'GET', array $headers = array(), array $curl_options = array()){ 298 | 299 | $url = $this->getApiBaseUrl() . '/' . $url . '?key=' . $this->getApiKey(); 300 | if ($this->getAccessToken()){ 301 | $url .= '&token=' . $this->getAccessToken(); 302 | } 303 | 304 | $ch = $this->_getCurlHandle(); 305 | $method = strtoupper($method); 306 | 307 | $options = array( 308 | CURLOPT_CUSTOMREQUEST => $method, 309 | CURLOPT_RETURNTRANSFER => true, 310 | CURLOPT_URL => $url, 311 | CURLOPT_HTTPHEADER => $headers, 312 | CURLOPT_SSL_VERIFYPEER => false, 313 | CURLOPT_FOLLOWLOCATION => true 314 | ); 315 | 316 | if ($method === 'GET'){ 317 | 318 | if (!empty($payload)){ 319 | $options[CURLOPT_URL] = $options[CURLOPT_URL] . '&' . http_build_query($payload, '&'); 320 | } 321 | 322 | }else if (!empty($payload)){ 323 | 324 | $options[CURLOPT_POST] = true; 325 | $options[CURLOPT_POSTFIELDS] = http_build_query($payload); 326 | $headers[] = 'Content-Length: ' . strlen($options[CURLOPT_POSTFIELDS]); 327 | $options[CURLOPT_HTTPHEADER] = $headers; 328 | 329 | } 330 | 331 | if (!empty($curl_options)){ 332 | $options = array_merge($options, $curl_options); 333 | } 334 | 335 | curl_setopt_array($ch, $options); 336 | $this->_raw_response = curl_exec($ch); 337 | $this->_debug_info = curl_getinfo($ch); 338 | 339 | if ($this->_raw_response === false){ 340 | throw new \RuntimeException('Request Error: ' . curl_error($ch)); 341 | } 342 | 343 | if ($this->_debug_info['http_code'] < 200 || $this->_debug_info['http_code'] >= 400){ 344 | throw new \RuntimeException('API Request failed - Response: ' . $this->_raw_response, $this->_debug_info['http_code']); 345 | } 346 | 347 | $response = json_decode($this->_raw_response, true); 348 | 349 | if ($response === null || !is_array($response)){ 350 | throw new \RuntimeException('Could not decode response JSON - Response: ' . $this->_raw_response, $this->_debug_info['http_code']); 351 | } 352 | 353 | return $response; 354 | 355 | } 356 | 357 | /** 358 | * Get the raw unparsed response returned from the CURL request 359 | * 360 | * @return string 361 | */ 362 | public function getRawResponse(){ 363 | 364 | return $this->_raw_response; 365 | 366 | } 367 | 368 | public function getDebugInfo(){ 369 | 370 | return $this->_debug_info; 371 | 372 | } 373 | 374 | /** 375 | * Singleton to get a CURL handle 376 | * 377 | * @return resource 378 | */ 379 | protected function _getCurlHandle(){ 380 | 381 | if (!$this->_curl_handle){ 382 | $this->_curl_handle = curl_init(); 383 | } 384 | 385 | return $this->_curl_handle; 386 | 387 | } 388 | 389 | /** 390 | * Closes the currently open CURL handle 391 | */ 392 | public function __destruct(){ 393 | 394 | if ($this->_curl_handle){ 395 | curl_close($this->_curl_handle); 396 | } 397 | 398 | } 399 | } -------------------------------------------------------------------------------- /Trello/Model/Action.php: -------------------------------------------------------------------------------- 1 | getPath('cards', $params); 12 | 13 | $tmp = array(); 14 | foreach ($data as $item){ 15 | array_push($tmp, new \Trello\Model\Card($this->getClient(), $item)); 16 | } 17 | 18 | return $tmp; 19 | 20 | } 21 | 22 | public function getCard($card_id, array $params = array()){ 23 | 24 | $data = $this->getPath("cards/{$card_id}", $params); 25 | 26 | return new \Trello\Model\Card($this->getClient(), $data); 27 | 28 | } 29 | 30 | public function getActions(array $params = array()){ 31 | 32 | $data = $this->getPath('actions', $params); 33 | 34 | $tmp = array(); 35 | foreach ($data as $item){ 36 | array_push($tmp, new \Trello\Model\Action($this->getClient(), $item)); 37 | } 38 | 39 | return $tmp; 40 | 41 | } 42 | 43 | public function getLists(array $params = array()){ 44 | 45 | $data = $this->getPath('lists', $params); 46 | 47 | $tmp = array(); 48 | foreach ($data as $item){ 49 | array_push($tmp, new \Trello\Model\Lane($this->getClient(), $item)); 50 | } 51 | 52 | return $tmp; 53 | 54 | } 55 | 56 | public function copy($new_name = null, array $copy_fields = array()){ 57 | 58 | if ($this->getId()){ 59 | 60 | $tmp = new self($this->getClient()); 61 | if (!$new_name){ 62 | $tmp->name = $this->name . ' Copy'; 63 | }else{ 64 | $tmp->name = $new_name; 65 | } 66 | $tmp->idBoardSource = $this->getId(); 67 | 68 | if (!empty($copy_fields)){ 69 | $tmp->keepFromSource = implode(',', $copy_fields); 70 | } 71 | 72 | return $tmp->save(); 73 | 74 | } 75 | 76 | return false; 77 | 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /Trello/Model/Card.php: -------------------------------------------------------------------------------- 1 | name)){ 43 | throw new \InvalidArgumentException('Missing required field "name"'); 44 | } 45 | 46 | if (empty($this->idList)){ 47 | throw new \InvalidArgumentException('Missing required filed "idList" - id of the list that the card should be added to'); 48 | } 49 | 50 | if (empty($this->pos)){ 51 | $this->pos = 'bottom'; 52 | }else{ 53 | if ($this->pos !== 'top' && $this->pos !== 'bottom' && $this->pos <= 0){ 54 | throw new \InvalidArgumentException("Invalid pos value {$this->pos}. Valid Values: A position. top, bottom, or a positive number"); 55 | } 56 | } 57 | 58 | if (empty($this->due)){ 59 | $this->due = null; 60 | } 61 | 62 | return parent::save(); 63 | 64 | } 65 | 66 | public function copy($new_name = null, $new_list_id = null, array $copy_fields = array()){ 67 | 68 | if ($this->getId()){ 69 | 70 | $tmp = new self($this->getClient()); 71 | if (!$new_name){ 72 | $tmp->name = $this->name . ' Copy'; 73 | }else{ 74 | $tmp->name = $new_name; 75 | } 76 | 77 | if (!$new_list_id){ 78 | $tmp->idList = $this->idList; 79 | }else{ 80 | $tmp->idList = $new_list_id; 81 | } 82 | 83 | $tmp->idCardSource = $this->getId(); 84 | 85 | if (!empty($copy_fields)){ 86 | $tmp->keepFromSource = implode(',', $copy_fields); 87 | } 88 | 89 | return $tmp->save(); 90 | 91 | } 92 | 93 | return false; 94 | 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /Trello/Model/Lane.php: -------------------------------------------------------------------------------- 1 | name)){ 12 | throw new \InvalidArgumentException('Missing required field "name"'); 13 | } 14 | 15 | if (empty($this->idBoard)){ 16 | throw new \InvalidArgumentException('Missing required filed "idBoard" - id of the board that the list should be added to'); 17 | } 18 | 19 | if (empty($this->pos)){ 20 | $this->pos = 'bottom'; 21 | }else{ 22 | if ($this->pos !== 'top' && $this->pos !== 'bottom' && $this->pos <= 0){ 23 | throw new \InvalidArgumentException("Invalid pos value {$this->pos}. Valid Values: A position. top, bottom, or a positive number"); 24 | } 25 | } 26 | 27 | return parent::save(); 28 | 29 | } 30 | 31 | public function getCards(array $params = array()){ 32 | 33 | $data = $this->getPath('cards', $params); 34 | 35 | $tmp = array(); 36 | foreach ($data as $item){ 37 | array_push($tmp, new \Trello\Model\Card($this->getClient(), $item)); 38 | } 39 | 40 | return $tmp; 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Trello/Model/Member.php: -------------------------------------------------------------------------------- 1 | getPath('boards'); 12 | 13 | $tmp = array(); 14 | foreach ($data as $item){ 15 | array_push($tmp, new \Trello\Model\Board($this->getClient(), $item)); 16 | } 17 | 18 | return $tmp; 19 | 20 | } 21 | 22 | public function getOrganizations() 23 | { 24 | $data = $this->getPath('organizations'); 25 | 26 | $tmp = array(); 27 | foreach ($data as $item){ 28 | array_push($tmp, new \Trello\Model\Organization($this->getClient(), $item)); 29 | } 30 | 31 | return $tmp; 32 | 33 | } 34 | 35 | public function getCards(array $params = array()) 36 | { 37 | $data = $this->getPath('cards', $params); 38 | 39 | $tmp = array(); 40 | foreach ($data as $item){ 41 | array_push($tmp, new \Trello\Model\Card($this->getClient(), $item)); 42 | } 43 | 44 | return $tmp; 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /Trello/Model/Notification.php: -------------------------------------------------------------------------------- 1 | _client = $client; 16 | $this->_data = $data; 17 | 18 | } 19 | 20 | /** 21 | * Save an object 22 | * 23 | * @return \Trello\Model\Object 24 | */ 25 | public function save(){ 26 | 27 | if ($this->getId()){ 28 | return $this->update(); 29 | }else{ 30 | $response = $this->getClient()->post($this->getModel() . '/' . $this->getId(), $this->toArray()); 31 | } 32 | 33 | $child = get_class($this); 34 | 35 | return new $child($this->getClient(), $response); 36 | 37 | } 38 | 39 | public function update(){ 40 | 41 | if (!$this->getId()){ 42 | throw new \InvalidArgumentException('There is no ID set for this object - Please call setId before calling update'); 43 | } 44 | 45 | $response = $this->getClient()->put($this->getModel() . '/' . $this->getId(), $this->toArray()); 46 | 47 | $child = get_class($this); 48 | 49 | return new $child($this->getClient(), $response); 50 | 51 | } 52 | 53 | /** 54 | * Get an item by id ($this->id) 55 | * 56 | * @throws \InvalidArgumentException 57 | * @return \Trello\Model\Object 58 | */ 59 | public function get(){ 60 | 61 | if (!$this->getId()){ 62 | throw new \InvalidArgumentException('There is no ID set for this object - Please call setId before calling get'); 63 | } 64 | 65 | $child = get_class($this); 66 | $response = $this->getClient()->get($this->getModel() . '/' . $this->getId()); 67 | 68 | return new $child($this->getClient(), $response); 69 | 70 | } 71 | 72 | /** 73 | * Get relative data 74 | * 75 | * @param string $path 76 | * @param array $payload 77 | * 78 | * @return array 79 | */ 80 | public function getPath($path, array $payload = array()){ 81 | 82 | return $this->getClient()->get($this->getModel() . '/' . $this->getId() . '/' . $path, $payload); 83 | 84 | } 85 | 86 | public function getModel(){ 87 | 88 | return $this->_model; 89 | 90 | } 91 | 92 | /** 93 | * 94 | * @return \Trello\Client 95 | */ 96 | public function getClient(){ 97 | 98 | return $this->_client; 99 | 100 | } 101 | 102 | public function setId($id){ 103 | 104 | $this->id = $id; 105 | 106 | return $this; 107 | 108 | } 109 | 110 | public function getId(){ 111 | 112 | return $this->id; 113 | 114 | } 115 | 116 | public function __get($key){ 117 | 118 | return $this->offsetExists($key)? $this->offsetGet($key) : null; 119 | 120 | } 121 | 122 | public function __set($key, $value){ 123 | 124 | $this->offsetSet($key, $value); 125 | 126 | } 127 | 128 | public function __isset($key){ 129 | 130 | return $this->offsetExists($key); 131 | 132 | } 133 | 134 | public function __unset($key){ 135 | 136 | return $this->offsetUnset($key); 137 | 138 | } 139 | 140 | public function toArray(){ 141 | 142 | return $this->_data; 143 | 144 | } 145 | 146 | public function offsetSet($offset, $value){ 147 | 148 | if (is_null($offset)){ 149 | $this->_data[] = $value; 150 | }else{ 151 | $this->_data[$offset] = $value; 152 | } 153 | 154 | } 155 | 156 | public function offsetExists($offset){ 157 | 158 | return isset($this->_data[$offset]); 159 | 160 | } 161 | 162 | public function offsetUnset($offset){ 163 | 164 | unset($this->_data[$offset]); 165 | 166 | } 167 | 168 | public function offsetGet($offset){ 169 | 170 | return isset($this->_data[$offset])? $this->_data[$offset] : null; 171 | 172 | } 173 | 174 | public function count(){ 175 | 176 | return count($this->_data); 177 | 178 | } 179 | 180 | public function rewind(){ 181 | 182 | $this->_position = 0; 183 | 184 | } 185 | 186 | public function current(){ 187 | 188 | return $this->_data[$this->_position]; 189 | 190 | } 191 | 192 | public function key(){ 193 | 194 | return $this->_position; 195 | 196 | } 197 | 198 | public function next(){ 199 | 200 | ++$this->_position; 201 | 202 | } 203 | 204 | public function valid(){ 205 | 206 | return isset($this->_data[$this->_position]); 207 | 208 | } 209 | 210 | } -------------------------------------------------------------------------------- /Trello/Model/Organization.php: -------------------------------------------------------------------------------- 1 | getPath('boards', $params); 12 | 13 | $tmp = array(); 14 | foreach ($data as $item){ 15 | array_push($tmp, new \Trello\Model\Board($this->getClient(), $item)); 16 | } 17 | 18 | return $tmp; 19 | 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trello/trello", 3 | "type": "library", 4 | "description": "PHP Trello API Wrapper", 5 | "keywords": ["trello", "api", "trello api wrapper"], 6 | "homepage": "https://github.com/ashwinks/Trello-API-PHP-Wrapper.git", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Ashwin Surajbali", 11 | "email": "ashwin@redinkdesign.net", 12 | "homepage": "http://www.redinkdesign.co" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.3.0" 17 | }, 18 | "autoload": { 19 | "psr-0": { "Trello": "." } 20 | } 21 | } --------------------------------------------------------------------------------