Alphred
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  • Download

Namespaces

  • Alphred
  • None

Classes

  • Alphred
  1 <?php
  2 /**
  3  * Contains wrapper class for Alphred, the main entry point to use the library
  4  *
  5  * PHP version 5
  6  *
  7  * @package      Alphred
  8  * @copyright  Shawn Patrick Rice 2014
  9  * @license    http://opensource.org/licenses/MIT  MIT
 10  * @version    1.0.0
 11  * @author     Shawn Patrick Rice <rice@shawnrice.org>
 12  * @link       http://www.github.com/shawnrice/alphred
 13  * @link       http://shawnrice.github.io/alphred
 14  * @since      File available since Release 1.0.0
 15  *
 16  */
 17 
 18 
 19 /**
 20  * Wrapper Class.
 21  *
 22  * This provides a simple wrapper for all of the important parts of the Alphred library.
 23  * It also simplifies the usage of some of the internal components, so calls to this class
 24  * do not always mirror calls to the internal components.
 25  *
 26  */
 27 class Alphred {
 28 
 29     /**
 30      * Initializes the wrapper object
 31      *
 32      * @param array                 $options options that can be configured
 33      *                            currently, only two options are available:
 34      *                            1. error_on_empty  - displays a script filter item when empty
 35      *                            2. no_filter       - initializes object without a script filter
 36      *                            3. no_config       - creates without a config item
 37      *                            4. config_filename - sets filename for the config (default: `config`)
 38      *                            5. config_handler  - sets the handler for the config (default: `ini`)
 39      * @param array|boolean $plugins plugins to be run at load
 40      */
 41     public function __construct( $options = [ 'error_on_empty' => true ] ) {
 42 
 43         // We're going to parse the ini file (if it exists) and just merge what we find there
 44         // with the $options array. The original $options array will override the workflow.ini file.
 45         $options = array_merge( $options, $this->parse_ini_file() );
 46 
 47         // Create a script filter object unless explicitly turned off
 48         if ( ! isset( $options[ 'no_filter' ] ) || true !== $options[ 'no_filter' ] ) {
 49             $this->filter = new Alphred\ScriptFilter( $options );
 50         }
 51 
 52         if ( ! isset( $options[ 'no_config' ] ) || true !== $options[ 'no_config' ] ) {
 53             // Use `ini` as the default handler and `config` as the default filename
 54             $handler  = ( isset( $options['config_handler'] ) ) ? $options['config_handler'] : 'ini';
 55             $filename = ( isset( $options['config_filename'] ) ) ? $options['config_filename'] : 'config';
 56             // Create the config object
 57             $this->config = new Alphred\Config( $handler, $filename );
 58         }
 59     }
 60 
 61     /**
 62      * Reads the `workflow.ini` file if it exists
 63      *
 64      * @return array an array of config values
 65      */
 66     private function parse_ini_file() {
 67         // If the file does not exist, then exit early with an empty array
 68         if ( ! file_exists( 'workflow.ini' ) ) {
 69             return [];
 70         }
 71 
 72         // Read the ini file
 73         $ini = Alphred\Ini::read_ini( 'workflow.ini' );
 74 
 75         // Just return the alphred bit
 76         return $ini['alphred'];
 77 
 78     }
 79 
 80     /**
 81      * Execute a php script in the background
 82      *
 83      * @todo Work on argument escaping
 84      *
 85      * @param  string  $script path to php script
 86      * @param  mixed     $args   args to pass to the script
 87      */
 88     public function background( $script, $args = false ) {
 89         // Make sure that the script
 90         if ( ! file_exists( $script ) ) {
 91             // File does not exist, so throw an exception
 92             throw new Alphred\FileDoesNotExist( "Script `{$script}` does not exist.", 4 );
 93         }
 94         if ( $args ) {
 95             if ( is_array( $args ) ) {
 96                 // Turn $args into a string if we were passed an array
 97                 $args = implode( "' '", $args );
 98                 // prepend and append the extra quotation marks... everything *should* be quoted now
 99                 $args = "'{$args}'";
100             } else {
101                 // Quote args if it is a string
102                 $args = "'{$args}'";
103             }
104             // Let's escape double-quotes
105             $args = str_replace( '"', '\"', $args );
106         }
107         // Set a variable to let us know that we're in the background, and execute the script
108         exec( "ALPHRED_IN_BACKGROUND=1 /usr/bin/nohup php '{$script}' {$args}  >/dev/null 2>&1 &", $output, $return );
109     }
110 
111     /**
112      * Tells you whether or not a script is running in the background
113      *
114      * @since 1.0.0
115      *
116      * @return boolean true if in the background; false if not
117      */
118     public function is_background() {
119         return Alphred\Globals::is_background();
120     }
121 
122     /**
123      * Calls an Alfred External Trigger
124      *
125      * Single and double-quotes in the argument might break this method, so make sure that you
126      * escape them appropriately.
127      *
128      * @since 1.0.0
129      * @uses Alphred\Alfred::call_external_trigger()
130      *
131      * @param  string               $bundle   the bundle id of the workflow to trigger
132      * @param  string               $trigger  the name of the trigger
133      * @param  string|boolean $argument an argument to pass
134      */
135     public function call_external_trigger( $bundle, $trigger, $argument = false ) {
136         Alphred\Alfred::call_external_trigger( $bundle, $trigger, $argument );
137     }
138 
139     /**
140      * Tells you if the current theme is `light` or `dark`
141      *
142      * @uses Alphred\Alfred::light_or_dark()
143      * @return string either 'light' or 'dark'
144      */
145     public function theme_background() {
146         return Alphred\Alfred::light_or_dark();
147     }
148 
149 
150     /**
151      * Filters an array based on a query
152      *
153      * Passing an empty query ($needle) to this method will simply return the initial array.
154      * If you have `fold` on, then this will fail on characters that cannot be translitered
155      * into regular ASCII, so most Asian languages.
156      *
157      * The options to be set are:
158      *  * max_results  -- the maximum number of results to return (default: false)
159      *  * min_score    -- the minimum score to return (0-100) (default: false)
160      *  * return_score -- whether or not to return the score along with the results (default: false)
161      *  * fold         -- whether or not to fold diacritical marks, thus making
162      *                                      `über` into `uber`. (default: true)
163      *  * match_type     -- the type of filters to run. (default: MATCH_ALL)
164      *
165      *  The match_type is defined as constants, and so you can call them by the flags or by
166      *  the integer value. Options:
167      *    Match items that start with the query
168      *    1: MATCH_STARTSWITH
169      *    Match items whose capital letters start with ``query``
170      *    2: MATCH_CAPITALS
171      *    Match items with a component "word" that matches ``query``
172      *    4: MATCH_ATOM
173      *    Match items whose initials (based on atoms) start with ``query``
174      *    8: MATCH_INITIALS_STARTSWITH
175      *    Match items whose initials (based on atoms) contain ``query``
176      *    16: MATCH_INITIALS_CONTAIN
177      *    Combination of MATCH_INITIALS_STARTSWITH and MATCH_INITIALS_CONTAIN
178      *    24: MATCH_INITIALS
179      *    Match items if ``query`` is a substring
180      *    32: MATCH_SUBSTRING
181      *    Match items if all characters in ``query`` appear in the item in order
182      *    64: MATCH_ALLCHARS
183      *    Combination of all other ``MATCH_*`` constants
184      *    127: MATCH_ALL
185      *
186      * @param  array                $haystack the array of items to filter
187      * @param  string               $needle   the search query to filter against
188      * @param  string|boolean $key      the name of the key to filter on if array is associative
189      * @param  array                    $options  a list of options to configure the filter
190      * @return array          an array of filtered items
191      */
192     public function filter( $haystack, $needle, $key = false, $options = [] ) {
193         return Alphred\Filter::Filter( $haystack, $needle, $key, $options );
194     }
195 
196 
197 
198     /*****************************************************************************
199      * Wrapper methods for script filters
200      ****************************************************************************/
201 
202     /**
203      * Adds a result to the script filter
204      *
205      * @since 1.0.0
206      *
207      * @param array $item an array of values to parse that construct an Alphred\Result object
208      */
209     public function add_result( $item ) {
210         return $this->filter->add_result( new \Alphred\Result( $item ) );
211     }
212 
213     /**
214      * Prints the script filter XML
215      *
216      * @since 1.0.0
217      *
218      * @return mixed
219      */
220     public function to_xml() {
221         $this->filter->to_xml();
222     }
223 
224     /*****************************************************************************
225      * Wrapper methods for requests ( GET / POST )
226      ****************************************************************************/
227 
228     /**
229      * Makes a `GET` Request
230      *
231      * This method is good for simple `GET` requests. By default, requests are cached for
232      * 600 seconds (ten minutes), and all options are passed via the `$options` array. Here
233      * are the options:
234      *  params     (array as $key => $value)
235      *  auth       (array as [ username, password ] )
236      *  user_agent (string)
237      *  headers    (array as list of headers to add)
238      *
239      * Set only the options that you need.
240      *
241      * To turn caching off, just set `$cache_ttl` to 0.
242      *
243      * The `$cache_bin` is the subfolder within the workflow's cache folder. If set to `true`,
244      * then the cache bin will be named after the hostname of the URL. So, if you are requesting
245      * something from `http://api.github.com/v3/shawnrice/repos`, the `cache bin` would be
246      * `api.github.com`. If you were requesting `http://www.google.com`, then the `cache bin`
247      * would be `www.google.com`.
248      *
249      * @uses Alphred\Request
250      *
251      * @param  string               $url       the URL
252      * @param  array|boolean  $options   an array of options for the request
253      * @param  integer              $cache_ttl cache time to live in seconds
254      * @param  string|boolean $cache_bin cache bin
255      * @return string         the results
256      */
257     public function get( $url, $options = false, $cache_ttl = 600, $cache_bin = true ) {
258         $request = $this->create_request( $url, $options, $cache_ttl, $cache_bin, 'get' );
259         return $request->execute();
260     }
261 
262     /**
263      * Makes a `POST` request
264      *
265      * @see Alphred::get() See `get()` for details. The method is basically the same.
266      *
267      * @uses Alphred\Request
268      *
269      * @param  string               $url       [description]
270      * @param  array|boolean  $options   an array of options for the request
271      * @param  integer              $cache_ttl cache time to live in seconds
272      * @param  string|boolean $cache_bin cache bin
273      * @return string         the results
274      */
275     public function post( $url, $options = false, $cache_ttl = 600, $cache_bin = true ) {
276         $request = $this->create_request( $url, $options, $cache_ttl, $cache_bin, 'post' );
277         return $request->execute();
278     }
279 
280     /**
281      * Creates a request object
282      *
283      * @param  string               $url       the URL
284      * @param  array|boolean  $options   an array of options for the request
285      * @param  integer              $cache_ttl cache time to live in seconds
286      * @param  string|boolean $cache_bin cache bin
287      * @param  string               $type      either `get` or `post`
288      * @return Alphred\Request           the request object
289      */
290     private function create_request( $url, $options, $cache_ttl, $cache_bin, $type ) {
291 
292         if ( $cache_ttl > 0 ) {
293             // Create an object with caching on
294             $request = new Alphred\Request( $url, [ 'cache' => true,
295                                                             'cache_ttl' => $cache_ttl,
296                                                             'cache_bin' => $cache_bin ] );
297         } else {
298             // Create an object with caching off
299             $request = new Alphred\Request( $url, [ 'cache' => false ] );
300         }
301         // Set it to `POST` if that's what they want
302         if ( 'post' == $type ) {
303             $request->use_post();
304         }
305         // If there are options, then go through them and set everything
306         if ( $options ) {
307             if ( isset( $options['params'] ) ) {
308                 if ( ! is_array( $options['params'] ) ) {
309                     throw new Alphred\Exception( 'Parameters must be passed as an array', 4 );
310                 }
311                 // Add the parameters
312                 $request->add_parameters( $options['params'] );
313             }
314             // For basic http authentication
315             if ( isset( $options['auth'] ) ) {
316                 // Make sure that there are two options in the auth array
317                 if ( ! is_array( $options['auth'] ) || ( 2 !== count( $options['auth'] ) ) ) {
318                     throw new Alphred\Exception( 'You need two arguments in the auth array.', 4 );
319                 }
320                 // Set the options
321                 $request->set_auth( $options['auth'][0], $options['auth'][1] );
322             }
323             // If we need a user agent
324             if ( isset( $options['user_agent'] ) ) {
325                 // Make sure that the user agent is a string
326                 if ( ! is_string( $options['user_agent'] ) ) {
327                     // It's not, so throw an exception
328                     throw new Alphred\Exception( 'The user agent must be a string', 4 );
329                 }
330                 // Set the user agent
331                 $request->set_user_agent( $options['user_agent'] );
332             }
333             // If we need to add headers
334             if ( isset( $options['headers'] ) ) {
335                 if ( ! is_array( $options['headers'] ) ) {
336                     throw new Alphred\Exception( 'Headers must be passed as an array', 4 );
337                 } else {
338                     $request->set_headers( $options['headers'] );
339                 }
340             }
341         }
342         return $request;
343     }
344 
345     /**
346      * Clears a cache bin
347      *
348      * Clears a cache bin. If you send it with no argument (i.e.: `$bin = false`), then
349      * it will attempt to clear the workflow's cache directory. Note: this will throw an
350      * exception if it encounters a sub-directory. While it would be easy to make this
351      * function clear sub-directories, it shouldn't. If you are storing data other than responses
352      * in your cache directory, then use a cache-bin with the requests.
353      *
354      * @since 1.0.0
355      * @throws Alphred\Exception when encountering a sub-directory
356      * @uses Alphred\Request::clear_cache()
357      *
358      * @param  string|boolean $bin the cache bin to clear
359      * @return null
360      */
361     public function clear_cache( $bin = false ) {
362         return Alphred\Request::clear_cache( $bin );
363     }
364 
365 
366     /*****************************************************************************
367      * Config functionality
368      ****************************************************************************/
369 
370     /**
371      * Reads a configuration value
372      *
373      * @param  string $key      name of key
374      * @return mixed            the value of the key or null if not set
375      */
376     public function config_read( $key ) {
377         try {
378             // Try to read it, and catch the exception if it is not set
379             return $this->config->read( $key );
380         } catch ( Alphred\ConfigKeyNotSet $e ) {
381             // There is nothing, so return null
382             return null;
383         }
384     }
385 
386     /**
387      * Sets a configuration value
388      *
389      * @param  string  $key      the name of the key
390      * @param  mixed   $value    the value for the key
391      */
392     public function config_set( $key, $value ) {
393         $this->config->set( $key, $value );
394     }
395 
396     /**
397      * Deletes a config value
398      *
399      * @param  string  $key      name of the key
400      */
401     public function config_delete( $key ) {
402         $this->config->delete( $key );
403     }
404 
405     /**
406      * Sends a system notification
407      *
408      * Use this for async notifications or when running code in the background. If you want
409      * regular "end-of-workflow" notifications, then use Alfred's built-in set.
410      *
411      * Since this uses AppleScript notifications, all of them will, unfortunately, have the
412      * icon for Script Editor in them, and this is not replaceable. If you want more control
413      * over your notifications, then use something like CocoaDialog or Terminal-Notifier.
414      *
415      * @since 1.0.0
416      * @uses Alphred\Notification::notify()
417      * @todo Check that return value is correct
418      * @see Alphred\Notification::notify() For more information on how to call with the correct options.
419      *
420      * @param  array $options   the list of options to construct the notification
421      * @return boolean          success
422      */
423     public function send_notification( $options ) {
424         return \Alphred\Notification::notify( $options );
425     }
426 
427 
428     /*****************************************************************************
429      * Keychain Wrapper functions
430      ****************************************************************************/
431 
432     /**
433      * Gets a password from the keychain
434      *
435      * @uses \Alphred\Keychain::find_password()
436      *
437      * @param  string  $account the name of the account (key) for the password
438      * @return string|boolean   the password or false if not found
439      */
440     public function get_password( $account ) {
441         // \Alphred\Keychain::find_password throws an exception when the password does not
442         // exist. This wrapper returns false if the password has not been found.
443         try {
444             return \Alphred\Keychain::find_password( $account, null );
445         } catch ( \Alphred\PasswordNotFound $e ) {
446             \Alphred\Log::console( "No password for account `{$account}` was found. Returning false.", 2 );
447             return false;
448         }
449     }
450 
451     /**
452      * Deletes a password from the keychain
453      *
454      * @uses \Alphred\Keychain::delete_password()
455      *
456      * @param  string  $account the name of the account (key) for the password
457      * @return boolean          true if it existed and was deleted, false if it didn't exist
458      */
459     public function delete_password( $account ) {
460         return \Alphred\Keychain::delete_password( $account, null );
461     }
462 
463     /**
464      * Saves a password to the keychain
465      *
466      * @uses \Alphred\Keychain::save_password()
467      *
468      * @param  string  $account  the name of the account (key) for the password
469      * @param  string  $password the password
470      * @return boolean
471      */
472     public function save_password( $account, $password ) {
473         return \Alphred\Keychain::save_password( $account, $password, true, null );
474     }
475 
476     /**
477      * Creates an AppleScript dialog to enter a password securely
478      *
479      * Note: this will return 'canceled' if the user presses the 'cancel' button
480      *
481      * @uses Alphred\Dialog
482      *
483      * @param  string|boolean $text         the text for the dialog
484      * @param  string|boolean $title        the title of the dialog; defaults to the workflow name
485      * @param  string|boolean $icon         An icon to use with the dialog box
486      * @return string         the result of the user-input
487      */
488     public function get_password_dialog( $text = false, $title = false, $icon = false ) {
489         // Set the default text
490         if ( ! $text ) {
491             $text = 'Please enter the password.';
492         }
493         // Set the default title to be that of the workflow's name
494         if ( ! $title ) {
495             $title = \Alphred\Globals::get( 'alfred_workflow_name' );
496         }
497         // Create hidden answer AppleScript dialog
498         $dialog = new \Alphred\Dialog([
499           'text' => $text,
500           'title' => $title,
501           'default_answer' => '',
502           'hidden_answer' => true
503         ]);
504         // If there was an icon, then set it
505         if ( $icon ) {
506             $dialog->set_icon( $icon );
507         }
508         // Execute the dialog and return the result
509         return $dialog->execute();
510     }
511 
512     /*****************************************************************************
513      * Logging Functions
514      ****************************************************************************/
515 
516     /**
517      * Sends a log message to the console
518      *
519      * If the log level is set higher than the level that this function is called with,
520      * then nothing will happen.
521      *
522      * @see \Alphred\Log::console() More information on the console log
523      * @uses \Alphred\Log
524      *
525      * @param  string                   $message the message to log
526      * @param  string|integer   $level   the log level
527      * @param  integer|boolean  $trace   how far to go in the stacktrace. Defaults to the last level.
528      * @return mixed            default returns nothing
529      */
530     public function console( $message, $level = 'INFO', $trace = false ) {
531         \Alphred\Log::console( $message, $level, $trace );
532     }
533 
534 
535     /**
536      * Writes a log message to a log file
537      *
538      * @see \Alphred\Log::file() More information on the file log
539      * @uses \Alphred\Log
540      *
541      * @param  string        $message  message to log
542      * @param  string|int  $level    log level
543      * @param  string        $filename filename with no extension
544      * @param  boolean|int $trace    how far back to trace
545      */
546     public function log( $message, $level = 'INFO', $filename = 'workflow', $trace = false ) {
547         \Alphred\Log::file( $message, $level, $filename, $trace );
548     }
549 
550     /*****************************************************************************
551      * Text Processing Filters
552      ****************************************************************************/
553 
554     /**
555      * Takes a unix epoch time and renders it as a string
556      *
557      * This also works for future times. If you set `$words` to `true`, then you will
558      * get "one" instead of "1". Past times are appended with "ago"; future times are
559      * prepended with "in ".
560      *
561      * @param  integer  $seconds unix epoch time value
562      * @param  boolean $words    whether to use words or numerals
563      * @return string
564      */
565     public function time_ago( $seconds, $words = false ) {
566         return Alphred\Date::ago( $seconds, $words );
567     }
568 
569     /**
570      * Takes a time and gives you a fuzzy description of when it is/was relative to now
571      *
572      * So, something like "5 days, 16 hours, and 34 minutes ago" turns into "almost a week ago";
573      * Something like "16 hours from now" turns into "yesterday"; and something like "1 month from now"
574      * turns into "in a month"; it's fuzzy. Also, the first strings need to be a unix epoch time,
575      * so the number of seconds since 1 Jan, 1970 12:00AM.
576      *
577      * @param  int $seconds    a unix epoch time
578      * @return string          a string that represents an approximate time
579      */
580     public function fuzzy_time_diff( $seconds ) {
581         return Alphred\Date::fuzzy_ago( $seconds );
582     }
583 
584     /**
585      * Implodes an array into a string with commas (uses an Oxford comma)
586      *
587      * If you set `$suffix` to `true`, then the function expects an associative array
588      * as 'suffix' => 'word', so an array like:
589      * ````php
590      * $list = [ 'penny' => 'one', 'quarters' => 'three', 'dollars' => 'five' ];
591      * ````
592      * will render as: "one penny, three quarters, and five dollars"
593      *
594      * @param array   $list    the array to add commas to
595      * @param boolean $suffix whether or not there is a suffix
596      * @return string               the array, but as a string with commas
597      */
598     public function add_commas( $list, $suffix = false ) {
599         return \Alphred\Text::add_commas_to_list( $list, $suffix );
600     }
601 
602     /*****************************************************************************
603      * AppleScript Actions
604      ****************************************************************************/
605 
606     /**
607      * Activates an application
608      *
609      * Brings an application to the front, launching it if necessary
610      *
611      * @param  string $application the name of the application
612      */
613     public function activate( $application ) {
614         Alphred\AppleScript::activate( $application );
615     }
616 
617     /**
618      * Gets the active window
619      *
620      * @return array an array of [ 'app_name' => $name, 'window_name' => $name ]
621      */
622     public function get_active_window() {
623         return Alphred\AppleScript::get_front();
624     }
625 
626     /**
627      * Brings an application to the front
628      *
629      * This is like `activate`, but it does not open the application if it is
630      * not already open.
631      *
632      * @param  string $application the name of an application
633      */
634     public function bring_to_front( $application ) {
635         Alphred\AppleScript::bring_to_front( $application );
636     }
637 
638 
639 
640 }
Alphred API documentation generated by ApiGen