aaemnnosttv / silk

A modern API for WordPress.

Home Page:https://aaemnnost.tv/silk/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Relationships

aaemnnosttv opened this issue · comments

The ability to define relationships between models.

At a minimum, this should include:

  • One to One
  • One to Many
  • Many to Many

The relationship should be polymorphic, so we can use the same syntax for all types:

PostModel <--> TermModel
TermModel <--> TermModel
PostModel <--> PostModel

Depends on #5.

First off, thank you so much for creating this! It's an awesome library!
I'd like to help you on this feature as I found myself needing this as well.
Did you have any plan for this already? May I send you some of the ideas I has so far?
Let me know! Thanks!

Thanks Nicolo! I want to emulate Eloquent pretty closely as far as the way it is used. The challenging bit here is of course the implementation. I'm open to any ideas you may have though, feel free to share!

Case by case, here are my thoughts:
Post <---> Term
Should be written as:

public function tags(){
 $this->hasOneOrMany(Tags::class);
}

The main issue I can foresee here is that Terms do not allow for the use of a WP_query object.
We would have to escalate to wp_get_object_terms. We could return a Collection instance and map the results to cast each result to a Tag::class.

TermModel <---> PostModel
Should be written as:

public function posts(){
 $this->hasOneOrMany(Post::class);
}

We could delegate this to the QueryBuilder instance we already have in the Post::class and simply set the tax_query options. The benefit here is that it would already be wrapped in a Collection.

We could detect which instance is passed to the hasOneOrMany with the is_subclass_of. This would enable us to be polymorphic:

  • if it extends a Term object -> case 1
  • if it extends a Post object -> case 2

I'm not entirely sure on how to approach the Term <---> Term or Post <---> Post cases though. Not even sure on what it would actually be the scenario in wordpress to create these relationships. (my bad, never really dug that much into these!). If you could provide a couple of examples I'd be more than happy to have a think about it and see how that would fit in.

Another way would be to completely delegate all of the assertions to a $wpdb handler, but I feel like it's more likely to give problems since developers can alterate the behaviour of the query with filter (such as post_where and so on)

Thanks Nicolo,

I think you're right in that Post to Term relationships are probably the best place to start here, as this is probably the best supported relationship in WordPress.

Like you said, a post model would have a method for getting the relationship as a query, that we should be able to continue chaining configuration on.

/**
 * @return \Silk\Term\Query\Builder
 */
public function terms()
{
    return $this->hasMany(Tag::class);
}

Since models have a common interface for starting a query that is configured to return models of itself, we should be able to do something like:

public function hasMany($modelClass)
{
    return $modelClass::query();
}

Post to post relationships would require defining the convention that is used to relate them in the database. This could be using a taxonomy-based relationship (posts of a common term), or by post meta (likely for 1-1 relationship). I believe posts-to-posts (the plugin) uses its own table for this. This plugin is really easy to work with in a plugin, but might be hard to do as a library.

Another consideration is when a taxonomy can be used with multiple post types. In this case, there needs to be a way to handle the results when mapping into models, as queries currently only support returning a collection of a single model class. The problem gets compounded when exceptions will be thrown if a model is instantiated using a post/term of the wrong type/taxonomy.

For this reason, again, probably best to start with Post to Term and the inverse relationships due to the lack of extra tables, meta, etc.

Hi Evan,

Thank you for your insight!
I agree that the post-to-post is tricky. I don't see any way of doing that that doesn't involve including some sort of functionality in the admin area to manage this kind of relationships.

We could tackle that with some meta data to avoid having to create additional tables but it will still be a custom solution, not something natively supported by WordPress (meaning we would have to include some sort of custom metabox in the admin area to allow users to modify/manage this).

I started creating a trait to manage the post-to-term and term-to-post relationships.
Are you happy for me to create a PR with relevant tests once it's ready?