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

Add support for path namespaces. #1791

Closed
wants to merge 15 commits into from

Conversation

jenkoian
Copy link

@jenkoian jenkoian commented Sep 17, 2018

Issue

When looking into timber for a project I'm currently working on, I was looking to make use of path namespaces (e.g. https://symfony.com/doc/current/templating/namespaced_paths.html#registering-your-own-namespaces) but it seems that Timber doesn't currently support this.

Solution

This patch introduces support for path namespace, at time of writing only as part of user defined locations, however this could easily be added to to support namespace in theme dirs as well if you wanted.

Impact

It should be backwards compatible, so it shouldn't have any negative impact on existing users.

Update This will have an affect on users of some filters, see #1791 (comment)

Usage Changes

Users who wish to make use of path namespaces can now do so, e.g. with a styleguide namespace

Timber::$locations = array(
    '/Users/jared/Sandbox/templates',
    '~/Sites/timber-templates/',
    ABSPATH.'/wp-content/templates',
    ABSPATCH.'/wp-content/styleguide' => 'styleguide'
);

Considerations

I've not spent too much time on this patch, I'm hoping for some guidance/advice if there are any edge cases I may not have considered as I am very new to this library.

It's also worth noting that I've just checked for a namespace presence and ignored if none there, but we could easily change to give each location the default namespace (__MAIN__) if none is configured, to cut down on an if statement.

Update This now does indeed set the default namespace.

Testing

I included one basic unit test, but would be happy to add more if you think this patch is worth including.

Update Have included several useful tests.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.02%) to 94.222% when pulling 7e3e172 on jenkoian:add-twig-namespace-support into fefd935 on timber:master.

@coveralls
Copy link

coveralls commented Sep 17, 2018

Coverage Status

Coverage increased (+0.03%) to 93.942% when pulling 83b188d on jenkoian:add-twig-namespace-support into 70724c2 on timber:master.

@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #1791 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1791      +/-   ##
============================================
+ Coverage     94.83%   94.84%   +<.01%     
- Complexity     1527     1530       +3     
============================================
  Files            48       48              
  Lines          3585     3591       +6     
============================================
+ Hits           3400     3406       +6     
  Misses          185      185
Impacted Files Coverage Δ Complexity Δ
lib/Loader.php 96.25% <100%> (+0.09%) 68 <0> (+2) ⬆️
lib/LocationManager.php 100% <100%> (ø) 26 <0> (+1) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fae5977...1185b9c. Read the comment docs.

@jarednova
Copy link
Member

@jenkoian thanks for the contrib! I'll confess we're deep into work on 2.x so I won't be able to start a review right away.

