1<?php 2namespace Aws; 3 4use GuzzleHttp\Promise; 5 6/** 7 * A configuration provider is a function that returns a promise that is 8 * fulfilled with a configuration object. This class provides base functionality 9 * usable by specific configuration provider implementations 10 */ 11abstract class AbstractConfigurationProvider 12{ 13 const ENV_PROFILE = 'AWS_PROFILE'; 14 const ENV_CONFIG_FILE = 'AWS_CONFIG_FILE'; 15 16 public static $cacheKey; 17 18 protected static $interfaceClass; 19 protected static $exceptionClass; 20 21 /** 22 * Wraps a config provider and saves provided configuration in an 23 * instance of Aws\CacheInterface. Forwards calls when no config found 24 * in cache and updates cache with the results. 25 * 26 * @param callable $provider Configuration provider function to wrap 27 * @param CacheInterface $cache Cache to store configuration 28 * @param string|null $cacheKey (optional) Cache key to use 29 * 30 * @return callable 31 */ 32 public static function cache( 33 callable $provider, 34 CacheInterface $cache, 35 $cacheKey = null 36 ) { 37 $cacheKey = $cacheKey ?: static::$cacheKey; 38 39 return function () use ($provider, $cache, $cacheKey) { 40 $found = $cache->get($cacheKey); 41 if ($found instanceof static::$interfaceClass) { 42 return Promise\promise_for($found); 43 } 44 45 return $provider() 46 ->then(function ($config) use ( 47 $cache, 48 $cacheKey 49 ) { 50 $cache->set($cacheKey, $config); 51 return $config; 52 }); 53 }; 54 } 55 56 /** 57 * Creates an aggregate configuration provider that invokes the provided 58 * variadic providers one after the other until a provider returns 59 * configuration. 60 * 61 * @return callable 62 */ 63 public static function chain() 64 { 65 $links = func_get_args(); 66 if (empty($links)) { 67 throw new \InvalidArgumentException('No providers in chain'); 68 } 69 70 return function () use ($links) { 71 /** @var callable $parent */ 72 $parent = array_shift($links); 73 $promise = $parent(); 74 while ($next = array_shift($links)) { 75 $promise = $promise->otherwise($next); 76 } 77 return $promise; 78 }; 79 } 80 81 /** 82 * Gets the environment's HOME directory if available. 83 * 84 * @return null|string 85 */ 86 protected static function getHomeDir() 87 { 88 // On Linux/Unix-like systems, use the HOME environment variable 89 if ($homeDir = getenv('HOME')) { 90 return $homeDir; 91 } 92 93 // Get the HOMEDRIVE and HOMEPATH values for Windows hosts 94 $homeDrive = getenv('HOMEDRIVE'); 95 $homePath = getenv('HOMEPATH'); 96 97 return ($homeDrive && $homePath) ? $homeDrive . $homePath : null; 98 } 99 100 /** 101 * Gets default config file location from environment, falling back to aws 102 * default location 103 * 104 * @return string 105 */ 106 protected static function getDefaultConfigFilename() 107 { 108 if ($filename = getenv(self::ENV_CONFIG_FILE)) { 109 return $filename; 110 } 111 return self::getHomeDir() . '/.aws/config'; 112 } 113 114 /** 115 * Wraps a config provider and caches previously provided configuration. 116 * 117 * @param callable $provider Config provider function to wrap. 118 * 119 * @return callable 120 */ 121 public static function memoize(callable $provider) 122 { 123 return function () use ($provider) { 124 static $result; 125 static $isConstant; 126 127 // Constant config will be returned constantly. 128 if ($isConstant) { 129 return $result; 130 } 131 132 // Create the initial promise that will be used as the cached value 133 if (null === $result) { 134 $result = $provider(); 135 } 136 137 // Return config and set flag that provider is already set 138 return $result 139 ->then(function ($config) use (&$isConstant) { 140 $isConstant = true; 141 return $config; 142 }); 143 }; 144 } 145 146 /** 147 * Reject promise with standardized exception. 148 * 149 * @param $msg 150 * @return Promise\RejectedPromise 151 */ 152 protected static function reject($msg) 153 { 154 $exceptionClass = static::$exceptionClass; 155 return new Promise\RejectedPromise(new $exceptionClass($msg)); 156 } 157} 158