Addon Model, conflict and cooperation

Hambil

Member
I have a question. Keep in mind I've only been looking at the new code for a day.... :p

It looks like xenForo uses an object oriented, design patterns approach, and I like that. It looks like the old hook system is now a system (by enlarge) replaced by extending classes.

So, for the mod I want, I'd have to extend XenForo_ViewPublic_Thread_ViewNewPosts, via the Load_Class_Control code event, and modify the method that does the sql query to get new posts. This is all very slick.

The question I have, is what happens when someone else does the same thing? Execution order will only help you decide which mod wins.

Am I missing something? As I said, new but learning fast.
 
This has some potential problems. When output was shared, addons could behave well and often multiple addons could alter the same output.
 
This has some potential problems. When output was shared, addons could behave well and often multiple addons could alter the same output.
Also what in it of strange? Certainly, any plug-in can through hooks, for example, completely to kill an output. It is just necessary to reflect on that the plug-in was safe for all system. But this problem of a plug-in, instead of system. After all would be silly to suppose, what XenForo Core will hinder with output change - then what generally sense in plug-ins? :)
 
I am writing an addon that overrides the XenForo_ViewPublic_Thread_ViewNewPosts class, to allow for filtering based on user. If anyone (as I understand it) for any other reason, even if they don't change the output, writes another mod that overrides the same class there is a conflict. That's not an argument, it's fact. However, what I'm asking is if/how the XenForo team, or other addon authors, deals with this.

It's possible I haven't dug deep enough yet, or missed someway on sharing the output that is already built into the system.
 
In the addon I also override some methods of base class. Naturally, I at first cause an original method, and then either I change an output, or I add it depending on that is necessary for me.
If another addon does the same the main thing - not to break a chain. If it is necessary to change a chain we can arrange only addons for this purpose. There are no two ways about it. So the developer addon should accurately to itself represent, as the base class, others addons which overrides its methods, and also, what consequences can be for the following addons which will do the same works.
The conflict is inevitable, therefore it is important to make everything to reduce this conflict only to ordering, instead of to the full rewriting of others addons or the product.

I do not know other variants.
 
The output could be piped, made static, there are many ways it could be done. Built into the base class is even a variable _executed which could be used to append output instead of overwriting it. I am all for us addon authors coming up with our own shared solution, and I agree the former system had issues. But this could ultimately be very limiting, when going object oriented should be just the opposite of limiting. Will just take some creative thinking :)
 
At any model (incapsulate and inheritance) all the same will be both pluses, and minuses. To make completely safe a class and results, to it produced, not really.
To minimize conflicts - a duty of developers addons.
Or you can offer more perfect system? :)
 
First, I want to say up front, you are a little hard for me to understand so please forgive me if I don't get something correct.

Second, we could do a addon developer solution, but we'd have to assume every addon developer used it, and unless we want to go the draconian addon approval process way of SMF, that would be a mess.

What would make more sense would be to build something into the core system. I can literally think of dozens of ways to do this, and in reality with an object oriented system there are probably thousands. But I'd probably go for something out of design patterns, like http://www.devshed.com/c/a/PHP/Implementing-the-Data-Mapper-Design-Pattern-in-PHP-5/
 
I regret, but my knowledge of English does not suffice to conduct this interesting discussion. Nevertheless, thanks for links. Also I will track this thread.
 
What is your point? Many current available add-ons are extending the same classes over and over again and there are not many conflicts. Of course, there are cases when 2 add-ons conflict with each other but it doesn't happen much. If you do it correctly, your add-on will work with other add-ons just fine.

In your example, you want to extend XenForo_ViewPublic_Thread_ViewNewPosts, you will need the event "load_class_view" (not load_class_control). You said you want to alter the query, well, you shouldn't do that in views. You should do that in the controller or model. I said "you should" because it's up to you to decide how you want to build your add-on but if you don't follow some basic principles, your add-on will break sooner or later and no body will use your add-on.

About the principles, well, I don't know how to express it but basically, you should keep the original output for each method (if it's array, keep it as an array). Don't remove the existing output completely, you must add or remove part of it (so if a method returns posts by a given query, and you want it to return posts with another query, you shouldn't discard the queried posts and execute your query by yourself). If you have more questions, you can ask them here but please be more specific (like: how can I change the query for posts in XenForo_ControllerPublic_Thread::actionIndex, etc.)

Good luck and hope to see your works here soon :D
 
What is your point?
I thought I made it very clearly. I also said I may not fully understand the model. So, what is your point?

In your example, you want to extend XenForo_ViewPublic_Thread_ViewNewPosts, you will need the event "load_class_view" (not load_class_control). You said you want to alter the query, well, you shouldn't do that in views. You should do that in the controller or model.
Yes, I know. I've since found the class with the sql query in it. Doesn't matter, because it doesn't change my original op at all. But thank you for pointing me in the right direction, had I ended up lost that would have been very helpful :)

I said "you should" because it's up to you to decide how you want to build your add-on but if you don't follow some basic principles, your add-on will break sooner or later and no body will use your add-on.
I understand that. I am talking about basic principles here. Design patterns for data persistence and data sharing aren't something I made up. And they help solve the issues of multiple addons. I can only speak from my personal experience, but this was a big issue when I wrote addons for vb, and tends to only get worse as a product gets more successful and has more addons.

If you have more questions, you can ask them here but please be more specific (like: how can I change the query for posts in XenForo_ControllerPublic_Thread::actionIndex, etc.)
I have to respectfully disagree. The questions I have are the ones I will post. You are under no obligation to answer them.

Good luck and hope to see your works here soon :D
Thanks! :)
 
Oh, hi fellow vBulletin developer! I don't remember much about working with conflicts when I develop vBulletin plugins... Most of the time it will be a common variable name getting used by 2 different plugins in the same hooks pair (postbit_start vs. postbit_display_complete for example). Good time! :) But yeah, that won't happen in XenForo, thanks to the design.

It looks like you still don't know how to deal with conflicts between add-ons. Why don't you just post your current code for the filter and we will see?
 
The code is in my head, but not complex. There is a method in XenForo_ControllerPublic_FindNew that uses find_new (from forum permissions) to filter a query. It has a
PHP:
'join' => XenForo_Model_Thread::FETCH_FORUM_OPTIONS
, but I haven't yet figured out how to coopertatively use that.

If I use the load_class_controller event listener I can extend XenForo_ControllerPublic_FindNew and add the join I want, but any other addon that messes with that query for any reason would (as I understand it) undo my changes?
 
If it's in your head, you'd better write it out to see how it works (and install a few similar add-ons to see if they break your add-on). But yeah, the thing you are trying to achieve is pretty tricky to be done. I still don't know exactly what you want to do so I have to assume: you want to use the FETCH_FORUM_OPTIONS join in XenForo_ControllerPublic_Forum::actionIndex() (not sure why you want to do that though :D). If I were you, I would do it this way:

Extends XenForo_Model_Thread
PHP:
class MyAddOn_Model_Thread extends XFCP_MyAddOn_Model_Thread {
 
public $MyAddOn_startAutoFetchForumOption = false;
 
public function prepareThreadFetchOptions(array $fetchOptions) {
if ($this->MyAddOn_startAutoFetchForumOption) {
// our flag is on, we should add the join now
if (!isset($fetchOptions['join'])) $fetchOptions['join'] = 0;
 
if ($fetchOptions['join'] & XenForo_Model_Thread::FETCH_FORUM_OPTIONS) {
// nothing to do here
} else {
$fetchOptions['join'] += XenForo_Model_Thread::FETCH_FORUM_OPTIONS;
}
}
// let's the parent do its job
return parent::prepareThreadFetchOptions($fetchOptions);
}
 
}


Extends XenForo_ControllerPublic_Forum
PHP:
class MyAddOn_ControllerPublic_Forum extends XFCP_MyAddOn_ControllerPublic_Forum {
 
public function actionIndex() {
// turn on our flag
$this->_getThreadModel()->MyAddOn_startAutoFetchForumOption = true;
 
// let's the parent do the real job (execute queries and such)
$response = parent::actionIndex();
 
// turn our flag off, this's optional
$this->_getThreadModel()->MyAddOn_startAutoFetchForumOption = false;
}
 
}

The code is not tested though. But it should give you the idea ;)
 
I want to make the "What's New" filterable by forum per user. Right now it's just by forum, set in the admin cp.

I thought about extending the model, but doesn't that have the same issue, and create more false positives? (the model listener would in theory be called far more than the view listener, as it might be used by multiple views).
 
Ah I see, there is an add-on request for that IIRC.

To do that, you will need to extends XenForo_ControllerPublic_FindNew then you can use a similar approach to my sample code above to "notify" the model that it should only get threads from a list of forums besides other things (new threads, permission check, etc.). Then you can do something like this in your extended version of XenForo_Model_Thread

PHP:
public function prepareThreadConditions(array $conditions, array &$fetchOptions) {
if (is_array($this->MyAddOn_listOfForums) AND count($this->MyAddOn_listOfForums) > 0) {
$conditions['node_id'] = $this->MyAddOn_listOfForums;
}
return parent::prepareThreadConditions($conditions, $fetchOptions);
}
 
Yes, and the samples are very much appreciated, as they save me some time. But I'm not really concerned about the specifics of the code. As you point out, there are a lot of addons and tutorials (plus just common sense) I can use for that. I've written plenty of code :)

My concern is more with the fact that the view no longer appears to have any session persistence. Meaning - if someone else extends the same view or model as me, there is no way for them to play 'cooperatively'. So, there can only every be one addon that modifies the FindNew view, for example.

If I am not explaining the issue properly, please let me know and I will try to do better.
 
The only things my sample code do is to add the node_id in the conditions. If other add-ons add more conditions (like adding prefix_id or limit last_post_date, etc.), they won't break your add-ons. But yeah, if there are 2 add-ons both changing $conditions['node_id'], one of them will be broken :D
 
Top Bottom