diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 03df5bc..0000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: php -php: - - 5.3 \ No newline at end of file diff --git a/GPL-LICENSE.txt b/GPL-LICENSE.txt deleted file mode 100644 index 11dddd0..0000000 --- a/GPL-LICENSE.txt +++ /dev/null @@ -1,278 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt deleted file mode 100644 index 542f67d..0000000 --- a/MIT-LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2011 Dave Reid - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 67dd9ea..0000000 --- a/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Toggl PHP SDK # - -Provides a re-usable PHP library for interacting with the Toggl time tracking -system's API. - -* Author: Dave Reid http://www.davereid.net/ -* Website: http://davereid.github.com/toggl-php-sdk/ -* License: GPLv2/MIT -* Thanks: [tanel](https://github.com/tanel) -* [![Build Status](https://secure.travis-ci.org/davereid/toggl-php-sdk.png?branch=master)](http://travis-ci.org/davereid/toggl-php-sdk) - -## Requirements ## - -* PHP 5.3 or higher -* [cURL](http://us.php.net/manual/en/book.curl.php) extension -* [JSON](http://us.php.net/manual/en/book.json.php) extension -* [PHPUnit](http://www.phpunit.de/) (for unit testing) - -## Usage ## - -``` -description = 'New description for #1.' -$time_entry->save(); -?> -``` - -## License ## - -The Toggl PHP SDK is dual licensed under the MIT and GPLv2 licenses. - -## Unit Tests ## - -To run the unit tests included with the SDK, you must have PHPUnit installed. -From the Toggl SDK directory, run `phpunit tests` to run all tests. diff --git a/images/bg_hr.png b/images/bg_hr.png new file mode 100644 index 0000000..7973bd6 Binary files /dev/null and b/images/bg_hr.png differ diff --git a/images/blacktocat.png b/images/blacktocat.png new file mode 100644 index 0000000..6e264fe Binary files /dev/null and b/images/blacktocat.png differ diff --git a/images/icon_download.png b/images/icon_download.png new file mode 100644 index 0000000..a2a287f Binary files /dev/null and b/images/icon_download.png differ diff --git a/images/sprite_download.png b/images/sprite_download.png new file mode 100644 index 0000000..f2babd5 Binary files /dev/null and b/images/sprite_download.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..d9d689c --- /dev/null +++ b/index.html @@ -0,0 +1,74 @@ + + + + + + + + + + + Toggl PHP SDK + + + + + +
+
+ Fork Me on GitHub + +

Toggl PHP SDK

+

PHP SDK for the Toggl API

+ +
+ Download this project as a .zip file + Download this project as a tar.gz file +
+
+
+ + +
+
+

Requirements

+ +

Usage

+ +
<?php
+$api_token = '00000000000000000000000000000000'; // Valid Toggl.com API token
+$connection = new TogglConnection($api_token);
+$time_entry = TogglTimeEntry::load($connection, 1); // Load time entry #1.
+$time_entry->description = 'New description for #1.'
+$time_entry->save();
+?>
+
+ +

Links

+ + +
+
+ + + + + + + + diff --git a/javascripts/main.js b/javascripts/main.js new file mode 100644 index 0000000..d8135d3 --- /dev/null +++ b/javascripts/main.js @@ -0,0 +1 @@ +console.log('This would be the main JS file.'); diff --git a/params.json b/params.json new file mode 100644 index 0000000..d7ab750 --- /dev/null +++ b/params.json @@ -0,0 +1 @@ +{"name":"Toggl PHP SDK","body":"### Requirements\r\n\r\n* PHP 5.3 or greater\r\n* [cURL](http://us.php.net/manual/en/book.curl.php) PHP extension\r\n* [JSON](http://us.php.net/manual/en/book.json.php) PHP extension\r\n* [PHPUnit](https://github.com/sebastianbergmann/phpunit/) (for running unit tests)\r\n\r\n### Usage\r\n\r\n```\r\ndescription = 'New description for #1.'\r\n$time_entry->save();\r\n?>\r\n```\r\n\r\n## Links\r\n\r\n* [Toggl.com API reference](https://www.toggl.com/public/api)","tagline":"PHP SDK for the Toggl API","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."} \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index b4065fe..0000000 --- a/phpunit.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - tests - - - diff --git a/src/TogglClient.php b/src/TogglClient.php deleted file mode 100644 index 9356383..0000000 --- a/src/TogglClient.php +++ /dev/null @@ -1,6 +0,0 @@ -token = $token; - $this->options = $options; - } - - public function setToken($token) { - $this->token = $token; - } - - public function getToken() { - return $this->token; - } - - public function getOptions() { - return $this->options; - } - - public function setOptions(array $options) { - $this->options = $options; - } - - /** - * Construct the request URI. - * - * @param string $resource - * The resource name/path. - * @param array $query - * An array of query string parameters to add to the URL. - * - * @return - * A fully-quantified Toggl API URL. - */ - public function getURL($resource, array $query = array()) { - $url = 'https://www.toggl.com/api/' . self::API_VERSION . '/' . $resource . '.json'; - if (!empty($query)) { - $url .= '?' . http_build_query($query, NULL, '&'); - } - return $url; - } - - /** - * Build the request headers. - * - * @return array - */ - protected function getHeaders() { - return array( - //'Authorization' => 'Basic ' . base64_encode($this->token . ':api_token'), - //'User-Agent' => 'Toggl PHP SDK (+https://github.com/davereid/toggl-php-sdk)', - ); - } - - public function request($resource, array $options = array()) { - $options += $this->getOptions() + array( - 'headers' => array(), - 'method' => 'GET', - 'query' => array(), - 'data' => NULL, - ); - - $url = $this->getURL($resource, $options['query']); - - // Set the CURL variables. - $ch = curl_init(); - - // Include post data. - if (isset($options['data'])) { - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($options['data'])); - $options['headers']['Content-Type'] = 'application/json'; - } - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_HEADER, FALSE); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // Needed since Toggl's SSL fails without this. - curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $options['method']); - curl_setopt($ch, CURLOPT_USERPWD, $this->getToken() . ':api_token'); - - // Build and format the headers. - foreach (array_merge($this->getHeaders(), $options['headers']) as $header => $value) { - $options['headers'][$header] = $header . ': ' . $value; - } - curl_setopt($ch, CURLOPT_HTTPHEADER, $options['headers']); - - // Perform the API request. - $result = curl_exec($ch); - if ($result == FALSE) { - throw new TogglException(curl_error($ch)); - } - - // Build the response. - $response = new stdClass(); - $response->data = json_decode($result, TRUE); - $response->code = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $response->success = $response->code == 200; - - curl_close($ch); - return $response; - } - - public function getUser() { - $response = $this->request('me'); - if (!empty($response->data['data'])) { - return new TogglUser($this, $response->data['data']); - } - return FALSE; - } -} diff --git a/src/TogglException.php b/src/TogglException.php deleted file mode 100644 index cb162d7..0000000 --- a/src/TogglException.php +++ /dev/null @@ -1,3 +0,0 @@ -connection = $connection; - $this->data = $data; - } - - public function __get($name) { - if (array_key_exists($name, $this->data)) { - return $this->data[$name]; - } - } - - public function __set($name, $value) { - $this->data[$name] = $value; - } - - public function __isset($name) { - return isset($this->data[$name]); - } - - public function __unset($name) { - unset($this->data[$name]); - } - - protected function setConnection(TogglConnection $connection) { - $this->connection = $connection; - } - - public function getConnection() { - return $this->connection; - } - - protected function setData(array $data) { - $this->data = $data; - } - - public function getData() { - return $this->data; - } - - public static function load(TogglConnection $connection, $id, array $options = array()) { - if (!is_numeric($id)) { - throw new TogglException('Invalid load ID ' . $id); - } - - $class = get_called_class(); - $resource = $class::$element_plural_name . '/' . $id; - $response = $connection->request($resource); - if (!empty($response->data['data'])) { - return new $class($connection, $response->data['data']); - } - return FALSE; - } - - public static function loadMultiple(TogglConnection $connection, array $options = array()) { - $class = get_called_class(); - $response = $connection->request($class::$element_plural_name, $options); - $count = 0; - foreach ($response->data['data'] as $key => $record) { - $response->data['data'][$key] = new $class($connection, $record); - $count++; - } - $response->data['count'] = $count; - return $response->data; - } - - public function save(array $options = array()) { - $options['method'] = !empty($this->id) ? 'PUT' : 'POST'; - $options['data'][$this::$element_name] = $this->data; - $resource = $this::element_plural_name . (!empty($this->id) ? '/' . $this->id : ''); - $response = $this->connection->request($resource, $options); - $this->data = $response->data['data']; - return TRUE; - } - - public function delete(array $options = array()) { - if (!empty($this->id)) { - $options['method'] = 'DELETE'; - $resource = $this::$element_plural_name . '/' . $this->id; - $response = $this->connection->request($resource, $options); - } - $this->data = array(); - return TRUE; - } -} diff --git a/src/TogglTask.php b/src/TogglTask.php deleted file mode 100644 index 03d93cb..0000000 --- a/src/TogglTask.php +++ /dev/null @@ -1,6 +0,0 @@ - $item) { - $key_exists = FALSE; - $found_value = TogglUtility::getNestedValue($item, $parents, $key_exists); - if ($key_exists) { - if (is_array($value) && in_array($found_value, $value)) { - $return[$key] = $item; - } - elseif ($found_value == $value) { - $return[$key] = $item; - } - } - } - return $return; - } - - /** - * Retrieves a value from an object or nested array with variable depth. - * - * This is a copy of Drupal's drupal_array_get_nested_value() but with added - * support for objects. - * - * @param mixed $item - * The array or object from which to get the value. - * @param array $parents - * An array of parent keys of the value, starting with the outermost key. - * @param bool $key_exists - * (optional) If given, an already defined variable that is altered by - * reference if all the keys in $parents were found. - * - * @return mixed - * The requested nested value. Possibly NULL if the value is NULL or not all - * nested parent keys exist. $key_exists is altered by reference and is a - * Boolean that indicates whether all nested parent keys exist (TRUE) or not - * (FALSE). This allows to distinguish between the two possibilities when - * NULL is returned. - */ - public static function getNestedValue($item, array $parents, &$key_exists = NULL) { - $ref = $item; - foreach ($parents as $parent) { - if (is_array($ref) && array_key_exists($parent, $ref)) { - $ref = &$ref[$parent]; - } - elseif (is_object($ref) && property_exists($ref, $parent)) { - $ref = $ref->$parent; - } - elseif (is_object($ref) && method_exists($ref, '__get') && $ref->__get($parent) !== NULL) { - // Support objects that override the __get magic method. - // This also doesn't support if $ref->$parent exists but is set to NULL. - $ref = $ref->$parent; - } - else { - $key_exists = FALSE; - return NULL; - } - } - $key_exists = TRUE; - return $ref; - } - - /** - * Convert a list of Toggl API objects into a keyed array by ID and name. - * - * @param array $items - * An array of objects from a Toggl API request. - * @param string $key - * The property from each object to use as the array key. Default is 'id'. - * @param string $value - * The proprety from each object ot use as the array value. Default is 'name'. - * - * @return array - * An array with the specified key/value pairs. - */ - public static function mapItemsToKeyedArray(array $items, $key = 'id', $value = 'name') { - $return = array(); - foreach ($items as $item) { - $return[$item->$key] = $item->$value; - } - return $return; - } -} diff --git a/src/TogglWorkspace.php b/src/TogglWorkspace.php deleted file mode 100644 index d67fdf3..0000000 --- a/src/TogglWorkspace.php +++ /dev/null @@ -1,18 +0,0 @@ -token = $token; - } - - public function setToken($token) { - $this->token = $token; - } - - public function getToken() { - return $this->token; - } - - /** - * Construct the request URI. - * - * @param string $resource - * The resource name/path. - * @param array $query - * An array of query string parameters to add to the URL. - * - * @return - * A fully-quantified Toggl API URL. - */ - protected function getURL($resource, array $query = array()) { - $url = 'https://www.toggl.com/api/' . self::API_VERSION . '/' . $resource . '.json'; - if (!empty($query)) { - $url .= '?' . http_build_query($query, NULL, '&'); - } - return $url; - } - - /** - * Build the request headers. - * - * @return array - */ - protected function getHeaders() { - return array( - //'Authorization' => 'Basic ' . base64_encode($this->token . ':api_token'), - //'User-Agent' => 'Toggl PHP SDK (+https://github.com/davereid/toggl-php-sdk)', - ); - } - - protected function request($url, array $options = array()) { - $options += array( - 'headers' => array(), - 'method' => 'GET', - 'data' => NULL, - ); - - // Set the CURL variables. - $ch = curl_init(); - - // Include post data. - if (isset($options['data'])) { - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($options['data'])); - $options['headers']['Content-Type'] = 'application/json'; - } - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_HEADER, FALSE); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // Needed since Toggl's SSL fails without this. - curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $options['method']); - curl_setopt($ch, CURLOPT_USERPWD, $this->getToken() . ':api_token'); - - // Build and format the headers. - foreach (array_merge($this->getHeaders(), $options['headers']) as $header => $value) { - $options['headers'][$header] = $header . ': ' . $value; - } - curl_setopt($ch, CURLOPT_HTTPHEADER, $options['headers']); - - // Perform the API request. - $result = curl_exec($ch); - if ($result == FALSE) { - throw new TogglException(curl_error($ch)); - } - - // Build the response. - $response = new stdClass(); - $response->data = json_decode($result); - $response->code = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $response->success = $response->code == 200; - - curl_close($ch); - return $response; - } - - /** - * Get time entries for the current user. - * - * @param int $start_date - * @param int $end_date - */ - public function timeEntriesLoadRecent($start_date = NULL, $end_date = NULL, array $options = array()) { - if (isset($start_date) != isset($end_date)) { - throw new TogglException("Invalid parameters for getTimeEntries."); - } - - $query = array(); - if (isset($start_date) && isset($end_date)) { - if ($end_date < $start_date) { - throw new TogglException("Start date cannot be after the end date."); - } - $query['start_date'] = gmdate(self::DATE_FORMAT, $start_date); - $query['end_date'] = gmdate(self::DATE_FORMAT, $end_date); - } - - // @todo Convert this into an array of timeEntry classes. - return $this->request($this->getURL('time_entries', $query), $options); - } - - /** - * Save a time entry for the current user. - * - * @param $timeEntry - * A time entry object. - */ - public function timeEntrySave($timeEntry) { - // Add a default created with - if (!isset($timeEntry->created_with)) { - $timeEntry->created_with = $this->userAgent; - } - - $options['method'] = !empty($timeEntry->id) ? 'PUT' : 'POST'; - $url = 'time_entries' . (!empty($timeEntry->id) ? '/' . $timeEntry->id : ''); - $options['data']['time_entry'] = $timeEntry; - - $response = $this->request($this->getURL($url), $options); - $timeEntry = $response->data; - return $response; - } - - /** - * Delete a time entry. - * - * @param $timeEntry - * A time entry object. - */ - public function timeEntryDelete($timeEntry) { - $options['method'] = 'DELETE'; - $url = 'time_entries/' . $timeEntry->id; - - $response = $this->request($this->getURL($url), $options); - unset($timeEntry); - return $response; - } - - public function workspaceLoadAll() { - return $this->request($this->getURL('workspaces')); - } - - public function clientLoadAll() { - return $this->request($this->getURL('clients')); - } - - public function clientSave($client) { - $options['method'] = !empty($client->id) ? 'PUT' : 'POST'; - $url = 'clients' . (!empty($client->id) ? '/' . $client->id : ''); - $options['data']['client'] = $client; - - $response = $this->request($this->getURL($url), $options); - $client = $response->data; - return $response; - } - - public function clientDelete($client) { - $options['method'] = 'DELETE'; - $url = 'clients/' . $client->id; - - $response = $this->request($this->getURL($url), $options); - $client = $response->data; - return $response; - } - - public function projectLoadAll() { - return $this->request($this->getURL('projects')); - } - - public function projectSave($project) { - $options['method'] = !empty($project->id) ? 'PUT' : 'POST'; - $url = 'projects' . (!empty($project->id) ? '/' . $project->id : ''); - $options['data']['project'] = $project; - - $response = $this->request($this->getURL($url), $options); - $project = $response->data; - return $response; - } - - public function taskLoadAll() { - return $this->request($this->getURL('tasks')); - } - - public function tagLoadAll() { - return $this->request($this->getURL('tags')); - } - - public function userLoad() { - $response = $this->request($this->getURL('me')); - if (!empty($response->data->data)) { - return $response->data->data; - } - return FALSE; - } - - public function loadAll($resource) { - $response = $this->request($this->getURL($resource)); - if (isset($response->data->data) && is_array($response->data->data)) { - $resources = toggl_map_ids($response->data->data); - return $resources; - } - return FALSE; - } - - public function save($resource, $object) { - $options['method'] = !empty($object->id) ? 'PUT' : 'POST'; - $url = $resource . '/' . (!empty($object->id) ? '/' . $object->id : ''); - $options['data']['client'] = $object; - - $response = $this->request($this->getURL($url), $options); - $client = $response->data; - return $response; - } - - public function delete($resource, $object) { - $options['method'] = 'DELETE'; - $url = $resource . '/' . $object->id; - - $response = $this->request($this->getURL($url), $options); - $client = $response->data; - return $response; - } -} - -function toggl_map_ids(array $items) { - $return = array(); - foreach ($items as $key => $item) { - if (isset($item->id)) { - $key = $item->id; - } - $return[$key] = $item; - } - return $return; -} - -function toggl_filter_array_set_variables(array $variables = NULL) { - static $stored_variables = array(); - - if (isset($variables)) { - $stored_variables = $variables; - } - - return $stored_variables; -} - -function toggl_filter_array($item) { - $variables = toggl_filter_array_set_variables(); - foreach ($variables as $key => $value) { - if (!isset($item->{$key}) || $item->{$key} != $value) { - return FALSE; - } - } - return $item; -} diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css new file mode 100644 index 0000000..e65cedf --- /dev/null +++ b/stylesheets/pygment_trac.css @@ -0,0 +1,70 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f0f3f3; } +.highlight .c { color: #0099FF; font-style: italic } /* Comment */ +.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */ +.highlight .k { color: #006699; font-weight: bold } /* Keyword */ +.highlight .o { color: #555555 } /* Operator */ +.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #009999 } /* Comment.Preproc */ +.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */ +.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */ +.highlight .go { color: #AAAAAA } /* Generic.Output */ +.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #99CC66 } /* Generic.Traceback */ +.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #006699 } /* Keyword.Pseudo */ +.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #FF6600 } /* Literal.Number */ +.highlight .s { color: #CC3300 } /* Literal.String */ +.highlight .na { color: #330099 } /* Name.Attribute */ +.highlight .nb { color: #336666 } /* Name.Builtin */ +.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */ +.highlight .no { color: #336600 } /* Name.Constant */ +.highlight .nd { color: #9999FF } /* Name.Decorator */ +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #CC00FF } /* Name.Function */ +.highlight .nl { color: #9999FF } /* Name.Label */ +.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #003333 } /* Name.Variable */ +.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #FF6600 } /* Literal.Number.Float */ +.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */ +.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */ +.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */ +.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */ +.highlight .sc { color: #CC3300 } /* Literal.String.Char */ +.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #CC3300 } /* Literal.String.Double */ +.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */ +.highlight .si { color: #AA0000 } /* Literal.String.Interpol */ +.highlight .sx { color: #CC3300 } /* Literal.String.Other */ +.highlight .sr { color: #33AAAA } /* Literal.String.Regex */ +.highlight .s1 { color: #CC3300 } /* Literal.String.Single */ +.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */ +.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #003333 } /* Name.Variable.Class */ +.highlight .vg { color: #003333 } /* Name.Variable.Global */ +.highlight .vi { color: #003333 } /* Name.Variable.Instance */ +.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css new file mode 100644 index 0000000..4189751 --- /dev/null +++ b/stylesheets/stylesheet.css @@ -0,0 +1,431 @@ +/******************************************************************************* +Slate Theme for Github Pages +by Jason Costello, @jsncostello +*******************************************************************************/ + +@import url(http://github.com/pygment_trac.css); + +/******************************************************************************* +MeyerWeb Reset +*******************************************************************************/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font: inherit; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +ol, ul { + list-style: none; +} + +blockquote, q { +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +a:focus { + outline: none; +} + +/******************************************************************************* +Theme Styles +*******************************************************************************/ + +body { + box-sizing: border-box; + color:#373737; + background: #212121; + font-size: 16px; + font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif; + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} + +h1, h2, h3, h4, h5, h6 { + margin: 10px 0; + font-weight: 700; + color:#222222; + font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif; + letter-spacing: -1px; +} + +h1 { + font-size: 36px; + font-weight: 700; +} + +h2 { + padding-bottom: 10px; + font-size: 32px; + background: url('http://github.com/images/bg_hr.png') repeat-x bottom; +} + +h3 { + font-size: 24px; +} + +h4 { + font-size: 21px; +} + +h5 { + font-size: 18px; +} + +h6 { + font-size: 16px; +} + +p { + margin: 10px 0 15px 0; +} + +footer p { + color: #f2f2f2; +} + +a { + text-decoration: none; + color: #007edf; + text-shadow: none; + + transition: color 0.5s ease; + transition: text-shadow 0.5s ease; + -webkit-transition: color 0.5s ease; + -webkit-transition: text-shadow 0.5s ease; + -moz-transition: color 0.5s ease; + -moz-transition: text-shadow 0.5s ease; + -o-transition: color 0.5s ease; + -o-transition: text-shadow 0.5s ease; + -ms-transition: color 0.5s ease; + -ms-transition: text-shadow 0.5s ease; +} + +#main_content a:hover { + color: #0069ba; + text-shadow: #0090ff 0px 0px 2px; +} + +footer a:hover { + color: #43adff; + text-shadow: #0090ff 0px 0px 2px; +} + +em { + font-style: italic; +} + +strong { + font-weight: bold; +} + +img { + position: relative; + margin: 0 auto; + max-width: 739px; + padding: 5px; + margin: 10px 0 10px 0; + border: 1px solid #ebebeb; + + box-shadow: 0 0 5px #ebebeb; + -webkit-box-shadow: 0 0 5px #ebebeb; + -moz-box-shadow: 0 0 5px #ebebeb; + -o-box-shadow: 0 0 5px #ebebeb; + -ms-box-shadow: 0 0 5px #ebebeb; +} + +pre, code { + width: 100%; + color: #222; + background-color: #fff; + + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + font-size: 14px; + + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + + + +} + +pre { + width: 100%; + padding: 10px; + box-shadow: 0 0 10px rgba(0,0,0,.1); + overflow: auto; +} + +code { + padding: 3px; + margin: 0 3px; + box-shadow: 0 0 10px rgba(0,0,0,.1); +} + +pre code { + display: block; + box-shadow: none; +} + +blockquote { + color: #666; + margin-bottom: 20px; + padding: 0 0 0 20px; + border-left: 3px solid #bbb; +} + +ul, ol, dl { + margin-bottom: 15px +} + +ul li { + list-style: inside; + padding-left: 20px; +} + +ol li { + list-style: decimal inside; + padding-left: 20px; +} + +dl dt { + font-weight: bold; +} + +dl dd { + padding-left: 20px; + font-style: italic; +} + +dl p { + padding-left: 20px; + font-style: italic; +} + +hr { + height: 1px; + margin-bottom: 5px; + border: none; + background: url('http://github.com/images/bg_hr.png') repeat-x center; +} + +table { + border: 1px solid #373737; + margin-bottom: 20px; + text-align: left; + } + +th { + font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; + padding: 10px; + background: #373737; + color: #fff; + } + +td { + padding: 10px; + border: 1px solid #373737; + } + +form { + background: #f2f2f2; + padding: 20px; +} + +img { + width: 100%; + max-width: 100%; +} + +/******************************************************************************* +Full-Width Styles +*******************************************************************************/ + +.outer { + width: 100%; +} + +.inner { + position: relative; + max-width: 640px; + padding: 20px 10px; + margin: 0 auto; +} + +#forkme_banner { + display: block; + position: absolute; + top:0; + right: 10px; + z-index: 10; + padding: 10px 50px 10px 10px; + color: #fff; + background: url('http://github.com/images/blacktocat.png') #0090ff no-repeat 95% 50%; + font-weight: 700; + box-shadow: 0 0 10px rgba(0,0,0,.5); + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +#header_wrap { + background: #212121; + background: -moz-linear-gradient(top, #373737, #212121); + background: -webkit-linear-gradient(top, #373737, #212121); + background: -ms-linear-gradient(top, #373737, #212121); + background: -o-linear-gradient(top, #373737, #212121); + background: linear-gradient(top, #373737, #212121); +} + +#header_wrap .inner { + padding: 50px 10px 30px 10px; +} + +#project_title { + margin: 0; + color: #fff; + font-size: 42px; + font-weight: 700; + text-shadow: #111 0px 0px 10px; +} + +#project_tagline { + color: #fff; + font-size: 24px; + font-weight: 300; + background: none; + text-shadow: #111 0px 0px 10px; +} + +#downloads { + position: absolute; + width: 210px; + z-index: 10; + bottom: -40px; + right: 0; + height: 70px; + background: url('http://github.com/images/icon_download.png') no-repeat 0% 90%; +} + +.zip_download_link { + display: block; + float: right; + width: 90px; + height:70px; + text-indent: -5000px; + overflow: hidden; + background: url(http://github.com/images/sprite_download.png) no-repeat bottom left; +} + +.tar_download_link { + display: block; + float: right; + width: 90px; + height:70px; + text-indent: -5000px; + overflow: hidden; + background: url(http://github.com/images/sprite_download.png) no-repeat bottom right; + margin-left: 10px; +} + +.zip_download_link:hover { + background: url(http://github.com/images/sprite_download.png) no-repeat top left; +} + +.tar_download_link:hover { + background: url(http://github.com/images/sprite_download.png) no-repeat top right; +} + +#main_content_wrap { + background: #f2f2f2; + border-top: 1px solid #111; + border-bottom: 1px solid #111; +} + +#main_content { + padding-top: 40px; +} + +#footer_wrap { + background: #212121; +} + + + +/******************************************************************************* +Small Device Styles +*******************************************************************************/ + +@media screen and (max-width: 480px) { + body { + font-size:14px; + } + + #downloads { + display: none; + } + + .inner { + min-width: 320px; + max-width: 480px; + } + + #project_title { + font-size: 32px; + } + + h1 { + font-size: 28px; + } + + h2 { + font-size: 24px; + } + + h3 { + font-size: 21px; + } + + h4 { + font-size: 18px; + } + + h5 { + font-size: 14px; + } + + h6 { + font-size: 12px; + } + + code, pre { + min-width: 320px; + max-width: 480px; + font-size: 11px; + } + +} diff --git a/tests/TogglTest.php b/tests/TogglTest.php deleted file mode 100644 index 24dc85d..0000000 --- a/tests/TogglTest.php +++ /dev/null @@ -1,61 +0,0 @@ -toggl = new Toggl(TOGGL_TEST_TOKEN); - } - - public function testConstruct() { - $this->assertClassHasAttribute('token', 'Toggl'); - $this->assertSame($this->toggl->getToken(), TOGGL_TEST_TOKEN); - } - - /** - * @expectedException TogglException - * @expectedExceptionMessage Invalid parameters for getTimeEntries. - */ - public function testTimeEntriesInvalidParameters() { - $this->toggl->timeEntriesLoadRecent(0, NULL); - } - - /** - * @expectedException TogglException - * @expectedExceptionMessage Start date cannot be after the end date. - */ - public function testTimeEntriesInvalidDates() { - $this->toggl->timeEntriesLoadRecent(1, 0); - } - - public function testWorkspaces() { - $response = $this->toggl->workspaceLoadAll(); - $this->assertSame($response->code, 200); - $this->assertSame(count($response->data->data), 2); - } - - public function testClients() { - $response = $this->toggl->clientLoadAll(); - $this->assertSame($response->code, 200); - $this->assertSame(count($response->data->data), 3); - } - - public function testUser() { - $account = $this->toggl->userLoad(); - $this->assertSame($account->api_token, TOGGL_TEST_TOKEN); - $this->assertSame($account->fullname, 'Toggl Tester'); - $this->assertSame($account->email, 'toggl-php-sdk@davereid.net'); - $this->assertSame($account->id, 202215); - } -}