View more context

 

jakx

@theruss I'm hoping to hook into the AWS CredentialProvider::memoize() helper method, while configuring my clients with the injector config

theruss

This? https://github.com/aws/aws-sdk-php/blob/master/src/Credentials/CredentialProvider.php

Show 1 attachment(s)
src/Credentials/CredentialProvider.php


<?php
namespace Aws\Credentials;

use Aws;
use Aws\Api\DateTimeResult;
use Aws\CacheInterface;
use Aws\Exception\CredentialsException;
use Aws\Sts\StsClient;
use GuzzleHttp\Promise;

/**
 * Credential providers are functions that accept no arguments and return a
 * promise that is fulfilled with an {@see \Aws\Credentials\CredentialsInterface}
 * or rejected with an {@see \Aws\Exception\CredentialsException}.
 *
 * <code>
 * use Aws\Credentials\CredentialProvider;
 * $provider = CredentialProvider::defaultProvider();
 * // Returns a CredentialsInterface or throws.
 * $creds = $provider()->wait();
 * </code>
 *
 * Credential providers can be composed to create credentials using conditional
 * logic that can create different credentials in different environments. You
 * can compose multiple providers into a single provider using
 * {@see Aws\Credentials\CredentialProvider::chain}. This function accepts
 * providers as variadic arguments and returns a new function that will invoke
 * each provider until a successful set of credentials is returned.
 *
 * <code>
 * // First try an INI file at this location.
 * $a = CredentialProvider::ini(null, '/path/to/file.ini');
 * // Then try an INI file at this location.
 * $b = CredentialProvider::ini(null, '/path/to/other-file.ini');
 * // Then try loading from environment variables.
 * $c = CredentialProvider::env();
 * // Combine the three providers together.
 * $composed = CredentialProvider::chain($a, $b, $c);
 * // Returns a promise that is fulfilled with credentials or throws.
 * $promise = $composed();
 * // Wait on the credentials to resolve.
 * $creds = $promise->wait();
 * </code>
 */
class CredentialProvider
{
    const ENV_ARN = 'AWS_ROLE_ARN';
    const ENV_KEY = 'AWS_ACCESS_KEY_ID';
    const ENV_PROFILE = 'AWS_PROFILE';
    const ENV_ROLE_SESSION_NAME = 'AWS_ROLE_SESSION_NAME';
    const ENV_SECRET = 'AWS_SECRET_ACCESS_KEY';
    const ENV_SESSION = 'AWS_SESSION_TOKEN';
    const ENV_TOKEN_FILE = 'AWS_WEB_IDENTITY_TOKEN_FILE';

    /**
     * Create a default credential provider that first checks for environment
     * variables, then checks for the "default" profile in ~/.aws/credentials,
     * then checks for "profile default" profile in ~/.aws/config (which is
     * the default profile of AWS CLI), then tries to make a GET Request to
     * fetch credentials if Ecs environment variable is presented, then checks
     * for credential_process in the "default" profile in ~/.aws/credentials,
     * then for credential_process in the "default profile" profile in
     * ~/.aws/config, and finally checks for EC2 instance profile credentials.
     *
     * This provider is automatically wrapped in a memoize function that caches
     * previously provided credentials.
     *
     * @param array $config Optional array of ecs/instance profile credentials
     *                      provider options.
     *
     * @return callable
     */
    public static function defaultProvider(array $config = [])
    {
        $cacheable = [
            'web_identity',
            'ecs',
            'process_credentials',
            'process_config',
            'instance'
        ];

        $defaultChain = [
            'env' => self::env(),
            'web_identity' => self::assumeRoleWithWebIdentityCredentialProvider(),
            'ini' => self::ini(),
            'ini_config' => self::ini('profile default', self::getHomeDir() . '/.aws/config'),
        ];

        if (!empty(getenv(EcsCredentialProvider::ENV_URI))) {
            $defaultChain['ecs'] = self::ecsCredentials($config);
        }
        $defaultChain['process_credentials'] = self::process();
        $defaultChain['process_config'] = self::process(
            'profile default',
            self::getHomeDir() . '/.aws/config'
        );
        $defaultChain['instance'] = self::instanceProfile($config);

        if (isset($config['credentials'])
            && $config['credentials'] instanceof CacheInterface
        ) {
            foreach ($cacheable as $provider) {
                if (isset($defaultChain[$provider])) {
                    $defaultChain[$provider] = self::cache(
                        $defaultChain[$provider],
                        $config['credentials'],
                        'aws_cached_' . $provider . '_credentials'
                    );
                };
            }
        }

        return self::memoize(
            call_user_func_array(
                'self::chain',
                $defaultChain
            )
        );
    }

    /**
     * Create a credential provider function from a set of static credentials.
     *
     * @param CredentialsInterface $creds
     *
     * @return callable
     */
    public static function fromCredentials(CredentialsInterface $creds)
    {
        $promise = Promise\promise_for($creds);

        return function () use ($promise) {
            return $promise;
        };
    }

    /**
     * Creates an aggregate credentials provider that invokes the provided
     * variadic providers one after the other until a provider returns
     * credentials.
     *
     * @return callable
     */
    public static function chain()
    {
        $links = func_get_args();
        if (empty($links)) {
            throw new \InvalidArgumentException('No providers in chain');
        }

        return function () use ($links) {
            /** @var callable $parent */
            $parent = array_shift($links);
            $promise = $parent();
            while ($next = array_shift($links)) {
                $promise = $promise->otherwise($next);
            }
            return $promise;
        };
    }

    /**
     * Wraps a credential provider and caches previously provided credentials.
     *
     * Ensures that cached credentials are refreshed when they expire.
     *
     * @param callable $provider Credentials provider function to wrap.
     *
     * @return callable
     */
    public static function memoize(callable $provider)
    {
        return function () use ($provider) {
            static $result;
            static $isConstant;

            // Constant credentials will be returned constantly.
            if ($isConstant) {
                return $result;
            }

            // Create the initial promise that will be used as the cached value
            // until it expires.
            if (null === $result) {
                $result = $provider();
            }

            // Return credentials that could expire and refresh when needed.
            return $result
                ->then(function (CredentialsInterface $creds) use ($provider, &$isConstant, &$result) {
                    // Determine if these are constant credentials.
                    if (!$creds->getExpiration()) {
                        $isConstant = true;
                        return $creds;
                    }

                    // Refresh expired credentials.
                    if (!$creds->isExpired()) {
                        return $creds;
                    }
                    // Refresh the result and forward the promise.
                    return $result = $provider();
                })
                ->otherwise(function($reason) use (&$result) {
                    // Cleanup rejected promise.
                    $result = null;
                    return new Promise\RejectedPromise($reason);
                });
        };
    }

    /**
     * Wraps a credential provider and saves provided credentials in an
     * instance of Aws\CacheInterface. Forwards calls when no credentials found
     * in cache and updates cache with the results.
     *
     * Defaults to using a simple file-based cache when none provided.
     *
     * @param callable $provider Credentials provider function to wrap
     * @param CacheInterface $cache Cache to store credentials
     * @param string|null $cacheKey (opti…
Hide attachment content
theruss

Both defaultProvider() and memoize() itself are declared statically, so you can't use Injector in that way.

jakx

Yep, that's the one. And true, I wasn't aware static methods couldn't be used. Thanks @theruss

jakx

I might try something with a factory

theruss

TBH, I've never tried, precisely because the instantiation component of Injector itself, is exactly that - for instantiation, which you don't do statically in PHP (Indirectly you can via a static factory() method of course, but all that's doing is intantiating again...so you're kicking the can up the road so to speak)

jakx

https://github.com/aws/aws-sdk-php/blob/master/src/Sdk.php is a factory that might do the trick. It doesn't have an explicit create method, but it seems to use __call() in a way that might catch it @theruss

Show 1 attachment(s)
src/Sdk.php


<?php
namespace Aws;

/**
 * Builds AWS clients based on configuration settings.
 *
 * @method \Aws\ACMPCA\ACMPCAClient createACMPCA(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionACMPCA(array $args = [])
 * @method \Aws\Acm\AcmClient createAcm(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAcm(array $args = [])
 * @method \Aws\AlexaForBusiness\AlexaForBusinessClient createAlexaForBusiness(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAlexaForBusiness(array $args = [])
 * @method \Aws\Amplify\AmplifyClient createAmplify(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAmplify(array $args = [])
 * @method \Aws\ApiGateway\ApiGatewayClient createApiGateway(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionApiGateway(array $args = [])
 * @method \Aws\ApiGatewayManagementApi\ApiGatewayManagementApiClient createApiGatewayManagementApi(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionApiGatewayManagementApi(array $args = [])
 * @method \Aws\ApiGatewayV2\ApiGatewayV2Client createApiGatewayV2(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionApiGatewayV2(array $args = [])
 * @method \Aws\AppMesh\AppMeshClient createAppMesh(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAppMesh(array $args = [])
 * @method \Aws\AppSync\AppSyncClient createAppSync(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAppSync(array $args = [])
 * @method \Aws\ApplicationAutoScaling\ApplicationAutoScalingClient createApplicationAutoScaling(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionApplicationAutoScaling(array $args = [])
 * @method \Aws\ApplicationDiscoveryService\ApplicationDiscoveryServiceClient createApplicationDiscoveryService(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionApplicationDiscoveryService(array $args = [])
 * @method \Aws\ApplicationInsights\ApplicationInsightsClient createApplicationInsights(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionApplicationInsights(array $args = [])
 * @method \Aws\Appstream\AppstreamClient createAppstream(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAppstream(array $args = [])
 * @method \Aws\Athena\AthenaClient createAthena(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAthena(array $args = [])
 * @method \Aws\AutoScaling\AutoScalingClient createAutoScaling(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAutoScaling(array $args = [])
 * @method \Aws\AutoScalingPlans\AutoScalingPlansClient createAutoScalingPlans(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionAutoScalingPlans(array $args = [])
 * @method \Aws\Backup\BackupClient createBackup(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionBackup(array $args = [])
 * @method \Aws\Batch\BatchClient createBatch(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionBatch(array $args = [])
 * @method \Aws\Budgets\BudgetsClient createBudgets(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionBudgets(array $args = [])
 * @method \Aws\Chime\ChimeClient createChime(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionChime(array $args = [])
 * @method \Aws\Cloud9\Cloud9Client createCloud9(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloud9(array $args = [])
 * @method \Aws\CloudDirectory\CloudDirectoryClient createCloudDirectory(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudDirectory(array $args = [])
 * @method \Aws\CloudFormation\CloudFormationClient createCloudFormation(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudFormation(array $args = [])
 * @method \Aws\CloudFront\CloudFrontClient createCloudFront(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudFront(array $args = [])
 * @method \Aws\CloudHSMV2\CloudHSMV2Client createCloudHSMV2(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudHSMV2(array $args = [])
 * @method \Aws\CloudHsm\CloudHsmClient createCloudHsm(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudHsm(array $args = [])
 * @method \Aws\CloudSearch\CloudSearchClient createCloudSearch(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudSearch(array $args = [])
 * @method \Aws\CloudSearchDomain\CloudSearchDomainClient createCloudSearchDomain(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudSearchDomain(array $args = [])
 * @method \Aws\CloudTrail\CloudTrailClient createCloudTrail(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudTrail(array $args = [])
 * @method \Aws\CloudWatch\CloudWatchClient createCloudWatch(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudWatch(array $args = [])
 * @method \Aws\CloudWatchEvents\CloudWatchEventsClient createCloudWatchEvents(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudWatchEvents(array $args = [])
 * @method \Aws\CloudWatchLogs\CloudWatchLogsClient createCloudWatchLogs(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCloudWatchLogs(array $args = [])
 * @method \Aws\CodeBuild\CodeBuildClient createCodeBuild(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCodeBuild(array $args = [])
 * @method \Aws\CodeCommit\CodeCommitClient createCodeCommit(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCodeCommit(array $args = [])
 * @method \Aws\CodeDeploy\CodeDeployClient createCodeDeploy(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCodeDeploy(array $args = [])
 * @method \Aws\CodePipeline\CodePipelineClient createCodePipeline(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCodePipeline(array $args = [])
 * @method \Aws\CodeStar\CodeStarClient createCodeStar(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCodeStar(array $args = [])
 * @method \Aws\CognitoIdentity\CognitoIdentityClient createCognitoIdentity(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCognitoIdentity(array $args = [])
 * @method \Aws\CognitoIdentityProvider\CognitoIdentityProviderClient createCognitoIdentityProvider(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCognitoIdentityProvider(array $args = [])
 * @method \Aws\CognitoSync\CognitoSyncClient createCognitoSync(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCognitoSync(array $args = [])
 * @method \Aws\Comprehend\ComprehendClient createComprehend(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionComprehend(array $args = [])
 * @method \Aws\ComprehendMedical\ComprehendMedicalClient createComprehendMedical(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionComprehendMedical(array $args = [])
 * @method \Aws\ConfigService\ConfigServiceClient createConfigService(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionConfigService(array $args = [])
 * @method \Aws\Connect\ConnectClient createConnect(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionConnect(array $args = [])
 * @method \Aws\CostExplorer\CostExplorerClient createCostExplorer(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCostExplorer(array $args = [])
 * @method \Aws\CostandUsageReportService\CostandUsageReportServiceClient createCostandUsageReportService(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionCostandUsageReportService(array $args = [])
 * @method \Aws\DAX\DAXClient createDAX(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionDAX(array $args = [])
 * @method \Aws\DLM\DLMClient createDLM(array $args = [])
 * @method \Aws\MultiRegionClient createMultiRegionDLM(array $…
Hide attachment content
theruss

So there you could prolly use a custom SS factory to replace Injector's default, which then called (new Sdk())->createClient()

🙏 (1)

Show less replies
gs

I tried to add a silverstripe module by composer require but it keeps throwing a The requested package dnadesign/silverstripe-elemental (locked at 4.0.3, required as ^4.1.0) is satisfiable by dnadesign/silverstripe-elemental[4.0.3] but these conflict with your requirements or minimum-stability.

gs

what's the best practice here to resolve the conflict? update silverstripe-elemental to 4.1.0?

jakx

@gs either upgrade silverstripe-elemental or find an older version of the package you're requiring which supports an older silverstripe-elemental version

jakx

Also, if I knew what module you're installing, I feel like there could be an opportunity for a terrible "sounds like you're stuck between a block and a ..." pun

Nik

Would someone be able to explain how SilverStripe distinguishes between a field and a method when specifying things like summary fields? It works fine, I'm just curious about the under-the-hood implementation. I've had a look through the code, but seems like I'm missing some parts there.

thats4shaw

I haven’t been following what you are trying to achieve but that error is telling you that it can’t find the class that you are trying to extend from. You’ll need to add:

  1. use SilverStripe\CMS\Model\VirtualPage;

gs

@jakx I'm trying to install silverstripe-mimevalidator,

gs

It's throwing a conflict on both dnadesign/silverstripe-elemental and silverstripe/userforms