My biggest concern is just double-tripple checking that the use of a namespace will not disrupt rendering a .twig file from a non-namespaced path (ie. inside the /templates or /views directory. Can you write a test that demonstrates and verifies this?

@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #1791 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1791      +/-   ##
============================================
+ Coverage     94.83%   94.84%   +<.01%     
- Complexity     1527     1530       +3     
============================================
  Files            48       48              
  Lines          3585     3591       +6     
============================================
+ Hits           3400     3406       +6     
  Misses          185      185
Impacted Files Coverage Δ Complexity Δ
lib/Loader.php 96.25% <100%> (+0.09%) 68 <0> (+2) ⬆️
lib/LocationManager.php 100% <100%> (ø) 26 <0> (+1) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fae5977...1185b9c. Read the comment docs.

4 similar comments
@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #1791 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1791      +/-   ##
============================================
+ Coverage     94.83%   94.84%   +<.01%     
- Complexity     1527     1530       +3     
============================================
  Files            48       48              
  Lines          3585     3591       +6     
============================================
+ Hits           3400     3406       +6     
  Misses          185      185
Impacted Files Coverage Δ Complexity Δ
lib/Loader.php 96.25% <100%> (+0.09%) 68 <0> (+2) ⬆️
lib/LocationManager.php 100% <100%> (ø) 26 <0> (+1) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fae5977...1185b9c. Read the comment docs.

@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #1791 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1791      +/-   ##
============================================
+ Coverage     94.83%   94.84%   +<.01%     
- Complexity     1527     1530       +3     
============================================
  Files            48       48              
  Lines          3585     3591       +6     
============================================
+ Hits           3400     3406       +6     
  Misses          185      185
Impacted Files Coverage Δ Complexity Δ
lib/Loader.php 96.25% <100%> (+0.09%) 68 <0> (+2) ⬆️
lib/LocationManager.php 100% <100%> (ø) 26 <0> (+1) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fae5977...1185b9c. Read the comment docs.

@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #1791 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1791      +/-   ##
============================================
+ Coverage     94.83%   94.84%   +<.01%     
- Complexity     1527     1530       +3     
============================================
  Files            48       48              
  Lines          3585     3591       +6     
============================================
+ Hits           3400     3406       +6     
  Misses          185      185
Impacted Files Coverage Δ Complexity Δ
lib/Loader.php 96.25% <100%> (+0.09%) 68 <0> (+2) ⬆️
lib/LocationManager.php 100% <100%> (ø) 26 <0> (+1) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fae5977...1185b9c. Read the comment docs.

@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #1791 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1791      +/-   ##
============================================
+ Coverage     94.83%   94.84%   +<.01%     
- Complexity     1527     1530       +3     
============================================
  Files            48       48              
  Lines          3585     3591       +6     
============================================
+ Hits           3400     3406       +6     
  Misses          185      185
Impacted Files Coverage Δ Complexity Δ
lib/Loader.php 96.25% <100%> (+0.09%) 68 <0> (+2) ⬆️
lib/LocationManager.php 100% <100%> (ø) 26 <0> (+1) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fae5977...1185b9c. Read the comment docs.

@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #1791 into master will increase coverage by 0.02%.
The diff coverage is 98.48%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1791      +/-   ##
============================================
+ Coverage     94.54%   94.57%   +0.02%     
- Complexity     1530     1540      +10     
============================================
  Files            48       48              
  Lines          3594     3613      +19     
============================================
+ Hits           3398     3417      +19     
  Misses          196      196
Impacted Files Coverage Δ Complexity Δ
lib/Loader.php 96.31% <100%> (+0.16%) 69 <1> (+3) ⬆️
lib/LocationManager.php 100% <100%> (ø) 30 <3> (+5) ⬆️
lib/Timber.php 96% <90%> (+0.04%) 34 <0> (+2) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 70724c2...83b188d. Read the comment docs.

@jenkoian
Copy link
Author

@jarednova thanks for taking a look at the PR! Yeah I figured it was all hands to the pump re. 2.x release (what a great 2.x feature namespace support would be btw! 😃). I'll add some more tests later today.

@jenkoian
Copy link
Author

@jarednova I've added a few more tests, let me know if that's what you had in mind 👍

Ian Jenkins added 2 commits September 19, 2018 15:35
Particularly useful if using a styleguide which uses a particular
namespace.
@jarednova
Copy link
Member

Yep! Those tests show namespaced and non-namespaced template calls living side-by-side in harmony. I think we're good here, but I'd still like @gchtr or @pascalknecht to give it a look as well to make sure there's something we're not missing/considering

@jenkoian
Copy link
Author

Looks like build failed due to a composer issue on one of the jobs, are you able to restart the job?

@pascalknecht
Copy link
Contributor

@jarednova @jenkoian Codewise it looks good to me. Only objection to merge for me is documentation which is currently missing and code style which is currently not according to WordPress Guidelines.

@jarednova
Copy link
Member

jarednova commented Sep 19, 2018

@pascalknecht agreed! @jenkoian can you format according to WordPress Coding Standards and update the docs? I think this would belong in the template-locations.md file:

https://github.com/timber/timber/blob/master/docs/guides/template-locations.md
https://timber.github.io/docs/guides/template-locations/

@gchtr
Copy link
Member

gchtr commented Sep 19, 2018

Oh, this is a really nice addition! I just have one question: In the linked Symfony documentation, the pattern to describe namespaces is defined through path => namespace. Here, we would add it as namespace => path. Is this a deliberate solution that was chosen because of technical reasons? Or would it make sense to have 'ABSPATH.'/wp-content/styleguide' => styleguide' instead of 'styleguide' => ABSPATH.'/wp-content/styleguide' to follow Symfony’s style?

@chrisvanpatten
Copy link

I'd echo @gchtr about following the Symfony convention. Anywhere Timber can follow existing conventions would be fantastic!

@jenkoian
Copy link
Author

Thanks for your comments!

Codewise it looks good to me. Only objection to merge for me is documentation which is currently missing and code style which is currently not according to WordPress Guidelines.

Docs now added, have amended code style, although it doesn't look like this is enforced throughout the lib?

Oh, this is a really nice addition! I just have one question: In the linked Symfony documentation, the pattern to describe namespaces is defined through path => namespace. Here, we would add it as namespace => path. Is this a deliberate solution that was chosen because of technical reasons? Or would it make sense to have 'ABSPATH.'/wp-content/styleguide' => styleguide' instead of 'styleguide' => ABSPATH.'/wp-content/styleguide' to follow Symfony’s style?

Excellent spot! 🦅 👁 I initially planned to follow what symfony do (i.e. path => namespace) but I didn't think it made as much sense here as we're not configuring via yaml. For example, in Symfony you can imagine..

'path/to/templates1': namespace1
'path/to/templates2': namespace2
'path/to/templates3': ~

Would map to PHP as..

array(
    'path/to/templates1' => 'namespace1',
    'path/to/templates2' => 'namespace2',
    'path/to/templates3' => null,
);

Which makes looping over etc. really easy. However, if you imagine the following...

Timber::$locations = array(
    'path/to/templates1' => 'namespace1',
    'path/to/templates2' => 'namespace2',
    'path/to/templates3',
);

We'd end up with...

array(
    'path/to/templates1' => 'namespace1',
    'path/to/templates2' => 'namespace2',
    0 => 'path/to/templates3',
);

So we end up with the path being the key in some instances and the value in others, we can of course code around that, but it seemed simpler to me to just flip them around.

However I noticed Symfony supports multiple paths per namespace, which obviously won't work if we have the namespace as our key as we can't have duplicate keys. So, I've gone ahead and made this change. It's quite involved unfortunately, but all the tests pass. Only concern I have is that it will potentially change the following filters:

timber/loader/paths
timber/loader/loader
timber_locations
timber/locations

As previously they would get a list of paths like so:

array(
    'path/of/templates1',
    'path/of/templates2'
);

Where as now it'll be:

array(
    '__MAIN__' => array(
        'path/of/templates1'
    ),
    'namespace' => array(
        'path/of/templates2'
    )
);

Finally, I've added a test for multiple paths per namespace and I've also thought of nested namespaces, so I've added a test to cover that too.

Cheers!

}, $path_locations );
} else {
$fs->addPath( $path_locations, $namespace );
}
Copy link
Author

Choose a reason for hiding this comment

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

I'm being overly defensive here as $path_locations will always be an array, as it affects code coverage I'll remove this if/else.

Copy link
Author

Choose a reason for hiding this comment

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

Have removed the else, think the if is fine.

lib/Timber.php Outdated
include trailingslashit( $uri_locations ) . $sidebar;
$found = true;
break;
}
Copy link
Author

Choose a reason for hiding this comment

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

I'm being overly defensive here as $uri_locations will always be an array, as it affects code coverage I'll remove this if/else.

@pascalknecht
Copy link
Contributor

Ok so it will affect the filters you mentioned:
timber/loader/paths timber/loader/loader timber_locations timber/locations

We will need to include this in the upgrade guide to 2.0 then. Agreed @jarednova ?

continue;
}
$theme_locs[] = $root;
$root = trailingslashit($root);
$theme_locs[ FilesystemLoader::MAIN_NAMESPACE ][] = $root;
Copy link
Author

Choose a reason for hiding this comment

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

This might be undesirable if a user is using a custom loader (via a filter) and have customised the main namespace name. Should a define a constant on the Loader class within Timber rather than use the one from the Twig Filesystem Loader?

Copy link
Author

Choose a reason for hiding this comment

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

Addressed in f31adba

As custom loaders may be used, limit the dependency on FilesystemLoader
in the LocationManager by defining our own main namespace.
@gchtr
Copy link
Member

gchtr commented Sep 25, 2018

Cool stuff 😎. This looks good for me in terms of documentation.

I have to admit that the Loader isn’t my strongest suit, so I’d be happy if someone else could look at the code in detail, @jarednova maybe?

If the filters are going to change, we definitely need to add this in the Upgrade Guide for 2.0. I normally do this separately, as soon as a feature is merged. Currently, this pull request wants to merge into master. I guess when the existing filters will change, we would have to pull this into the 2.x branch.

@jenkoian
Copy link
Author

Do you want me to rebase against 2.x ?

$locs = array_merge($locs, self::get_locations_theme());
$locs = array_merge($locs, self::get_locations_caller($caller));
$locs = array_unique($locs);
//$locs = array_diff_assoc( $locs, self::get_locations_theme() );
Copy link
Author

Choose a reason for hiding this comment

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

Will remove this.

Copy link
Author

@jenkoian jenkoian Sep 29, 2018

Choose a reason for hiding this comment

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

Just to explain, I don't think the diff is needed, it's handled in the array merge and array unique.

Ian Jenkins and others added 3 commits September 29, 2018 21:49
@jarednova
Copy link
Member

@jenkoian thanks so much for hanging with us through all these Qs. I think we're very close, but I get caught on the issue of the filters and how it could potentially break compatibility with anyone who's using timber/loader/paths or some of the others.

I just wrote a test in 9f4ed02 to validate the current behavior and see how it compares to this PR (on my local the new test fails against this PR). I think there are two routes to go to merge this in:

  1. Merge into 1.x and write some functions to adapt old filter behavior into the how things are handled with the namespaces
  2. Merge into 2.x and handle write the info in the upgrade guide.

My vote is for #2; but I want to see what @jenkoian thinks of this

@pascalknecht
Copy link
Contributor

Also voting for option 2

@jenkoian
Copy link
Author

jenkoian commented Oct 1, 2018

Awesome test! I'll take a closer look and get back to you 👍

@jenkoian
Copy link
Author

jenkoian commented Oct 3, 2018

Ok had chance to review the failing test. Yes agree with your two options, I am happy to add the backwards compatibility workaround if you'd like, but yeah would probably vote for option 2. I guess one thing on that, is it would require the user to add a namespace, even if using the default, e.g.

$paths[Timber\Loader::MAIN_NAMESPACE][] = __DIR__.'/october/';

as opposed to simply

$paths[] = __DIR__.'/october/';

They would also need to ensure they're appending to an existing array (or passing an array if using a new namespace they've created).

Not sure if we deem this too much of a departure even for 2.x or not? I'm not sure how used these filters are for the community? I guess as long as we document the filter and it's usage it should be ok, I can't seem to find much docs on the filter at the mo, so perhaps that's something else I can add?

@gchtr
Copy link
Member

gchtr commented Oct 3, 2018

I also vote for option 2. In addition to that, could we get rid of the following pattern, where locations are assigned through a static variable?

Timber::$locations = array(
    'path/to/templates1' => 'namespace1',
    'path/to/templates2' => 'namespace2',
    'path/to/templates3',
);

Instead, I’d only use the timber/locations filter and make this the primary filter for custom locations.

They would also need to ensure they're appending to an existing array (or passing an array if using a new namespace they've created).

This is also a reason why I think using a filter only would be better, because that’s the established behavior for filters: You filter something, or you append to something existing. If we provide good examples, I don’t see a problem.

For the deprecation, I’d do it like this:

  • Let Timber::$locations work like before, but issue a deprecation warning through Helper::deprecated().
  • Add a check for the filters, whether the resulting array is associative or not. If it’s not associative, then do not apply the namespacing functionality and issue a deprecation warning through Helper::deprecated().

@jenkoian There’s not so much documentation about the filters yet, but if you’re going to rebase against 2.x, then you’re gonna see that there’s the base for the upcoming filter documentation (read more about this here.

/**
* Filters …
*
* @todo Add summary, description, example, parameter description
*
* @since 0.20.10
*
* @param array $locs
*/
$locs = apply_filters('timber/locations', $locs);

I’d be very happy if you could complete that with descriptions and examples, etc. We’d still have the main documentation in the Template Locations Guide. The filter documentation is more some kind of technical reference.

@jenkoian
Copy link
Author

jenkoian commented Oct 3, 2018

@gchtr that is an awesome approach (love this project!). When I get some time i'll add the filter documentation.

I've not rebased this against 2.x yet, do you want me to do that now, or should I open up a new PR with this against 2.x for comparison?

@jarednova
Copy link
Member

@jenkoian please open a fresh PR against 2.x (referencing this PR), I think things will be easiest to track there — thanks!

@jenkoian
Copy link
Author

jenkoian commented Oct 8, 2018

Ok opened against 2.x here: #1811 struggling for time a bit at the mo, so not had chance to make the recommended changes. Will do so as soon as I can!

@jarednova
Copy link
Member

Great, thanks @jenkoian! I'm going to close this PR so we can follow-up on #1811 and resolve that last change there

@jarednova jarednova closed this Oct 8, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants