Skip to content

2.x term factories#2203

Merged
jarednova merged 28 commits into2.x-factoriesfrom
2.x-term-factories
Mar 10, 2020
Merged

2.x term factories#2203
jarednova merged 28 commits into2.x-factoriesfrom
2.x-term-factories

Conversation

@acobster
Copy link
Copy Markdown
Collaborator

Implements the Terms API.

Per my recommendation on #2094, this drops support for automatically including 'hide_empty' => false in Term query params.

I did manage to keep the "corrections" e.g. fixing taxonomies => taxonomy and tags => post_tag, etc. without too much fanfare. So we don't have to break code that relies on that.

Coby Tamayo and others added 12 commits January 17, 2020 17:32
This matches up with WP Core and constitutes a non-breaking change.

As a follow-up, we should still test passing different args for terms
shared between taxonomies, and define exactly what those semantics are.
also make a note about a test that randomly failed
because it turns out I am not a time lord.
@acobster acobster requested a review from gchtr February 22, 2020 00:19
@jarednova
Copy link
Copy Markdown
Member

Awesome, thanks @acobster! Things are looking good on the testing side. There are some failures (not in PHPUnit, but static analysis). Most of them are in code not connected to this PR — but there's one we should def. take a look at ...

 ------ -------------------------------------------------------------------- 
  Line   Term.php                                                            
 ------ -------------------------------------------------------------------- 
  229    Static method Timber\Timber::get_term() invoked with 2 parameters,  
         0-1 required.        ```

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 25, 2020

Codecov Report

❗ No coverage uploaded for pull request base (2.x-factories@7d38ef1). Click here to learn what that means.
The diff coverage is n/a.

Impacted file tree graph

@@               Coverage Diff                @@
##             2.x-factories    #2203   +/-   ##
================================================
  Coverage                 ?   91.28%           
  Complexity               ?     1626           
================================================
  Files                    ?       53           
  Lines                    ?     4097           
  Branches                 ?        0           
================================================
  Hits                     ?     3740           
  Misses                   ?      357           
  Partials                 ?        0

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 7d38ef1...da49967. Read the comment docs.

@acobster
Copy link
Copy Markdown
Collaborator Author

@jarednova thanks for that - fixed. I'll make a note to start running the analyzer before making PRs, too.

@szepeviktor not directly related to this PR, but some of my code is getting flagged:

 ------ -------------------------------------------------------
  Line   Comment.php                                           
 ------ -------------------------------------------------------
  123    Unsafe usage of new static().
         💡 Consider making the class or the constructor final.
 ------ -------------------------------------------------------

 ------ -------------------------------------------------------
  Line   User.php                                              
 ------ -------------------------------------------------------
  115    Unsafe usage of new static().
         💡 Consider making the class or the constructor final.
 ------ -------------------------------------------------------

what about new static() is unsafe? We need to use late static binding here, or else class maps simply won't work.

@szepeviktor
Copy link
Copy Markdown
Contributor

new static() is unsafe when the class is not final.
@ondrejmirtes is very good at explaining this.

@ondrejmirtes
Copy link
Copy Markdown

Someone can extend from your class and override the constructor with different arguments, so that your new static call will crash. See: https://3v4l.org/7JlG4

You have these options:

  1. Use new self() - you might realize you don't need new static().
  2. Make your constructor final.
  3. Make your class final at which point you can also use new self() :)
  4. Create an abstract method createX() that each child class needs to implement with their own new self implementation.

@ondrejmirtes
Copy link
Copy Markdown

  1. Make your constructor part of an implemented interface at which point its signature cannot change.

@acobster
Copy link
Copy Markdown
Collaborator Author

Thanks @ondrejmirtes and @szepeviktor - making the constructors final seems heavy-handed to me for this case but sound like we have some other good options.

@jarednova this discussion made me realize that I never actually implemented Term::build()...d'oh! So standby for that.

@acobster
Copy link
Copy Markdown
Collaborator Author

OK @jarednova I'll have an update soon but in the meantime I wanted to get back to this discussion about the new static warning. In short, I believe each of those options in this specific case is untenable for our users and I'm still recommending that we annotate these instances with ignores.

@szepeviktor - please note that this is not about the cost/benefit of syntax checks, coding standards, or static analysis in general. The net benefit of all those things is clear and is taken as a given (tip of the hat to @ondrejmirtes - I'm already liking this tool a lot more that phpcs! 😃). This is about answering the question: what is the cost vs. the benefit for our users of appeasing or ignoring this specific warning?

Here is why I think each option won't work in our particular case:

  1. We need late static binding here or else Class Maps simply will not work.
  2. Making the constructor final precludes any user in the future doing anything involving a custom constructor. For example, I might want to do this:
class MyPost extends Post {
  protected function __construct($stuff, $things) {
    // do something special with $stuff and $things
  }

  public static function build( WP_Post $wp_post ) {
    [ $stuff, $things ] = SomeApi::special_sauce();
    return new static($stuff, $things);
  }  
}
  1. Making any of these classes final would essentially make most of Timber's API useless.
  2. I'd be fine with each subclass implementing its own build() method to call new self() if these were purely internal classes. Unfortunately these are classes that are designed to be extended, which means we'd be putting the burden on users to implement something that Factories are already capable of doing, and defeats the purpose of the Factory pattern to begin with.
  3. Protected methods, including constructors, cannot be part of an interface by definition. I tried this on the abstract Timber\Core class but abstract classes do not make the same guarantees about the signature.

To sum up, following the letter of this specific error just swaps out a (already very rare) Fatal Error about required arguments with one about final constructors, and moreover limits our users' movement for very little benefit to them.

@ondrejmirtes
Copy link
Copy Markdown

The most non-disrupting way would probably be to introduce a new interface implemented by the class where the new static code is. The interface would contain public function __construct with the arguments to enforce. This would only break code that already has the bad constructor and already represents broken code today.

@szepeviktor
Copy link
Copy Markdown
Contributor

szepeviktor commented Feb 27, 2020

I believe each of those options in this specific case

I think a developer has to have some ground rules
which are not evaluated on per project basis.
Many businessmen do this (the per project thinking)

I am looking at things from a 2 years perspective.

@acobster
Copy link
Copy Markdown
Collaborator Author

a developer has to have some ground rules

Agreed. It seems we only differ on what those ground rules are. Here are some of mine:

  • Think from your users' perspective
  • Use the right tool for the job
  • Identify reasonable exceptions

@szepeviktor
Copy link
Copy Markdown
Contributor

Think from your users' perspective

You're right.
I'm not able to manufacture a WordPress developer compatible software
as ~30-50% of the source code will be highly abnormal from modern PHP perspective.

@acobster
Copy link
Copy Markdown
Collaborator Author

Hahaha. The WP core is a rat's nest, no two ways about it!

Sometimes WP is the right tool for the job, and sometimes it isn't.

@jarednova
Copy link
Copy Markdown
Member

Thanks everyone for the thoughts and expertise on this issue. I'm really glad we've been able to work out both the guidelines and the exceptions we need to make given the circumstances. @acobster do you have any more commits coming to this branch, or is ready for final review?

@acobster
Copy link
Copy Markdown
Collaborator Author

@jarednova @gchtr turned out there was quite a bit more work that I'd missed once I made the constructor protected. Should be ready for review now.

Copy link
Copy Markdown
Member

@gchtr gchtr left a comment

Choose a reason for hiding this comment

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

Cool, thank you so much @acobster for the next piece towards 2.x! I really like how factories centralize the logic from various places.

I looked at it mainly from an API perspective and found some small things.

@acobster
Copy link
Copy Markdown
Collaborator Author

acobster commented Mar 1, 2020

@gchtr I was definitely coming at it with PHPUnit-induced tunnel vision. 😆 You're right on with all of this; I'll circle back this week. Thanks for the detailed review!

cc @jarednova

@jarednova
Copy link
Copy Markdown
Member

jarednova commented Mar 1, 2020

@acobster @gchtr looking good! I second the notes/comments made above. As for ...

public function terms( $query_args = [], $options = [] ) {}  

@jarednova Would this be something you could work on?

Yup! I'll get to work on a PR for that

Update: the PR is #2208

@jarednova jarednova mentioned this pull request Mar 1, 2020
@acobster
Copy link
Copy Markdown
Collaborator Author

acobster commented Mar 6, 2020

@gchtr @jarednova I think I've addressed all the review feedback except the docs update. Take another look at let me know?

Copy link
Copy Markdown
Member

@gchtr gchtr left a comment

Choose a reason for hiding this comment

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

Good to go from my part 👍

@jarednova
Copy link
Copy Markdown
Member

Copy that, added one last test — and presto!

@jarednova jarednova merged commit 62e42e5 into 2.x-factories Mar 10, 2020
@nlemoine nlemoine deleted the 2.x-term-factories branch June 23, 2022 09:35
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.

5 participants