Overview

Packages

  • AlfredBundler
  • None

Classes

  • CocoaDialog
  • ProgressBar
  • TerminalNotifier
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * PHP API for interacting with OSX dialog spawner Terminal Notifier.
  5:  * 
  6:  * Terminal Notifier is a resource which allows the user to spawn MacOSX notifications
  7:  * from the command-line. Notifications return nothing.
  8:  * 
  9:  * Official Documentation {@link https://github.com/alloy/terminal-notifier}
 10:  * LICENSE: GPLv3 {@link https://www.gnu.org/licenses/gpl-3.0.txt}
 11:  *
 12:  * -> Usage
 13:  * ===========================================================================
 14:  *
 15:  * To include this api in your PHP scripts, copy this ``terminalnotifier.php`` 
 16:  * to a viable place for you to include.
 17:  *
 18:  * Build the Terminal Notifier client:
 19:  *
 20:  *     include('terminalnotifier');
 21:  *     $client = new TerminalNotifier('path to terminal-notifier.app or exec', $debug=Boolean)
 22:  *     
 23:  * Now that you have access to the client, you can call specific dialogs:
 24:  *
 25:  *     $my_notification = $client.notify([
 26:  *         'title'=>'My Notification',
 27:  *         'subtitle'=>'Hello, World!',
 28:  *         'message'=>'Have a nice day!',
 29:  *         'sender'=>'com.apple.Finder']);
 30:  * 
 31:  * **NOTE**: The included `debug` parameter is very useful for finding out why
 32:  * your specified parameters are not being shown, or why your parameters are not
 33:  * passing as valid parameters, and thus the dialog is not being spawned.
 34:  *
 35:  * -> Revisions
 36:  * ============================================================================
 37:  * 1.0, 07-28-14: Initial release
 38:  * 
 39:  * @copyright  Ritashugisha 2014
 40:  * @license    https://www.gnu.org/licenses/gpl-3.0.txt  GPL v3
 41:  * @version    1.0
 42:  */
 43: 
 44: $AUTHOR = 'Ritashugisha <ritashugisha@gmail.com>';
 45: $DATE = '07-28-14';
 46: $VERSION = 1.0;
 47: 
 48: 
 49: /**
 50:  * Main class used for interaction with Terminal Notifier.
 51:  *
 52:  * Public class used to initialize the Terminal Notifier interaction client.
 53:  * Client inintialization is built by:
 54:  *
 55:  *     $client = new TerminalNotifier('path to terminal-notifier.app or exec', $debug=bool)
 56:  *
 57:  * Initializes valid and required options.
 58:  */
 59: class TerminalNotifier {
 60: 
 61:     /**
 62:      * Reference to Terminal Notifier exec
 63:      *
 64:      * @access private
 65:      * @var string
 66:      */
 67:     private $notifier;
 68: 
 69:     /**
 70:      * Toggle for log output
 71:      *
 72:      * @access private
 73:      * @var boolean
 74:      */
 75:     private $debug;
 76: 
 77:     /**
 78:      * Associative array of valid notification options
 79:      *
 80:      * @access private
 81:      * @var array
 82:      */
 83:     private $valid_options;
 84: 
 85:     /**
 86:      * Array of required notification options
 87:      *
 88:      * @access private
 89:      * @var array
 90:      */
 91:     private $required_options;
 92: 
 93:     /**
 94:      * This function prints debug logs to the console.
 95:      * 
 96:      * @param string $level Logging level (adapted from Python's logging module)
 97:      * @param string $funct Calling function's name
 98:      * @param integer $lineno Calling functions line number
 99:      * @param string $message Desired message
100:      */
101:     function log( $level, $funct, $lineno, $message ) {
102:         if ( $this->debug ) {
103:             echo sprintf( "[%s] [%s:%d] [%s] %s\xA", date('Y-m-d h:i:s'), basename(__FILE__), $lineno, strtoupper( $level ), $message );
104:         }
105:     }
106: 
107:     /**
108:      * TerminalNotifier class constructor.
109:      * 
110:      * @access public
111:      * @param string $notifier Path to either terminal-notifier.app or exec
112:      * @param boolean $debug True if logging is enabled
113:      */
114:     public function __construct( $notifier, $debug=False ) {
115:         $this->notifier = $notifier;
116:         $this->debug = $debug;
117:         date_default_timezone_set('UTC');
118:         if ( file_exists( $this->notifier ) ) {
119:             if ( 'app' === strtolower( pathinfo( $notifier, PATHINFO_EXTENSION ) ) ) {
120:                 $this->notifier = '/' . join( '/', array( trim( $notifier, '/' ), 
121:                     trim( '/Contents/MacOS/terminal-notifier', '/' ) ) );
122:                 $valid_notifier = file_exists( $this->notifier );
123:             }
124:             else {
125:                 $valid_notifier = ( strtolower( basename( $this->notifier ) ) === 'terminal-notifier' );
126:             }
127:         }
128:         else {
129:             $valid_notifier = False;
130:         }
131:         if ( ! $valid_notifier ) {
132:             $this->log( 'critical', __FUNCTION__, __LINE__, 
133:                 sprintf( 'invalid path to terminal-notifier (%s)', $this->notifier ) );
134:             die();
135:         }
136:         $this->valid_options = [
137:             'message' => ['string'],
138:             'title' => ['string'],
139:             'subtitle' => ['string'],
140:             'sound' => ['string'],
141:             'group' => ['string'],
142:             'remove' => ['string'],
143:             'activate' => ['string'],
144:             'sender' => ['string'],
145:             'appIcon' => ['string'],
146:             'contentImage' => ['string'],
147:             'open' => ['string'],
148:             'execute' => ['string']
149:         ];
150:         $this->required_options = ['message'];
151:     }
152: 
153:     /**
154:      * Run a process on the host system.
155:      * 
156:      * @param string $process Process to be run
157:      * @return string Output of process
158:      */
159:     public function _run_subprocess( $process ) {
160:         // Preferrably, we should send a string rather than a list in PHP
161:         if ( gettype( $process ) === 'array' ) {
162:             $process = join( ' ', $process );
163:         }
164:         return shell_exec( $process );
165:     }
166: 
167:     /**
168:      * Validate and clean up passed notification options.
169:      * 
170:      * @param array $passed Associative array of passed dialog arguemnts
171:      */
172:     public function _valid_options( $passed ) {
173:         $_is_valid = True;
174: 
175:         // First we validate that all $passed options are valid options and \
176:         // are the coresponding valid type
177:         foreach ( array_keys( $passed ) as $passed_key ) {
178:             if ( in_array( $passed_key, array_keys( $this->valid_options ) ) ) {
179:                 if ( ! in_array( gettype( $passed[$passed_key] ), $this->valid_options[$passed_key] ) ) {
180:                     $this->log( 'warning', __FUNCTION__, __LINE__, 
181:                         sprintf( 'removing (%s) invalid type, expected (%s), got (%s)',
182:                         $passed_key,
183:                         implode( ' or ', array_values( $this->valid_options[$passed_key] ) ),
184:                         gettype( $passed[$passed_key] ) ) );
185:                     unset( $passed[$passed_key] );
186:                 }
187:             }
188:             else {
189:                 $this->log( 'warning', __FUNCTION__, __LINE__, 
190:                     sprintf( 'removing (%s) invalid parameter, available are (%s)',
191:                         $passed_key,
192:                         implode( ', ', array_keys( $this->valid_options ) ) ) );
193:                 unset( $passed[$passed_key] );
194:             }
195:         }
196: 
197:         // Next we can check that the $passed options contain the required \
198:         // options
199:         foreach ( $this->required_options as $required_key ) {
200:             if ( ! in_array( $required_key, array_keys( $passed ) ) ) {
201:                 $this->log( 'error', __FUNCTION__, __LINE__,
202:                     sprintf( 'missing required parameter (%s)', $required_key ) );
203:                 $_is_valid = False;
204:             }
205:         }
206: 
207:         // If the remove option is given, then we sould remove all other \
208:         // options in order to allow room for notification removal to occur.
209:         if ( in_array( 'remove', array_keys( $passed ) ) ) {
210:             $_is_valid = True;
211:             foreach ( array_keys( $passed ) as $k ) {
212:                 if ( substr( $k, 0, 6 ) !== 'remove' ) {
213:                     unset( $passed[$k] );
214:                 }
215:             }
216:         }
217: 
218:         // PHP is stupid, that's why we have to remember and return the formated passed
219:         // arguments back to our notification
220:         return [$_is_valid, $passed];
221:     }
222: 
223:      /**
224:      * Display the passed notification after some crutial formatting.
225:      * 
226:      * @param array $passed Associative array of passed dialog options
227:      */
228:     public function _display( $passed ) {
229:         $process = ["'$this->notifier'"];
230:         foreach ( $passed as $k => $v ) {
231:             array_push( $process, sprintf( '-%s', $k ) );
232:             // It is important we escape the first character of every value
233:             // passed. This is a known bug in TN.
234:             array_push( $process, sprintf( '"\\%s"', $v ) );
235:         }
236:         try {
237:             $this->log('info', __FUNCTION__, __LINE__, implode( ' ', $process ) );
238:             $this->_run_subprocess( implode( ' ', $process ) );
239:         } catch (Exception $e) {
240:             $this->log('critical', __FUNCTION__, __LINE__, $e );
241:         }
242:     } 
243: 
244:     /**
245:      * Spawn a notification with passed arguments
246:      * 
247:      * @param array $_passed Associative array of notification arguments
248:      */
249:     public function notify( array $_passed ) {
250:         $_valid = $this->_valid_options( $_passed );
251:         if ( $_valid[0] ) {
252:             $this->_display( $_valid[1] );
253:         }
254:     }
255: }
256: 
Alfred Bundler API documentation generated by ApiGen 2.8.0