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

Skip AbstractProvider when generating provider list #107

Merged

Conversation

leafnode
Copy link
Contributor

@leafnode leafnode commented Jun 5, 2018

In some cases, when filesystem iterator returned AbstractProvider.php after USA.php, provider list generator returned AbstractProvider as the provider for USA, as abstract provider has the ID constant set to US (I'm unsure why it has this constant at all). The mechanism is simple: loop checks USA.php, adds 'US' => 'USA' to the array, then checks AbstractProvider, and overwrites the USA provider by adding 'US' => 'AbstractProvider' to the output.

To overcome this issue, I've expanded the condition checking if the class is a proper provider by checking if it's a subclass of AbstractProvider. That's why AbstractProvider won't be taken into consideration at all.

@stelgenhof
Copy link
Member

Thank you for your PR. Can you maybe share your code or an example where this issue appears? I tried to replicate it myself with the following simple script, but couldn't see any issue:

// Require the composer auto loader
require 'vendor/autoload.php';

$providers = Yasumi::getProviders();
ksort($providers);
print_r($providers);

Output:

Array
(
    [AT] => Austria
    [AU] => Australia
    [AU-VIC] => Australia/Victoria
    [BA] => Bosnia
    [BE] => Belgium
    [BR] => Brazil
    [CH] => Switzerland
    [CH-AG] => Switzerland/Aargau
    [CH-AI] => Switzerland/AppenzellInnerrhoden
    [CH-AR] => Switzerland/AppenzellAusserrhoden
    [CH-BE] => Switzerland/Bern
    [CH-BL] => Switzerland/BaselLandschaft
    [CH-BS] => Switzerland/BaselStadt
    [CH-FR] => Switzerland/Fribourg
    [CH-GE] => Switzerland/Geneva
    [CH-GL] => Switzerland/Glarus
    [CH-GR] => Switzerland/Grisons
    [CH-JU] => Switzerland/Jura
    [CH-LU] => Switzerland/Lucerne
    [CH-NE] => Switzerland/Neuchatel
    [CH-NW] => Switzerland/Nidwalden
    [CH-OW] => Switzerland/Obwalden
    [CH-SG] => Switzerland/StGallen
    [CH-SH] => Switzerland/Schaffhausen
    [CH-SO] => Switzerland/Solothurn
    [CH-SZ] => Switzerland/Schwyz
    [CH-TG] => Switzerland/Thurgau
    [CH-TI] => Switzerland/Ticino
    [CH-UR] => Switzerland/Uri
    [CH-VD] => Switzerland/Vaud
    [CH-VS] => Switzerland/Valais
    [CH-ZG] => Switzerland/Zug
    [CH-ZH] => Switzerland/Zurich
    [CZ] => CzechRepublic
    [DE] => Germany
    [DE-BB] => Germany/Brandenburg
    [DE-BE] => Germany/Berlin
    [DE-BW] => Germany/BadenWurttemberg
    [DE-BY] => Germany/Bavaria
    [DE-HB] => Germany/Bremen
    [DE-HE] => Germany/Hesse
    [DE-HH] => Germany/Hamburg
    [DE-MV] => Germany/MecklenburgWesternPomerania
    [DE-NI] => Germany/LowerSaxony
    [DE-NW] => Germany/NorthRhineWestphalia
    [DE-RP] => Germany/RhinelandPalatinate
    [DE-SH] => Germany/SchleswigHolstein
    [DE-SL] => Germany/Saarland
    [DE-SN] => Germany/Saxony
    [DE-ST] => Germany/SaxonyAnhalt
    [DE-TH] => Germany/Thuringia
    [DK] => Denmark
    [EE] => Estonia
    [ES] => Spain
    [ES-AN] => Spain/Andalusia
    [ES-AR] => Spain/Aragon
    [ES-AS] => Spain/Asturias
    [ES-CB] => Spain/Cantabria
    [ES-CE] => Spain/Ceuta
    [ES-CL] => Spain/CastileAndLeon
    [ES-CM] => Spain/CastillaLaMancha
    [ES-CN] => Spain/CanaryIslands
    [ES-CT] => Spain/Catalonia
    [ES-EX] => Spain/Extremadura
    [ES-GA] => Spain/Galicia
    [ES-IB] => Spain/BalearicIslands
    [ES-MC] => Spain/RegionOfMurcia
    [ES-MD] => Spain/CommunityOfMadrid
    [ES-ML] => Spain/Melilla
    [ES-NC] => Spain/Navarre
    [ES-PV] => Spain/BasqueCountry
    [ES-RI] => Spain/LaRioja
    [ES-VC] => Spain/ValencianCommunity
    [FI] => Finland
    [FR] => France
    [FR-57] => France/Moselle
    [FR-67] => France/BasRhin
    [FR-68] => France/HautRhin
    [GB] => UnitedKingdom
    [GR] => Greece
    [HR] => Croatia
    [HU] => Hungary
    [IE] => Ireland
    [IT] => Italy
    [JP] => Japan
    [LT] => Lithuania
    [LV] => Latvia
    [NL] => Netherlands
    [NO] => Norway
    [NZ] => NewZealand
    [PL] => Poland
    [PT] => Portugal
    [RO] => Romania
    [RU] => Russia
    [SE] => Sweden
    [SK] => Slovakia
    [UA] => Ukraine
    [US] => USA
    [ZA] => SouthAfrica
)

@leafnode
Copy link
Contributor Author

leafnode commented Jun 7, 2018

I was thinking about making a dedicated test for it, but it'd require quite a lot of refactoring. To replicate this bug, you'd have to replace filesystem iterators with a method call, and inject some mock here, that would return predefined file list.

But for the sake of example, I'd hardcode it into Yasumi. Let's hardcode normal file order into getProviders method:

//        $filesIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(
//            __DIR__ . $ds . 'Provider',
//            FilesystemIterator::SKIP_DOTS
//        ), RecursiveIteratorIterator::SELF_FIRST);

        $filesIterator = [
            new \SplFileInfo('/Users/leafnode/var/devel/yasumi/src/Yasumi/Provider/AbstractProvider.php'),
            new \SplFileInfo('/Users/leafnode/var/devel/yasumi/src/Yasumi/Provider/Belgium.php'),
            new \SplFileInfo('/Users/leafnode/var/devel/yasumi/src/Yasumi/Provider/USA.php'),
        ];

Now let's see what's inside the array that was returned:

        $providers = Yasumi::getProviders();
        var_dump($providers);
array(2) {
  ["US"]=>
  string(3) "USA"
  ["BE"]=>
  string(7) "Belgium"
}

Everything seems fine. But now let's change the order in which filesystem returned file list:

        $filesIterator = [
            new \SplFileInfo('/Users/leafnode/var/devel/yasumi/src/Yasumi/Provider/Belgium.php'),
            new \SplFileInfo('/Users/leafnode/var/devel/yasumi/src/Yasumi/Provider/USA.php'),
            new \SplFileInfo('/Users/leafnode/var/devel/yasumi/src/Yasumi/Provider/AbstractProvider.php'),
        ];

And now the output is:

array(2) {
  ["BE"]=>
  string(7) "Belgium"
  ["US"]=>
  string(16) "AbstractProvider"
}

Why? Because the pair 'US' => 'AbstractProvider' has overwritten the pair 'US' => 'USA'.

We could fix this issue in many different ways. One of them is to sort the input iterator by filename, but that's kind of a naive approach that relies on believing that we get the input in a specific order. My idea was to make sure that we load only actual providers basing on one thing we know: it has to extend AbstractProvider class, as well as contain ID constant. I was thinking about removing the constant from the AbstractProvider, but I'm not that accustomed with Yasumi's internals, and maybe there's some requirement for that constant to be there.

@stelgenhof
Copy link
Member

Thanks for the example! Totally understand the issue now. So it looks like the FilesystemIterator may return an array of the files in an order that is not always guaranteed to be the same.

The ID constant acts merely as an identifier for the provider. I believe I used 'US' as a default for no particular reason :)

