Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

With config functionality added. #9011

Conversation

mfendeksilverstripe
Copy link
Contributor

@mfendeksilverstripe mfendeksilverstripe commented May 26, 2019

New feature:

  • withConfig - a callback that allows to safely manipulate configuration
  • very useful for unit tests which use data providers

Example use (unit test):

/**
 * @dataProvider testValuesProvider
 * @param string $value
 * @param string $expected
 */
public function testConfigValues(string $value, string $expected)
{
    $result = Config::withConfig(function(MutableConfigCollectionInterface $config) use ($value): string {
        // update your config
        $config->set(MyService::class, 'some_setting', $value);

        // your test code goes here
        return MyService::singleton()->executeSomeFunction();
    });

    $this->assertEquals($expected, $result);
}

public function testValuesProvider(): array
{
    return [
        ['test value 1', 'expected value 1'],
        ['test value 2', 'expected value 2'],
        ['test value 3', 'expected value 3'],
    ];
}

$config = static::modify();

try {
return $callback($config);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be using return call_user_func($callback, $config) to support more ways of providing a valid callback, e.g. an array of class & method pair?

Copy link
Contributor

@robbieaverill robbieaverill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a stylistic comment. I'm not entirely convinced that this feature is worth having in core, to be honest, but happy to leave it open to see what the others in the core team think =) Thanks for the PR!

$config = static::modify();

try {
return call_user_func($callback, $config);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on $callback($config) instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It used to be that at the beginning of the PR and I suggested to use the call_user_func notation (as above). Then I checked the $callback variable support in the docs and found it's just fine.
Sorry for the hassle @mfendeksilverstripe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for feedback. It's now back to $callback($config)

Copy link
Contributor

@dnsl48 dnsl48 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.
I think that's worth having in terms of the config API around nesting.

I believe this wrapper should also be considered to be a best practice and that we should recommend its use over nesting configs manually. Some other languages even have built-in syntax sugar specifically for with context implementations.

@robbieaverill
Copy link
Contributor

I believe this wrapper should also be considered to be a best practice and that we should recommend its use over nesting configs manually

Yeah, the issue I have with this PR is that the config manifest automatically nests itself when you modify it, and SapphireTest automatically nests and unnests it for each test, so if we're talking about unit testing context I don't really see why this is useful. If you're doing more than one thing in a unit test I can see this being useful, but that is probably something we should discourage anyway.

@dnsl48
Copy link
Contributor

dnsl48 commented Oct 10, 2019

SapphireTest automatically nests and unnests it for each test

Agree, for that particular use case it may not be really necessary. Though, that's rather specific for SapphireTest deriving functional tests. When I think about the Config class APIs in a more general way, then I see the value in having the method for covering some low-level edgy use cases.

Copy link
Contributor

@robbieaverill robbieaverill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'm convinced 😄one piece of feedback

src/Core/Config/Config.php Show resolved Hide resolved
@mfendeksilverstripe
Copy link
Contributor Author

@robbieaverill Updated based on your suggestions.

Copy link
Contributor

@robbieaverill robbieaverill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Anyone from @silverstripe/core-team want to take quick look, since we're introducing a new API?

@ScopeyNZ
Copy link
Contributor

Agree, for that particular use case it may not be really necessary. Though, that's rather specific for SapphireTest deriving functional tests. When I think about the Config class APIs in a more general way, then I see the value in having the method for covering some low-level edgy use cases.

I personally think that if you're modifying config outside of a testing environment then it's not really config. Given the automated nesting for functional tests - I'm not really sure of its use.

In saying that I don't have any strong opposing opinions to this API and it seems like a good implementation.

@maxime-rainville
Copy link
Contributor

Can't say I ever recall coming across a situation where this would have been helpful. But I don't feel like it adds any significant complexity, so I'm OK with it being merged in.

@mfendeksilverstripe
Copy link
Contributor Author

mfendeksilverstripe commented Oct 11, 2019

@maxime-rainville We found this useful for several unit tests, but I think there are some cases outside of unit tests too. For example this one:

https://github.com/symbiote/silverstripe-queuedjobs/blob/master/src/Services/QueuedJobService.php#L749

In this instance not using callback makes writing unit tests for this code quite challenging. As unit test may effect each other.

btw we also have another callback function which we use in unit tests:

public static function withEnvironment(array $values, callable $callback)
{
    $originalValues = [];
    foreach ($values as $key => $value) {
        if (strlen($key) === 0) {
            continue;
        }

        $originalValues[$key] = Environment::getEnv($key);
    }

    try {
        foreach ($values as $key => $value) {
            if (strlen($key) === 0) {
                continue;
            }

            Environment::setEnv($key, $value);
        }

        return $callback();
    } finally {
        foreach ($originalValues as $key => $value) {
            if (strlen($key) === 0) {
                continue;
            }

            Environment::setEnv($key, $value);
        }
    }
}

You can take this one too :D

Such callback functions are really handy in unit tests if you use dataProviders

Copy link
Contributor

@maxime-rainville maxime-rainville left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a bit of doc for this new feature.

I'm thinking this page seems like the natural place to add it https://docs.silverstripe.org/en/4/developer_guides/configuration/configuration/

@mfendeksilverstripe
Copy link
Contributor Author

@maxime-rainville I added an example use to the pull request description as I don't have access to update the docs.

@kinglozzer
Copy link
Member

kinglozzer commented Oct 30, 2019

@mfendeksilverstripe The docs are pulled from the docs/ directory in this repo, so you can add to the docs by editing this file as part of this PR: https://github.com/silverstripe/silverstripe-framework/blob/4/docs/en/02_Developer_Guides/04_Configuration/00_Configuration.md

@mfendeksilverstripe mfendeksilverstripe force-pushed the feature/with-config-rebase branch from 1a8dc51 to d5549c9 Compare October 30, 2019 20:05
@mfendeksilverstripe
Copy link
Contributor Author

@maxime-rainville Readme updated.

Copy link
Contributor

@maxime-rainville maxime-rainville left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've suggested some minor rewording to make some sentences a bit simpler. Apply at your discretion.

I'm happy for this to be merge.

@mfendeksilverstripe
Copy link
Contributor Author

@maxime-rainville All good, thanks :)

@maxime-rainville
Copy link
Contributor

I'll merge on green.

@maxime-rainville maxime-rainville merged commit e2bea6b into silverstripe:4 Oct 31, 2019
@@ -376,6 +376,48 @@ When you have more than one rule for a nested fragment, they're joined like
That is, the fragment will be included if all Only rules match, except if all Except rules match.
</div>

## Unit tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for documenting this so well @mfendeksilverstripe, great addition! :)

@Cheddam Cheddam deleted the feature/with-config-rebase branch December 11, 2019 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants