XF 2.0 Creating Tables VS Creating Columns. src\XF\Repository\SessionActivity.php

Brad Padgett

Well-known member
I'm trying to create a "Most Users Ever Online" add-on. If I manage to pull it off I plan to release it as a free release to the community.

I need the run-down on when I should take the initiative to create a table vs whether I should create a column in one of the tables instead.

I've actually come fairly far to see in my phpstorm IDE that src\XF\Repository\SessionActivity.php is the file I'll need to add a proxy class too in order to do this. I can simply add a proxy class based on the XF proxy system and use the Finder so that it will dump out the total users online.

My simple question is this. What table should I add the column to or should it be a separate table? Last question is do you suggest I use the proxy class system for the entity/finder and when are you able to know when it's needed and when you should extend a class without it?

I'm actually quite happy I found the right file for the add-on. You can view the php code and see that the majority of the file is for the online users record.

Any help you can provide with this is highly valued. If I can manage to learn how to do this one add-on I can do many more in the future.

And @Chris D I know your quite busy to respond to everyone's postings but I wanted to tag you just in case your able to help.
 
I need the run-down on when I should take the initiative to create a table vs whether I should create a column in one of the tables instead.
"It depends".

If you're extending an entity and you expect every entity to hold a value (e.g. new user preference), you would add an column to the entity table. This gives you the adventage that you don't need to join a second table into the query, thus, every existing call will have the updated entity, so you easily could work with that in templates and existing code. On the other hand, this means, you most likely have to declare a default value (or empty) if not all of your entities actually need that extra column which can be an ugly overhead because, well, every entity would have an additional data column.

If you're extending an entity and you don't expect every entity to actually populate the values (e.g. new log for an interaction), you would create a separate table for that. This gives you the freedom of choice to keep the entity records when the referenced key is deleted or not (foreign keys). The "downside" whatsoever is that this would either require an additional join or an additional query and some more coding (entity, relations, all that stuff). But imho, that's not tragic. Also, existing code wouldn't be able to use that entity so you would need to manually alter that code aswell.

This is my humble opinion and it could be total bs, but that's the route I usually go. Depending on the functionality and how far you've thinked about evolving your add-on, I'd actually suggest you to create a new table and entity so you could keep track of "Most Users Ever Online" as a history, timeline or whatever. It's fairly easy to adapt that and it would be a step in being open for requests rather than being set in stone on one direction. If you're not planning on adding basic functionalities, then probably some kind of stat, xf_stats_daily, or an uneditable option would fit (just create an option for your addon and update that value via cron then).

Regarding your last question: https://xenforo.com/community/threads/extending-the-same-class-twice-in-two-addons.147996/
 
@S Thomas thanks for the information. One more question I have is aren't you not supposed to create a code event listener for a separately created table? It seemed that's what it said in the xf 2 docs. Does this strictly rely on relations to work rather than code event listeners? Or is just adding a class extension in the admin panel enough for it to work.
 
There was a discussion about this here https://xenforo.com/community/threa...ev-listeners-trying-to-grasp-the-idea.147348/.
What I've learned since then is the following:
  • If you want to be absolutely compliant with every kind of addon out there, you will need a code event listener
  • If you have filled your additional stuff with nullable = true or maybe a default value, you're most likely fine with just a class extension.
The reason for that is pretty simple: Without event listener, you're just extending the entity class. This means, if someone directly calls the base class, e.g. new ThreadEntity(), this will only create the base class (this is what the entity manager for example does). This entity won't contain your modified code. On the other hand, with a listener, when creating the entity, the entity itself will fire an event which you can listen to. And here is where you can inject your code.

So unless you have some super-important code which supersedes something in the base entity or you really want to have all the time, you're good-to-go. Downside obviously, if you create the entity class yourself, you will have to keep in mind that you will need to either create an element of your child entity or you will need to fully extend your base entity first. Services for example iirc usually fully extend a class. Nvm, they don't :D Or maybe they do, idk, it's too late.
 
Last edited:
Yes @S Thomas I get that and it makes complete sense. However in the documentation. Specifically here:

https://xenforo.com/xf2-docs/dev/lets-build-an-add-on/#creating-a-new-entity

In that it says the following:

Above in installStep3() we created a new table. We are going to need to create an entity to interact with and create new records in this table. Because this is a brand new entity we don't need to do anything other than create the class inside src/addons/Demo/Portal/Entity/FeaturedThread.php,

That leads me to believe your not supposed to create code even listeners to single tables.

Now given it says "brand new entity" and not "brand new table", I suppose if I'm extending a base entity like you said inside "src\XF\Repository\SessionActivity.php" then I should be free to create a code event listener correct? I'm just trying to weed through when it's not allowed and when it's okay for me to create one. Tbh I think a combination of code event listeners and class extensions both are the right way to do this but need clarification that by what that says it's referring to the fact that the entity does not already have a code event listener, rather than the other way around where it's saying you can't create one.

Thanks for your help. I know this will help out a lot of other people too.
 
That leads me to believe your not supposed to create code even listeners to single tables.
No, this just means you're not extending a class, so you obviously can use your entity as-is.

To put it short, code event listeners modify the behaviour of your base class always ("replace functionality always"), while class extensions only work when you're using an extended class ("use functionality only when I want"). From the addons I've quickly looked at nobody actually uses listeners to extend entities, they rather replace some basic functionality or add functions to global objects.
 
No, this just means you're not extending a class, so you obviously can use your entity as-is.

To put it short, code event listeners modify the behaviour of your base class always ("replace functionality always"), while class extensions only work when you're using an extended class ("use functionality only when I want"). From the addons I've quickly looked at nobody actually uses listeners to extend entities, they rather replace some basic functionality or add functions to global objects.

This makes complete sense. Thank you so much for your detailed response. I was afraid my thread wouldn't receive any help but you've out-done yourself to go out of your way to help me. Plus that makes sense to me now. I can now see that more than likely a code event listener would be used to modify a base class or a more generic class that would be core functionality. When reading the xf 2 dev docs I see that certain things like the thread entity are core to xf2 and therefore need a listener because they're modifying the base class of the thread entity. Where if I wanted to only change or extend small functionality for classes that weren't base classes then I would need to use a class extension.

Makes perfect sense now that you've put it like that. I appreciate the advice.
 
Top Bottom