Let me have a look in a bit more detail tomorrow; however your PR looks like a good solution.

Copy link
Member

@stelgenhof stelgenhof 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 checked this and looks to address the issue. Would you mind adding an entry to the CHANGELOG.md file as part of this PR?

Once added, I will merge it.

@stelgenhof stelgenhof added the bug label Jun 7, 2018
@stelgenhof stelgenhof added this to the v2.0.0 milestone Jun 7, 2018
@leafnode
Copy link
Contributor Author

leafnode commented Jun 8, 2018

Added the changelog entry.

@norberttech
Copy link

stelgenhof added this to the v2.0.0 milestone 8 hours ago

Why 2.0.0? It looks like something that should be fixed in earliest possible version. It does not break anything, I dont think anybody was relying on random behavior.

@stelgenhof
Copy link
Member

@norzechowicz v2.0.0 will be the next official release. This PR will be merged in the development branch, so anyone can use that branch if they like :)

@stelgenhof stelgenhof merged commit 45ff7b2 into azuyalabs:develop Jun 8, 2018
@norberttech
Copy link

merge into develop does not sounds like a solution, my project relies on that library (and probably many others as well), it's also having composer.json in pretty good shape (meaning we can update dependencies without risk of breaking things), using not stable branches is against our dependencies policy. I would really appreciate if you could at least release 1.8.1 with this fix.
I'm also not sure what changes you are planning in version 2.0.0 but I can't allow to jump from 1.x to 2.x just like that, our dependencies are set to ^1.8, I hope you understand my concerns.
If you would need any help with what I'm asking for, just let me know what I can do.

@stelgenhof
Copy link
Member

Sure, understand your concern. Let me see if I can create a 1.8 patched version. :)

Just FYI: v2.0.0 will be a new branch supporting PHP 7 only going forward. v1.8 will be the last version based on PHP 5 and will not include any new features. Not sure yet when I'm going to release v2.0.0 yet (kind of occupied with other projects).

@norberttech
Copy link

hey @stelgenhof any chance to release 1.8.1 anytime soon?

@stelgenhof
Copy link
Member

@norzechowicz No. Do you experience any critical issues with the current release?

@norberttech
Copy link

Yes, random behavior that can't be predicted fixed by this particular PR

@stelgenhof
Copy link
Member

@norzechowicz Perhaps I am not seeing the entire picture here, but could you describe your situation in more detail? That may give me more context. Are there also other unpredictable results besides the one described in this PR (USA example)?

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants