From 1febdc5f07e0458d18cdb51ebab348416056340d Mon Sep 17 00:00:00 2001 From: UndefinedOffset Date: Tue, 17 Dec 2013 12:23:54 -0400 Subject: [PATCH] Initial Commit --- .gitignore | 3 + LICENSE | 27 +++++++ README.md | 43 ++++++++++ _config.php | 6 ++ _config/config.yml | 6 ++ code/PackagistShortCode.php | 109 ++++++++++++++++++++++++++ composer.json | 23 ++++++ css/PackagistButton.css | 98 +++++++++++++++++++++++ images/packagist-button.png | Bin 0 -> 5845 bytes templates/Includes/PackagistButton.ss | 14 ++++ 10 files changed, 329 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 _config.php create mode 100644 _config/config.yml create mode 100644 code/PackagistShortCode.php create mode 100644 composer.json create mode 100644 css/PackagistButton.css create mode 100644 images/packagist-button.png create mode 100644 templates/Includes/PackagistButton.ss diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5aa30a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.buildpath +/.project +/.settings diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..26dcd2a --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, The Web Builders Group Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + Neither the name of The Web Builders Group Inc nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d727778 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +Packagist Short Code +================= +Add a short code for adding a Packagist installs button with a count to a HTMLText field. + +## Maintainer Contact +* Ed Chipman ([UndefinedOffset](https://github.com/UndefinedOffset)) + +## Requirements +* SilverStripe CMS 3.x + + +## Installation +* Download the module from here https://github.com/webbuilders-group/silverstripe-packagistshortcode/archive/master.zip +* Extract the downloaded archive into your site root so that the destination folder is called githubshortcode, opening the extracted folder should contain _config.php in the root along with other files/folders +* Run dev/build?flush=all to regenerate the manifest + + +## Usage +Usage is pretty straight forward to add a packagist downloads button you simply add the following: +``` +[packagist package="package owner/package name"] +``` + +Optionally you may add mode="monthly" or button="daily" (defaults to total) to show the download count for the given period. +``` +[packagist package="package owner/package name" mode="monthly"] + +``` + +In 3.1 the short codes above will work as included however the updated syntax for the short code would be (of course layout and button are not required): +``` +[packagist,package="package owner/package name",mode="monthly"] +``` + + +#### Configuration Options +There are a few configuration options available to you: + +```yml +PackagistShortCode: + CacheTime: 86400 #Cache time in seconds (default is 1 day, remember the GitHub api is rate limited) + UseShortHandNumbers: true #Use short hand numbers i.e 5.6K or not +``` diff --git a/_config.php b/_config.php new file mode 100644 index 0000000..3f9c716 --- /dev/null +++ b/_config.php @@ -0,0 +1,6 @@ +register('packagist', array('PackagistShortCode', 'parse')); +?> \ No newline at end of file diff --git a/_config/config.yml b/_config/config.yml new file mode 100644 index 0000000..46f53c4 --- /dev/null +++ b/_config/config.yml @@ -0,0 +1,6 @@ +--- +Name: packagistbutton +--- +PackagistShortCode: + CacheTime: 86400 #Cache time in seconds + UseShortHandNumbers: true #Use short hand numbers i.e 5.6K or not \ No newline at end of file diff --git a/code/PackagistShortCode.php b/code/PackagistShortCode.php new file mode 100644 index 0000000..def229e --- /dev/null +++ b/code/PackagistShortCode.php @@ -0,0 +1,109 @@ +Packagist package undefined

'; + } + + //Get Config + $config=Config::inst()->forClass('PackagistShortCode'); + + + $obj=new ViewableData(); + + //Add the Respository Setting + $obj->Package=$arguments['package']; + + //Add the button config + if(array_key_exists('mode', $arguments) && ($arguments['mode']=='total' || $arguments['mode']=='monthly' || $arguments['mode']=='daily')) { + $obj->DisplayMode=$arguments['mode']; + }else { + $obj->DisplayMode='total'; + } + + //Retrieve Stats + SS_Cache::set_cache_lifetime('PackagistShortCode', $config->CacheTime); + + $cacheKey=md5('packagistshortcode_'.$arguments['package']); + $cache=SS_Cache::factory('PackagistShortCode'); + $cachedData=$cache->load($cacheKey); + if($cachedData==null) { + $response=self::getFromAPI($arguments['package']); + + //Verify a 200, if not say the repo errored out and cache false + if(empty($response) || $response===false || !property_exists($response, 'package')) { + $cachedData=array('total'=>'N/A', 'monthly'=>'N/A', 'daily'=>'N/A'); + }else { + if($config->UseShortHandNumbers==true) { + $totalDownloads=self::shortHandNumber($response->package->downloads->total); + $monthlyDownloads=self::shortHandNumber($response->package->downloads->monthly); + $dailyDownloads=self::shortHandNumber($response->package->downloads->daily); + }else { + $totalDownloads=number_format($response->package->downloads->total); + $monthlyDownloads=number_format($response->package->downloads->monthly); + $dailyDownloads=number_format($response->package->downloads->daily); + } + + $cachedData=array('total'=>$totalDownloads, 'monthly'=>$monthlyDownloads, 'daily'=>$dailyDownloads); + } + + //Cache response to file system + $cache->save(serialize($cachedData), $cacheKey); + }else { + $cachedData=unserialize($cachedData); + } + + + $obj->TotalDownloads=$cachedData['total']; + $obj->MonthlyDownloads=$cachedData['monthly']; + $obj->DailyDownloads=$cachedData['daily']; + + + //Init ss viewer and render + Requirements::css(PACKAGISTSHORTCODE_BASE.'/css/PackagistButton.css'); + + $ssViewer=new SSViewer('PackagistButton'); + return $ssViewer->process($obj); + } + + /** + * Loads the data from the github api + * @param {string} $url URL to load + * @return {stdObject} Returns the JSON Response from the GitHub API + * + * @see http://developer.github.com/v3/repos/#get + */ + final protected static function getFromAPI($repo) { + if(function_exists('curl_init') && $ch=curl_init()) { + curl_setopt($ch, CURLOPT_URL, 'https://packagist.org/packages/'.$repo.'.json'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + + + $contents=json_decode(curl_exec($ch)); + curl_close($ch); + + return $contents; + }else { + user_error('CURL is not available', E_USER_ERROR); + } + } + + /** + * Gets the short hand of the given number so 1000 becomes 1k, 2000 becomes 2k, and 1000000 becomes 1m etc + * @param {int} $number Number to convert + * @return {string} Short hand of the given number + */ + protected static function shortHandNumber($number) { + if($number>=1000000000) { + return round($number/1000000000, 1).'B'; + }else if($number>=1000000) { + return round($number/1000000, 1).'M'; + }else if($number>=1000) { + return round($number/1000, 1).'K'; + } + + return $number; + } +} +?> \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..367a3ef --- /dev/null +++ b/composer.json @@ -0,0 +1,23 @@ +{ + "name": "webbuilders-group/silverstripe-packagistshortcode", + "description": "Add a short code for adding a Packagist installs button with a count to a HTMLText field.", + "type": "silverstripe-module", + "keywords": ["silverstripe", "packagist", "shortcode"], + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Ed Chipman", + "homepage": "http://webbuildersgroup.com", + "role": "Developer" + } + ], + + "require": + { + "silverstripe/framework": "3.*", + "composer/installers": "*" + }, + "support": { + "issues": "https://github.com/webbuilders-group/silverstripe-packagistshortcode/issues" + } +} diff --git a/css/PackagistButton.css b/css/PackagistButton.css new file mode 100644 index 0000000..08536d4 --- /dev/null +++ b/css/PackagistButton.css @@ -0,0 +1,98 @@ +.packagistButtonGroup .packagistButton { + clear: both; + + margin: 10px 0 20px 0; +} + +.packagistButtonGroup.stacked .packagistButton { + display: block; +} + +.packagistButtonGroup.stacked .packagistButton + .packagistButton { + margin-top: -10px; +} + +.packagistButtonGroup.inline .packagistButton + .packagistButton { + margin-left: 4ex; +} + +.packagistButtonGroup .packagistButton a { + background: url(./../images/packagist-button.png) no-repeat; + + display: inline-block; + + width: 170px; + height: 26px; + + vertical-align: middle; +} + +.packagistButtonGroup a.packagistDownloadsButton:hover, .packagistButtonGroup a.packagistDownloadsButton:active { + background-position: 0 -26px; +} + +.packagistButtonGroup .packagistButton span.count { + background-color: #FAFAFA; + + position: relative; + + font-family: Arial, sans-serif; + font-size: 11px; + color: #666666; + + text-decoration: none; + text-shadow: 0 1px 0 #FFFFFF; + + line-height: 15px; + + white-space: nowrap; + + border: 1px solid #DDDDDD; + + margin-left: 8px; + padding: 6px 7px 5px; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.packagistButtonGroup .packagistButton span.count:after { + display: block; + + position: absolute; + top: 50%; + right: 100%; + + content: ""; + + border-width: 6px; + border-style: solid; + border-color: transparent #FAFAFA transparent transparent; + + width: 0; + height: 0; + + margin-right: -1px; + margin-top: -6px; +} + +.packagistButtonGroup .packagistButton span.count:before { + display: block; + + position: absolute; + top: 50%; + right: 100%; + + content: ""; + + border-width: 6px; + border-style: solid; + border-color: transparent #D4D4D4 transparent transparent; + + width: 0; + height: 0; + + margin-right: 0; + margin-top: -6px; +} \ No newline at end of file diff --git a/images/packagist-button.png b/images/packagist-button.png new file mode 100644 index 0000000000000000000000000000000000000000..b6cc080a4ea1da1a1baa6f3adf4333cdacd3f956 GIT binary patch literal 5845 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 literal 0 HcmV?d00001 diff --git a/templates/Includes/PackagistButton.ss b/templates/Includes/PackagistButton.ss new file mode 100644 index 0000000..cc5cca4 --- /dev/null +++ b/templates/Includes/PackagistButton.ss @@ -0,0 +1,14 @@ +

+ + + + <% if $DisplayMode=='monthly' %> + $MonthlyDownloads + <% else_if $DisplayMode=='daily' %> + $DailyDownloads + <% else %> + $TotalDownloads + <% end_if %> + + +

\ No newline at end of file