From 3cfc08abb151f6942d85570636dd166282ea2e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFck=20Piera?= Date: Sun, 1 Mar 2015 10:25:35 +0100 Subject: [PATCH] Initial commit --- .gitignore | 25 + CHANGELOG.md | 8 + CONTRIBUTING.md | 51 + LICENSE | 19 + README.md | 65 + VERSIONING.md | 22 + composer.json | 28 + composer.lock | 1328 +++++++++++++++++ example/index.php | 31 + example/notification-icon.png | Bin 0 -> 10706 bytes phpunit.xml.dist | 27 + src/Driver/CliBasedDriver.php | 49 + src/Driver/Driver.php | 44 + src/Driver/GrowlNotifyDriver.php | 61 + src/Driver/NotifySendDriver.php | 60 + src/Driver/TerminalNotifierDriver.php | 61 + src/Driver/UnixBasedDriver.php | 44 + src/Exception/Exception.php | 16 + .../InvalidNotificationException.php | 37 + src/Exception/SystemNotSupportedException.php | 16 + src/Notification.php | 90 ++ src/Notifier.php | 91 ++ tests/Driver/CliBasedDriverTestTrait.php | 57 + tests/Driver/DriverTestCase.php | 41 + tests/Driver/GrowlNotifyDriverTest.php | 109 ++ tests/Driver/NotifySendDriverTest.php | 109 ++ tests/Driver/TerminalNotifierDriverTest.php | 109 ++ tests/Driver/UnixBasedDriverTestTrait.php | 32 + tests/NotifierTest.php | 164 ++ tests/fixtures/ConfigurableDriver.php | 69 + 30 files changed, 2863 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 VERSIONING.md create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 example/index.php create mode 100644 example/notification-icon.png create mode 100644 phpunit.xml.dist create mode 100644 src/Driver/CliBasedDriver.php create mode 100644 src/Driver/Driver.php create mode 100644 src/Driver/GrowlNotifyDriver.php create mode 100644 src/Driver/NotifySendDriver.php create mode 100644 src/Driver/TerminalNotifierDriver.php create mode 100644 src/Driver/UnixBasedDriver.php create mode 100644 src/Exception/Exception.php create mode 100644 src/Exception/InvalidNotificationException.php create mode 100644 src/Exception/SystemNotSupportedException.php create mode 100644 src/Notification.php create mode 100644 src/Notifier.php create mode 100644 tests/Driver/CliBasedDriverTestTrait.php create mode 100644 tests/Driver/DriverTestCase.php create mode 100644 tests/Driver/GrowlNotifyDriverTest.php create mode 100644 tests/Driver/NotifySendDriverTest.php create mode 100644 tests/Driver/TerminalNotifierDriverTest.php create mode 100644 tests/Driver/UnixBasedDriverTestTrait.php create mode 100644 tests/NotifierTest.php create mode 100644 tests/fixtures/ConfigurableDriver.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fab9e47 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# IDE +.build_dir +.externalTollBuilders +.settings +.project +.buildpath +deps.lock +.idea + +# OS +.DS_Store +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes +.buildpath +.project +.settings + +# Dependencies +/vendor + +# Composer +composer.phar diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..be11269 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changes between versions + +## Not yet released + +* added Notification, Notifier and Driver +* added NotifySendDriver (can be used on most Linux distributions) +* added TerminalNotifierDriver (can be used on Mac OS X 10.8 and higher) +* added GrowlNotifyDriver (can be used on Mac OS if growlnotify is available) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e63e838 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,51 @@ +# How to contribute + +Everybody should be able to help. Here's how you can make this project more +awesome: + +1. [Fork it](https://github.com/jolicode/JoliNotif/fork_select) +2. improve it +3. submit a [pull request](https://help.github.com/articles/creating-a-pull-request) + +Your work will then be reviewed as soon as possible (suggestions about some +changes, improvements or alternatives may be given). + +Here's some tips to make you the best contributor ever: + +* [Green tests](#green-tests) +* [Standard code](#standard-code) +* [Keeping your fork up-to-date](#keeping-your-fork-up-to-date) + +## Green tests + +Run the tests using the following script: + + vendor/bin/phpunit + +## Standard code + +Use [PHP CS fixer](http://cs.sensiolabs.org/) to make your code compliant with +JoliNotif's coding standards: + + vendor/bin/php-cs-fixer fix --config=sf23 . + +## Keeping your fork up-to-date + +To keep your fork up-to-date, you should track the upstream (original) one +using the following command: + + git remote add upstream https://github.com/jolicode/JoliNotif.git + +Then get the upstream changes: + + git checkout master + git pull --rebase origin master + git pull --rebase upstream master + git checkout + git rebase master + +Finally, publish your changes: + + git push -f origin + +Your pull request will be automatically updated. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6051c3a --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Loïck Piera + +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 new file mode 100644 index 0000000..128aaa5 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# JoliNotif + +JoliNotif allows you to send notification to your system directly from your php +script. The notifier will take care to use the right command available, without +having to worry if you're running on Linux, Windows or MacOS. + +JoliNotif can be used from your long running task, f.e. to inform your user +that a task just finished. Originally inspired by [mikaelbr/node-notifier](https://github.com/mikaelbr/node-notifier). + +## Getting started + +Use [Composer](http://getcomposer.org/) to install JoliNotif in your projects: + + + composer require "jolicode/jolinotif" + + +## Usage + +The main class is `Notifier`. It should be instantiated with an array of +`Driver`. The `Notifier` constructor will choose the best driver to use, +according to which commands are available on your system. If no driver are +supported, a `SystemNotSupportedException` will be thrown. + +Look at below (or [example/index.php](example/index.php)) to see an example on +how to use JoliNotif. + +```php +// Build a Notifier +$notifier = new Notifier([ + new TerminalNotifierDriver(), + new GrowlNotifyDriver(), + new NotifySendDriver(), +]); + +// Create your notification +$notification = new Notification(); +$notification->setTitle('I\'m a notification title'); +$notification->setBody('And this is the body'); +$notification->setIcon(__DIR__.'/notification-icon.png'); + +// Send it +$notifier->send($notification); +``` + +> **Important**: The only required property on Notification is the body. +> The notifier will throw an InvalidNotificationException if it is empty. + +> **Note**: New properties could be added later on Notification. Drivers are +> designed to only handle the supported properties and discard not supported +> ones without throwing any exception. + +## Further documentation + +You can see the current and past versions using one of the following: + +* the `git tag` command +* the [releases page on Github](https://github.com/jolicode/JoliNotif/releases) +* the file listing the [changes between versions](CHANGELOG.md) + +You can find more documentation at the following links: + +* [copyright and MIT license](LICENSE) +* [versioning and branching models](VERSIONING.md) +* [contribution instructions](CONTRIBUTING.md) diff --git a/VERSIONING.md b/VERSIONING.md new file mode 100644 index 0000000..8a5cab0 --- /dev/null +++ b/VERSIONING.md @@ -0,0 +1,22 @@ +# Versioning and branching models + +This file explains the versioning and branching models of this project. + +## Versioning + +The versioning is inspired by [Semantic Versioning](http://semver.org/): + +> Given a version number MAJOR.MINOR.PATCH, increment the: +> +> 1. MAJOR version when you make incompatible API changes +> 2. MINOR version when you add functionality in a backwards-compatible manner +> 3. PATCH version when you make backwards-compatible bug fixes + +## Branching Model + +The branching is inspired by [@jbenet](https://github.com/jbenet) +[simple git branching model](https://gist.github.com/jbenet/ee6c9ac48068889b0912): + +> 1. `master` must always be deployable. +> 2. **all changes** are made through feature branches (pull-request + merge) +> 3. rebase to avoid/resolve conflicts; merge in to `master` diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..75a01a3 --- /dev/null +++ b/composer.json @@ -0,0 +1,28 @@ +{ + "name": "jolicode/jolinotif", + "license": "MIT", + "type": "library", + + "description": "Send desktop notifications on Windows, Linux, MacOS.", + "keywords": ["notification", "windows", "linux", "mac", "growl"], + "minimum-stability": "stable", + + "autoload": { + "psr-4": { + "JoliNotif\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "JoliNotif\\tests\\": "tests/" + } + }, + "require": { + "php": ">=5.4.0", + "symfony/process": "~2.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.5", + "fabpot/php-cs-fixer": "~1.5" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..74fbc09 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1328 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "550c9d7dab0c3538e7d0f337532705d7", + "packages": [ + { + "name": "symfony/process", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Process", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process.git", + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Process/zipball/ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Process\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Process Component", + "homepage": "http://symfony.com", + "time": "2015-01-25 04:39:26" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "2.0.*@ALPHA" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Instantiator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2014-10-13 12:58:55" + }, + { + "name": "fabpot/php-cs-fixer", + "version": "v1.5", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "2d6851520bf0250f668307ab2fd28cbb0b35d2b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/2d6851520bf0250f668307ab2fd28cbb0b35d2b9", + "reference": "2d6851520bf0250f668307ab2fd28cbb0b35d2b9", + "shasum": "" + }, + "require": { + "php": ">=5.3.6", + "sebastian/diff": "~1.1", + "symfony/console": "~2.1", + "symfony/event-dispatcher": "~2.1", + "symfony/filesystem": "~2.1", + "symfony/finder": "~2.1", + "symfony/process": "~2.3", + "symfony/stopwatch": "~2.5" + }, + "require-dev": { + "satooshi/php-coveralls": "0.7.*@dev" + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "Symfony\\CS\\": "Symfony/CS/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "A script to automatically fix Symfony Coding Standard", + "time": "2015-02-18 19:35:59" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, + { + "name": "phpspec/prophecy", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.2", + "phpdocumentor/reflection-docblock": "~2.0" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "http://phpspec.org", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2014-11-17 16:23:49" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.0.15", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "34cc484af1ca149188d0d9e91412191e398e0b67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/34cc484af1ca149188d0d9e91412191e398e0b67", + "reference": "34cc484af1ca149188d0d9e91412191e398e0b67", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "~1.0", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-01-24 10:06:35" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2013-08-02 07:42:54" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-01-17 09:51:32" + }, + { + "name": "phpunit/phpunit", + "version": "4.5.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "5b578d3865a9128b9c209b011fda6539ec06e7a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5b578d3865a9128b9c209b011fda6539ec06e7a5", + "reference": "5b578d3865a9128b9c209b011fda6539ec06e7a5", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "~1.3.1", + "phpunit/php-code-coverage": "~2.0", + "phpunit/php-file-iterator": "~1.3.2", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.2", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.5.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-02-05 15:51:19" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "c63d2367247365f688544f0d500af90a11a44c65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c63d2367247365f688544f0d500af90a11a44c65", + "reference": "c63d2367247365f688544f0d500af90a11a44c65", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.1", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2014-10-03 05:12:11" + }, + { + "name": "sebastian/comparator", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-01-29 16:28:08" + }, + { + "name": "sebastian/diff", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2014-08-15 10:29:00" + }, + { + "name": "sebastian/environment", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e6c71d918088c251b181ba8b3088af4ac336dd7", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2014-10-25 08:00:45" + }, + { + "name": "sebastian/exporter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "84839970d05254c73cde183a721c7af13aede943" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-01-27 07:23:06" + }, + { + "name": "sebastian/global-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2014-10-06 09:23:50" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-01-24 09:48:32" + }, + { + "name": "sebastian/version", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/a77d9123f8e809db3fbdea15038c27a95da4058b", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2014-12-15 14:25:24" + }, + { + "name": "symfony/console", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Console", + "source": { + "type": "git", + "url": "https://github.com/symfony/Console.git", + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Console/zipball/e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.1" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Console Component", + "homepage": "http://symfony.com", + "time": "2015-01-25 04:39:26" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.6.4", + "target-dir": "Symfony/Component/EventDispatcher", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "f75989f3ab2743a82fe0b03ded2598a2b1546813" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/f75989f3ab2743a82fe0b03ded2598a2b1546813", + "reference": "f75989f3ab2743a82fe0b03ded2598a2b1546813", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "http://symfony.com", + "time": "2015-02-01 16:10:57" + }, + { + "name": "symfony/filesystem", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Filesystem", + "source": { + "type": "git", + "url": "https://github.com/symfony/Filesystem.git", + "reference": "a1f566d1f92e142fa1593f4555d6d89e3044a9b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/a1f566d1f92e142fa1593f4555d6d89e3044a9b7", + "reference": "a1f566d1f92e142fa1593f4555d6d89e3044a9b7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Filesystem\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 21:13:09" + }, + { + "name": "symfony/finder", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Finder", + "source": { + "type": "git", + "url": "https://github.com/symfony/Finder.git", + "reference": "16513333bca64186c01609961a2bb1b95b5e1355" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Finder/zipball/16513333bca64186c01609961a2bb1b95b5e1355", + "reference": "16513333bca64186c01609961a2bb1b95b5e1355", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Finder\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Finder Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 08:01:59" + }, + { + "name": "symfony/stopwatch", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Stopwatch", + "source": { + "type": "git", + "url": "https://github.com/symfony/Stopwatch.git", + "reference": "e8da5286132ba75ce4b4275fbf0f4cd369bfd71c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/e8da5286132ba75ce4b4275fbf0f4cd369bfd71c", + "reference": "e8da5286132ba75ce4b4275fbf0f4cd369bfd71c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Stopwatch\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 08:01:59" + }, + { + "name": "symfony/yaml", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/60ed7751671113cf1ee7d7778e691642c2e9acd8", + "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2015-01-25 04:39:26" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.4.0" + }, + "platform-dev": [] +} diff --git a/example/index.php b/example/index.php new file mode 100644 index 0000000..3a44a88 --- /dev/null +++ b/example/index.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use JoliNotif\Driver\GrowlNotifyDriver; +use JoliNotif\Driver\NotifySendDriver; +use JoliNotif\Driver\TerminalNotifierDriver; +use JoliNotif\Notification; +use JoliNotif\Notifier; + +require __DIR__.'/../vendor/autoload.php'; + +$notifier = new Notifier([ + new TerminalNotifierDriver(), + new GrowlNotifyDriver(), + new NotifySendDriver(), +]); + +$notification = new Notification(); +$notification->setTitle('I\'m a notification title'); +$notification->setBody('And this is the body'); +$notification->setIcon(__DIR__.'/notification-icon.png'); + +$notifier->send($notification); diff --git a/example/notification-icon.png b/example/notification-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cfead59bf73da5821ec1571a5e2dede89c6b9f3f GIT binary patch literal 10706 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 literal 0 HcmV?d00001 diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..9781723 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,27 @@ + + + + + + + + + + ./tests/ + + + + + + ./ + + ./vendor + + + + diff --git a/src/Driver/CliBasedDriver.php b/src/Driver/CliBasedDriver.php new file mode 100644 index 0000000..bb3744a --- /dev/null +++ b/src/Driver/CliBasedDriver.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Driver; + +use JoliNotif\Notification; +use Symfony\Component\Process\ProcessBuilder; + +abstract class CliBasedDriver implements Driver +{ + /** + * Get the arguments that will be passed to the process in order to send the notification. + * + * @param Notification $notification + * + * @return array + */ + abstract protected function getProcessArguments(Notification $notification); + + /** + * Get the binary to check existence. + * + * @return string + */ + abstract protected function getBinary(); + + /** + * {@inheritdoc} + */ + public function send(Notification $notification) + { + $arguments = $this->getProcessArguments($notification); + + $builder = new ProcessBuilder($arguments); + $process = $builder->getProcess(); + + $process->run(); + + return $process->isSuccessful(); + } +} diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php new file mode 100644 index 0000000..675160e --- /dev/null +++ b/src/Driver/Driver.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Driver; + +use JoliNotif\Notification; + +interface Driver +{ + const PRIORITY_LOW = 0; + const PRIORITY_MEDIUM = 50; + const PRIORITY_HIGH = 100; + + /** + * This method is called to check whether the driver can be used on the current system or not. + * + * @return bool + */ + public function isSupported(); + + /** + * The supported driver with the higher priority will be preferred. + * + * @return int + */ + public function getPriority(); + + /** + * Send a the given notification. + * + * @param \JoliNotif\Notification $notification + * + * @return bool + */ + public function send(Notification $notification); +} diff --git a/src/Driver/GrowlNotifyDriver.php b/src/Driver/GrowlNotifyDriver.php new file mode 100644 index 0000000..3e36b46 --- /dev/null +++ b/src/Driver/GrowlNotifyDriver.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Driver; + +use JoliNotif\Notification; + +/** + * This driver can be used on Mac OS X when growlnotify command is available. + */ +class GrowlNotifyDriver extends UnixBasedDriver +{ + /** + * {@inheritdoc} + */ + public function getBinary() + { + return 'growlnotify'; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return static::PRIORITY_LOW; + } + + /** + * {@inheritdoc} + */ + protected function getProcessArguments(Notification $notification) + { + $arguments = [ + $this->getBinary(), + '--message', + $notification->getBody(), + ]; + + if ($notification->getTitle()) { + $arguments[] = '--title'; + $arguments[] = $notification->getTitle(); + } + + // Require 10.9+ + if (0 < strlen($notification->getIcon())) { + $arguments[] = '--image'; + $arguments[] = $notification->getIcon(); + } + + return $arguments; + } +} diff --git a/src/Driver/NotifySendDriver.php b/src/Driver/NotifySendDriver.php new file mode 100644 index 0000000..734ee1b --- /dev/null +++ b/src/Driver/NotifySendDriver.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Driver; + +use JoliNotif\Notification; + +/** + * This driver can be used on most Linux distributions, using the command notify-send. + * This command is packaged in libnotify-bin. + */ +class NotifySendDriver extends UnixBasedDriver +{ + /** + * {@inheritdoc} + */ + public function getBinary() + { + return 'notify-send'; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return static::PRIORITY_MEDIUM; + } + + /** + * {@inheritdoc} + */ + protected function getProcessArguments(Notification $notification) + { + $arguments = [ + $this->getBinary(), + ]; + + if (0 < strlen($notification->getIcon())) { + $arguments[] = '--icon'; + $arguments[] = $notification->getIcon(); + } + + if ($notification->getTitle()) { + $arguments[] = $notification->getTitle(); + } + + $arguments[] = $notification->getBody(); + + return $arguments; + } +} diff --git a/src/Driver/TerminalNotifierDriver.php b/src/Driver/TerminalNotifierDriver.php new file mode 100644 index 0000000..8efcf25 --- /dev/null +++ b/src/Driver/TerminalNotifierDriver.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Driver; + +use JoliNotif\Notification; + +/** + * This driver can be used on Mac OS X 10.8, or higher, using the terminal-notifier binary. + */ +class TerminalNotifierDriver extends UnixBasedDriver +{ + /** + * {@inheritdoc} + */ + public function getBinary() + { + return 'terminal-notifier'; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return static::PRIORITY_MEDIUM; + } + + /** + * {@inheritdoc} + */ + protected function getProcessArguments(Notification $notification) + { + $arguments = [ + $this->getBinary(), + '-message', + $notification->getBody(), + ]; + + if ($notification->getTitle()) { + $arguments[] = '-title'; + $arguments[] = $notification->getTitle(); + } + + // Require 10.9+ + if (0 < strlen($notification->getIcon())) { + $arguments[] = '-contentImage'; + $arguments[] = $notification->getIcon(); + } + + return $arguments; + } +} diff --git a/src/Driver/UnixBasedDriver.php b/src/Driver/UnixBasedDriver.php new file mode 100644 index 0000000..eb85378 --- /dev/null +++ b/src/Driver/UnixBasedDriver.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Driver; + +use Symfony\Component\Process\ProcessBuilder; + +abstract class UnixBasedDriver extends CliBasedDriver +{ + /** + * {@inheritdoc} + */ + public function isSupported() + { + if (DIRECTORY_SEPARATOR !== '/') { + return false; + } + + $bin = $this->getBinary(); + + // Do not use the which programm to check if a binary exists. + // See also http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script + $builder = new ProcessBuilder([ + 'command', + '-v', + $bin, + '>/dev/null', + '2>&1', + ]); + $process = $builder->getProcess(); + + $process->run(); + + return $process->isSuccessful(); + } +} diff --git a/src/Exception/Exception.php b/src/Exception/Exception.php new file mode 100644 index 0000000..736a93f --- /dev/null +++ b/src/Exception/Exception.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Exception; + +interface Exception +{ +} diff --git a/src/Exception/InvalidNotificationException.php b/src/Exception/InvalidNotificationException.php new file mode 100644 index 0000000..4c50b49 --- /dev/null +++ b/src/Exception/InvalidNotificationException.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Exception; + +use JoliNotif\Notification; + +class InvalidNotificationException extends \LogicException implements Exception +{ + /** + * @var \JoliNotif\Notification + */ + private $notification; + + public function __construct(Notification $notification, $message = "", $code = 0, Exception $previous = null) + { + $this->notification = $notification; + + parent::__construct($message, $code, $previous); + } + + /** + * @return Notification + */ + public function getNotification() + { + return $this->notification; + } +} diff --git a/src/Exception/SystemNotSupportedException.php b/src/Exception/SystemNotSupportedException.php new file mode 100644 index 0000000..16f2dc0 --- /dev/null +++ b/src/Exception/SystemNotSupportedException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\Exception; + +class SystemNotSupportedException extends \RuntimeException implements Exception +{ +} diff --git a/src/Notification.php b/src/Notification.php new file mode 100644 index 0000000..f71b9e9 --- /dev/null +++ b/src/Notification.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif; + +class Notification +{ + /** + * @var string + */ + private $title; + + /** + * @var string + */ + private $body; + + /** + * @var string + */ + private $icon; + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $title + * + * @return $this + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * @return string + */ + public function getBody() + { + return $this->body; + } + + /** + * @param string $body + * + * @return $this + */ + public function setBody($body) + { + $this->body = $body; + + return $this; + } + + /** + * @return string + */ + public function getIcon() + { + return $this->icon; + } + + /** + * @param string $icon + * + * @return $this + */ + public function setIcon($icon) + { + $this->icon = $icon; + + return $this; + } +} diff --git a/src/Notifier.php b/src/Notifier.php new file mode 100644 index 0000000..c07a8c3 --- /dev/null +++ b/src/Notifier.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif; + +use JoliNotif\Driver\Driver; +use JoliNotif\Exception\InvalidNotificationException; +use JoliNotif\Exception\SystemNotSupportedException; + +class Notifier +{ + /** + * @var Driver[] + */ + private $drivers = []; + + /** + * @var Driver + */ + private $driverInUse; + + /** + * @param Driver[] $drivers + * + * @throw SystemNotSupportedException if no drivers are supported + */ + public function __construct(array $drivers) + { + $this->drivers = $drivers; + + $this->driverInUse = $this->chooseBestDriver(); + } + + /** + * @return Driver + */ + public function getDriverInUse() + { + return $this->driverInUse; + } + + /** + * @param Notification $notification + * + * @return bool + */ + public function send(Notification $notification) + { + if (strlen($notification->getBody()) < 1) { + throw new InvalidNotificationException($notification, 'Notification body can not be empty'); + } + + return $this->driverInUse->send($notification); + } + + /** + * @return Driver + * + * @throw SystemNotSupportedException if no drivers are supported + */ + private function chooseBestDriver() + { + $bestDriver = null; + + foreach ($this->drivers as $driver) { + if (!$driver->isSupported()) { + continue; + } + + if (null !== $bestDriver && $bestDriver->getPriority() >= $driver->getPriority()) { + continue; + } + + $bestDriver = $driver; + } + + if (null === $bestDriver) { + throw new SystemNotSupportedException('No drivers support your system'); + } + + return $bestDriver; + } +} diff --git a/tests/Driver/CliBasedDriverTestTrait.php b/tests/Driver/CliBasedDriverTestTrait.php new file mode 100644 index 0000000..9753f3c --- /dev/null +++ b/tests/Driver/CliBasedDriverTestTrait.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\tests\Driver; + +use JoliNotif\Notification; + +/** + * The class using this trait should extend DriverTestCase. + */ +trait CliBasedDriverTestTrait +{ + /** + * @param \JoliNotif\Notification $notification + * + * @dataProvider provideValidNotifications + */ + public function testSendAcceptAnyValidNotification(Notification $notification) + { + try { + $arguments = $this->invokeMethod($this->getDriver(), 'getProcessArguments', [$notification]); + $this->assertInternalType('array', $arguments); + $this->assertGreaterThan(1, count($arguments)); + } catch(\Exception $e) { + $this->fail($e->getMessage()); + } + } + + /** + * @return array + */ + public static function provideValidNotifications() + { + return [ + [(new Notification()) + ->setBody('The notification body')], + [(new Notification()) + ->setBody('The notification body') + ->setTitle('The notification title')], + [(new Notification()) + ->setBody('The notification body') + ->setIcon('example/notification-icon.png')], + [(new Notification()) + ->setBody('The notification body') + ->setTitle('The notification title') + ->setIcon('example/notification-icon.png')], + ]; + } +} diff --git a/tests/Driver/DriverTestCase.php b/tests/Driver/DriverTestCase.php new file mode 100644 index 0000000..27d5f01 --- /dev/null +++ b/tests/Driver/DriverTestCase.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\tests\Driver; + +use JoliNotif\Driver\Driver; +use JoliNotif\Notification; + +abstract class DriverTestCase extends \PHPUnit_Framework_TestCase +{ + /** + * @return Driver + */ + abstract protected function getDriver(); + + /** + * Call protected/private method of a class. + * + * @param object $object Instantiated object that we will run method on. + * @param string $methodName Method name to call + * @param array $parameters Array of parameters to pass into method. + * + * @return mixed Method return. + */ + protected function invokeMethod($object, $methodName, array $parameters = array()) + { + $reflection = new \ReflectionClass(get_class($object)); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + + return $method->invokeArgs($object, $parameters); + } +} diff --git a/tests/Driver/GrowlNotifyDriverTest.php b/tests/Driver/GrowlNotifyDriverTest.php new file mode 100644 index 0000000..6f27958 --- /dev/null +++ b/tests/Driver/GrowlNotifyDriverTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\tests\Driver; + +use JoliNotif\Driver\Driver; +use JoliNotif\Driver\GrowlNotifyDriver; +use JoliNotif\Notification; + +class GrowlNotifyDriverTest extends DriverTestCase +{ + const BINARY = 'growlnotify'; + + use CliBasedDriverTestTrait; + use UnixBasedDriverTestTrait; + + protected function getDriver() + { + return new GrowlNotifyDriver(); + } + + public function testGetBinary() + { + $driver = $this->getDriver(); + + $this->assertSame(self::BINARY, $driver->getBinary()); + } + + public function testGetPriority() + { + $driver = $this->getDriver(); + + $this->assertSame(Driver::PRIORITY_LOW, $driver->getPriority()); + } + + /** + * @param \JoliNotif\Notification $notification + * @param array $expectedArguments + * + * @dataProvider provideNotifications + */ + public function testGetProcessArguments(Notification $notification, array $expectedArguments) + { + try { + $arguments = $this->invokeMethod($this->getDriver(), 'getProcessArguments', [$notification]); + $this->assertInternalType('array', $arguments); + $this->assertEquals($expectedArguments, $arguments); + } catch(\Exception $e) { + $this->fail($e->getMessage()); + } + } + + /** + * @return array + */ + public static function provideNotifications() + { + return [ + [ + (new Notification()) + ->setBody('The notification body'), + [ + self::BINARY, + '--message', 'The notification body' + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setTitle('The notification title'), + [ + self::BINARY, + '--message', 'The notification body', + '--title', 'The notification title' + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setIcon('/home/toto/Images/my-icon.png'), + [ + self::BINARY, + '--message', 'The notification body', + '--image', '/home/toto/Images/my-icon.png' + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setTitle('The notification title') + ->setIcon('/home/toto/Images/my-icon.png'), + [ + self::BINARY, + '--message', 'The notification body', + '--title', 'The notification title', + '--image', '/home/toto/Images/my-icon.png' + ], + ], + ]; + } +} diff --git a/tests/Driver/NotifySendDriverTest.php b/tests/Driver/NotifySendDriverTest.php new file mode 100644 index 0000000..1ab188c --- /dev/null +++ b/tests/Driver/NotifySendDriverTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\tests\Driver; + +use JoliNotif\Driver\Driver; +use JoliNotif\Driver\NotifySendDriver; +use JoliNotif\Notification; + +class NotifySendDriverTest extends DriverTestCase +{ + const BINARY = 'notify-send'; + + use CliBasedDriverTestTrait; + use UnixBasedDriverTestTrait; + + protected function getDriver() + { + return new NotifySendDriver(); + } + + public function testGetBinary() + { + $driver = $this->getDriver(); + + $this->assertSame(self::BINARY, $driver->getBinary()); + } + + public function testGetPriority() + { + $driver = $this->getDriver(); + + $this->assertSame(Driver::PRIORITY_MEDIUM, $driver->getPriority()); + } + + /** + * @param Notification $notification + * @param array $expectedArguments + * + * @dataProvider provideNotifications + */ + public function testGetProcessArguments(Notification $notification, array $expectedArguments) + { + try { + $arguments = $this->invokeMethod($this->getDriver(), 'getProcessArguments', [$notification]); + $this->assertInternalType('array', $arguments); + $this->assertEquals($expectedArguments, $arguments); + } catch(\Exception $e) { + $this->fail($e->getMessage()); + } + } + + /** + * @return array + */ + public static function provideNotifications() + { + return [ + [ + (new Notification()) + ->setBody('The notification body'), + [ + self::BINARY, + 'The notification body', + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setTitle('The notification title'), + [ + self::BINARY, + 'The notification title', + 'The notification body', + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setIcon('/home/toto/Images/my-icon.png'), + [ + self::BINARY, + '--icon', '/home/toto/Images/my-icon.png', + 'The notification body', + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setTitle('The notification title') + ->setIcon('/home/toto/Images/my-icon.png'), + [ + self::BINARY, + '--icon', '/home/toto/Images/my-icon.png', + 'The notification title', + 'The notification body' + ], + ], + ]; + } +} diff --git a/tests/Driver/TerminalNotifierDriverTest.php b/tests/Driver/TerminalNotifierDriverTest.php new file mode 100644 index 0000000..4e48f75 --- /dev/null +++ b/tests/Driver/TerminalNotifierDriverTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\tests\Driver; + +use JoliNotif\Driver\Driver; +use JoliNotif\Driver\TerminalNotifierDriver; +use JoliNotif\Notification; + +class TerminalNotifierDriverTest extends DriverTestCase +{ + const BINARY = 'terminal-notifier'; + + use CliBasedDriverTestTrait; + use UnixBasedDriverTestTrait; + + protected function getDriver() + { + return new TerminalNotifierDriver(); + } + + public function testGetBinary() + { + $driver = $this->getDriver(); + + $this->assertSame(self::BINARY, $driver->getBinary()); + } + + public function testGetPriority() + { + $driver = $this->getDriver(); + + $this->assertSame(Driver::PRIORITY_MEDIUM, $driver->getPriority()); + } + + /** + * @param \JoliNotif\Notification $notification + * @param array $expectedArguments + * + * @dataProvider provideNotifications + */ + public function testGetProcessArguments(Notification $notification, array $expectedArguments) + { + try { + $arguments = $this->invokeMethod($this->getDriver(), 'getProcessArguments', [$notification]); + $this->assertInternalType('array', $arguments); + $this->assertEquals($expectedArguments, $arguments); + } catch(\Exception $e) { + $this->fail($e->getMessage()); + } + } + + /** + * @return array + */ + public static function provideNotifications() + { + return [ + [ + (new Notification()) + ->setBody('The notification body'), + [ + self::BINARY, + '-message', 'The notification body' + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setTitle('The notification title'), + [ + self::BINARY, + '-message', 'The notification body', + '-title', 'The notification title' + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setIcon('/home/toto/Images/my-icon.png'), + [ + self::BINARY, + '-message', 'The notification body', + '-contentImage', '/home/toto/Images/my-icon.png' + ], + ], + [ + (new Notification()) + ->setBody('The notification body') + ->setTitle('The notification title') + ->setIcon('/home/toto/Images/my-icon.png'), + [ + self::BINARY, + '-message', 'The notification body', + '-title', 'The notification title', + '-contentImage', '/home/toto/Images/my-icon.png' + ], + ], + ]; + } +} diff --git a/tests/Driver/UnixBasedDriverTestTrait.php b/tests/Driver/UnixBasedDriverTestTrait.php new file mode 100644 index 0000000..fa99cc5 --- /dev/null +++ b/tests/Driver/UnixBasedDriverTestTrait.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\tests\Driver; + +/** + * The class using this trait should define a BINARY constant and extend DriverTestCase. + */ +trait UnixBasedDriverTestTrait +{ + public function testIsSupported() + { + $supported = DIRECTORY_SEPARATOR === '/'; + + if ($supported) { + $commandLine = 'command -v '.static::BINARY.' >/dev/null 2>&1 '; + passthru($commandLine, $return); + + $supported = $return === 0; + } + + $this->assertSame($supported, $this->getDriver()->isSupported()); + } +} diff --git a/tests/NotifierTest.php b/tests/NotifierTest.php new file mode 100644 index 0000000..34ded11 --- /dev/null +++ b/tests/NotifierTest.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\tests; + +use JoliNotif\Notification; +use JoliNotif\Notifier; +use JoliNotif\tests\fixtures\ConfigurableDriver; + +class NotifierTest extends \PHPUnit_Framework_TestCase +{ + public function testNoDriverOrNoSupportedDriverThrowsException() + { + try { + new Notifier([]); + $this->fail('Expected a SystemNotSupportedException'); + } catch (\Exception $e) { + $this->assertInstanceOf('JoliNotif\Exception\SystemNotSupportedException', $e); + } + + try { + new Notifier([ + new ConfigurableDriver(false), + new ConfigurableDriver(false), + ]); + $this->fail('Expected a SystemNotSupportedException'); + } catch (\Exception $e) { + $this->assertInstanceOf('JoliNotif\Exception\SystemNotSupportedException', $e); + } + } + + public function testTheBestSupportedDriverIsUsed() + { + // test case + $driver = new ConfigurableDriver(true); + + $notifier = new Notifier([ + $driver, + ]); + $this->assertSame($driver, $notifier->getDriverInUse()); + + // test case + $driver1 = new ConfigurableDriver(false); + $driver2 = new ConfigurableDriver(true); + $driver3 = new ConfigurableDriver(true); + $driver4 = new ConfigurableDriver(true); + + $notifier = new Notifier([ + $driver1, + $driver2, + $driver3, + $driver4, + ]); + $this->assertSame($driver2, $notifier->getDriverInUse()); + + // test case + $driver1 = new ConfigurableDriver(false); + $driver2 = new ConfigurableDriver(true, 5); + $driver3 = new ConfigurableDriver(false); + $driver4 = new ConfigurableDriver(true, 8); + $driver5 = new ConfigurableDriver(true, 6); + + $notifier = new Notifier([ + $driver1, + $driver2, + $driver3, + $driver4, + $driver5, + ]); + $this->assertSame($driver4, $notifier->getDriverInUse()); + + // test case + $driver1 = new ConfigurableDriver(false); + $driver2 = new ConfigurableDriver(true, 5); + $driver3 = new ConfigurableDriver(true, 8); + $driver4 = new ConfigurableDriver(false); + $driver5 = new ConfigurableDriver(true, 8); + + $notifier = new Notifier([ + $driver1, + $driver2, + $driver3, + $driver4, + $driver5, + ]); + $this->assertSame($driver3, $notifier->getDriverInUse()); + } + + public function testSendThrowsExceptionWhenNotificationHasAnEmptyBody() + { + $notifier = new Notifier([new ConfigurableDriver(true)]); + + // test case + $notification = new Notification(); + + try { + $notifier->send($notification); + $this->fail('Expected a InvalidNotificationException'); + } catch (\Exception $e) { + $this->assertInstanceOf('JoliNotif\Exception\InvalidNotificationException', $e); + } + + // test case + $notification = new Notification(); + $notification->setBody(''); + + try { + $notifier->send($notification); + $this->fail('Expected a InvalidNotificationException'); + } catch (\Exception $e) { + $this->assertInstanceOf('JoliNotif\Exception\InvalidNotificationException', $e); + } + } + + public function testSendUsesTheBestDriverAndReturnsItsReturn() + { + $notification = new Notification(); + $notification->setBody('My notification'); + + // test case + $driver = new ConfigurableDriver(true, 2, false); + + $notifier = new Notifier([ + $driver, + ]); + $this->assertFalse($notifier->send($notification)); + + // test case + $driver1 = new ConfigurableDriver(false, 0, false); + $driver2 = new ConfigurableDriver(true, 0, true); + $driver3 = new ConfigurableDriver(true, 0, false); + $driver4 = new ConfigurableDriver(true, 0, false); + + $notifier = new Notifier([ + $driver1, + $driver2, + $driver3, + $driver4, + ]); + $this->assertTrue($notifier->send($notification)); + + // test case + $driver1 = new ConfigurableDriver(false, 0, false); + $driver2 = new ConfigurableDriver(true, 0, false); + $driver3 = new ConfigurableDriver(true, 5, true); + $driver4 = new ConfigurableDriver(true, 2, false); + + $notifier = new Notifier([ + $driver1, + $driver2, + $driver3, + $driver4, + ]); + $this->assertTrue($notifier->send($notification)); + } +} diff --git a/tests/fixtures/ConfigurableDriver.php b/tests/fixtures/ConfigurableDriver.php new file mode 100644 index 0000000..95b243c --- /dev/null +++ b/tests/fixtures/ConfigurableDriver.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliNotif\tests\fixtures; + +use JoliNotif\Driver\Driver; +use JoliNotif\Notification; + +class ConfigurableDriver implements Driver +{ + /** + * @var bool + */ + private $supported; + + /** + * @var int + */ + private $priority; + + /** + * @var bool + */ + private $sendReturn; + + /** + * @param $supported + * @param $priority + * @param $sendReturn + */ + public function __construct($supported, $priority = Driver::PRIORITY_MEDIUM, $sendReturn = true) + { + $this->supported = $supported; + $this->priority = $priority; + $this->sendReturn = $sendReturn; + } + + /** + * {@inheritdoc} + */ + public function isSupported() + { + return $this->supported; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return $this->priority; + } + + /** + * {@inheritdoc} + */ + public function send(Notification $notification) + { + return $this->sendReturn; + } +}