I have been pondering over this question for a few days now, and I can't seem to figure out what the best practice would be, so hopefully one of you guys / girls will be able to lead me down the right path.
Data
Lets say for the sake of argument we have a Meta data table, an Item data table and an Expiration date table.
Meta
Items
Expirations
A meta is what defines a collection of items and holds the general information for that collection, and there a certain criterias set on the meta which are used throughout the items layout.
An item is a derivation of a meta and holds unique data specific to that ONE item, and usually calls for the meta information. (Note: An item can ALSO be a collection of OTHER items)
A expiration is self explanatory, and is the expiration date of one individual item.
Current implementation
If you enter the meta page for any given meta, it will load the items in a paginated ajax call and for each loaded item it will load a status icon. This status icon is generated EACH time it is shown, and it is recursive (This means that if I were to put a status icon on the meta, then it would load all items for that meta and check all it's expiration dates and so fourth.)
With the extended implementation it currently does 600 calls (5.56 seconds) to the database (Which is quite a load, but is neccessary based on the database layout.)
My theory
I reckon it would show much better results for the end-user to simply store the status value in the database alongside each element, however I don't know if that is the right way to do things - considering that I would have to recursively adjust this status icon every time an element within the spectrum changes (including having a server job setup to go and update the status based on the expiration date)
The question
What would the best practice for a status icon be that is recursive and has many factors and relations to keep track of?
Best practice would be to cache a status icon and read it for end-user from cache only. All your load heavy stuff (recursive DB calls magic) will go into a job. Lastly you create observers for all your models that will queue this job to update cache value for changed items.
This way you will separate load heavy stuff to be handled by workers on your server side and on your client side everything will be fast and smooth. Once status icon update will be handled your end-user will see a change.
Related
I'm using Laravel 9 with php 8.1 in a pretty advanced project. In this project I have a parent form which allows a purchase order document to be created. The po document has at least one child row which is added by clicking an add button using livewire. However when this is saved the document it belongs to has not been created and thus no id i can use. So how would you guys handle such a form?
I'm considering a temporary id which I think is my best option. I had considered using the user id here but if I as the user have 2 such forms on the go then I wouldn't know which are the correct rows to amend with the document id, worse if I've added rows and get logged out these rows will be unattached.
Another option would be to create the document but as it stands it would fail validation due to there being no associated rows.
I'm struggling to find a strategy to deal with this scenario. In a previous project I used an is_draft flag for a similar scenario but it left orphaned items if the process was not fully completed.
thanks
You could refactor the view so Livewire controls both the purchase order form and the child row(s). Then Livewire would be able to keep the rows in their unsaved state until you save the parent form, at which point you'd also associate the rows and save those.
If the data is tightly coupled and interdependent then I would go for that approach.
I initially came across a composer package called cjmellor/approval (https://github.com/cjmellor/approval) but quickly realised it was far more than I needed but it did inspire me to into thinking of storing the raw data to use later.
After some thought I decided to create an stdClass to hold the required data for each row in the array and add/update this while creating the PO. I 'saved' this into my cache (I use redis in this app) with a 2 hour expiry. I then updated this cached array in livewire until the form was saved at which point I get the cached array data and updated the po data table with the cached data.
I'm currently developing a database/website server interface to facilitate inputting data for a data collection project. There are two types of additions being made to the database: A and B here. Some of the tables in the database that handle these entries are as follows:
dcs_projectname_a
dcs_projectname_b
Each of these have tables for all the required input fields in addition to things like creator, timestamp, etc.
The pages on the website facilitate three different options: add, view, and edit. Each page for each type of entry performs the respective function. That is, the add page adds, view page views, etc.
I am just about done; however, there is a major challenge I haven't really confronted yet: concurrency. There will be multiple users adding content to the database at the same time. Each entry is given its own specific id and there CANNOT be any duplicate id's. That is, the first a entry is A000001, the next is A000002, and so on.
On the add and edit pages, there is a disabled field for the user to view the id for other uses when physically documenting entries.
What I need to figure out is how to implement concurrency management so that when users are concurrently adding a's that they will not be under the same id and row.
The add page automatically generates the id to be used by accessing the database's most recent id and adding one.
My thought was to create a new row in the table every time the add page is opened and give it the calculated id. Then, when information is added it performs a modification to that existing row. This way, if another user opens the add page while another entry is currently being added it will be given the future id, not the same one.
With this method I need a way to delete this entry if the user leaves the add page or closes the browser. Then, I also need other users with open add pages to automatically update their id's to one less when the first user (or any other user less than the most id being used) leaves their add page and cancels the addition.
This is kind of a complicated explanation and if you don't understand let me know and I'll try to answer as best as I can. Any help is much appreciated!
Thanks
There's a number of solutions to your problem, but you seem to have made things harder by having your application generate the record IDs for you.
Instead, you could just be using MySQL's AUTO_INCREMENT functionality to automatically generate/increment the record ID for you (upon insert). MySQL will ensure that there are no duplicates, and you can get rid of the extra database call to retrieve the most recent ID.
I'm working for a client who asks me to prepare a module for its website (written using Yii) with the following features:
It shows 3 elements from a mysql_result, starting from offset=0.
The user can click on any of them to mark them as "read". That makes the desired item to disappear and to appear what would be the following item. That is, if you are showing items 3 4 5 and you click on 4, that item would disappear and appear the number 6, meaning the result would be 3 5 6.
The elements being shown are partial views and the button that "deletes" the item is a widget within each partial view.
The user can move through the list of items using some << and >> arrows to go back and forth the result.
One of the options the client gave to me was to show a list of pages ( 1 | 2 | 3 | 4... and so), but deleting items means the number of pages will decrease at some time in the future, plus if the amount is pretty big, I would need something more flexible such as only showing the current and other 4 pages at most. Another option is to keep the << and >> arrows.
I've tried to convince the client that pagination and a "live list" is a pretty bad idea, but he rejected the idea to limit the visualization to only the first 3 items (keeping in mind that eventually you will delete them and thus will be able to see the following items).
I'm developing it using Yii, MySQL and jQuery, and I'm not able to use CPagination because of this living list. I'm not asking the code, just some guidelines because I got lost the third time I tried doing it.
Some basics about the system:
I got a controller which loads the first 3 items of this module.
I got some actions in this controller that fetches the next item within a page (which may not be the same of the current object, though. One of my problems resides here), and the full page.
Each item is able to mark itself as "read", which will make the item not appearing the next time you fetch some results.
Every 1 second I check for items that have been marked as read, remove from DOM and append some new items using the action I defined in the second bullet.
Every time the user hits the << or >>, I reload the previous/next page (That would not be a problem apparently. If you're in the last page and there aren't more items to add, you just remain there. However if you empty the page, I don't have any method to detect that and scroll one page back).
As you may see, this headache would be easier without the pagination buttons, but the client obligues me to put them. What would you do guys? Thanks in advance
EDIT: The client decided to get the results in a random flavor. There is no more pagination, so the problem has disappeared. The #thaddeusmt answer may not have helped me really much, but I'll give it as valid, as it might be plenty useful for other people with similar problems than mine. Cheers
It seems to me like the CGridView or CListView should basically do this automatically. They support AJAX updating/paging out-of-the-box.
I assume that you have an AJAX action that like "actionMarkRead()" which you are calling when the user clicks. I assume that this sets some database field somewhere saying that the user has "Read" that item. To make this work with the CListView, just make sure that the CDataProvider has a condition which checks that "read" field (might have to JOIN a table, I don't know what your DB looks like). Then, when the list reloads via AJAX, it will have the correct # of pages to represent the smaller number of pages the CDataProvier query is returning.
I just tested this and it works!
The way I tested it is I set up a CGridView with 'ajaxUpdate'=>true,. Then in my CDataProvider I set 'pagination'=>1 to make it easy to test. Then I used the default AJAX actionDelete in my Controller to delete the items. Every time I deleted an item via that AJAX action link in the CGridView, the grid refreshed via AJAX and page count shrunk by 1. Seems to work like a charm!
Cheers and good luck!
In a PHP application I'm building, I'd like to have an 'editable' table. The idea is that each row will have an edit button, which, when clicked, will replace certain fields with text fields and select lists and change to a save button. When the user clicks save, the data data should be validated and changed if appropriate.
I'm mainly tackling this as a learning project (I'm aware there's a ton of stuff already out there) and to see if I can get anything 'cool' working. I've created a PHP table-generating class that can take an array of objects as a datasource, and can have columns created based on those class methods.
e.g.
$table = new Table($dataSource);
$table->addColumn('Name', 'getName');
$table->addColumn('Amount Due', array('getOrdersManager', 'getTotalAmountDue')); //First calls getOrdersManager() on each data item and then calls the getTotalAmountDue() on the result
I'd like to try my hand at extending this to be able to the table row and have those changes reflect on the corresponding object in the data source.
I don't really have very much experience with AJAX although it's clearly going to play a very important role in getting this to work correctly.
Any tips on how I should approach such a task?
Edit: I'm not really interesting in looking at Ajax libraries at this point (I do have some experience with jQuery). I'm more interested in learning the basics of Ajax at this point.
my tip is to use jquery(does most of the heavy lifting for you and is easy to learn).
The idea is that each row will have an
edit button, which, when clicked, will
replace certain fields with text
fields and select lists and change to
a save button
http://api.jquery.com/click/
When the user clicks save, the data
data should be validated and changed
if appropriate.
http://api.jquery.com/jQuery.post/
Some things to be aware of/think about:
Are you going to send every field change to the server, or only the whole row (the latter is more resource efficient, but not necessarily as accurate)
How are you going to ensure the data displayed stays accurate even if the update to the server fails for some reason (either a network failure or a DB/validation error)
How will you ensure the user has permission to update the record and that you don't open a security hole by allowing the AJAX responder just to update whatever record it is told to. My approach has been that if a record is shown in the interactive table then the user has the permission to update it, so a cache of record IDs is held in the session when the table is created
Are you going to load options dynamically? If you don't, then a long table can end up containing a lot of HTML because of repetition of the select controls, but again it is more resource efficient not to have a request every time a user clicks into a dropdown. One compromise might be to put the options into a hidden HTML field and load them dynamically into the correct place when a user clicks a dropdown
Over at rsscache they offer a mechanism that caches your website's feed. They claim that if a new node gets added to your feed, instead of flushing and refilling the entire cache(for the current user, they proably do for new users), they only send the new node to the current users newsreader, and the reader adds it within the other nodes, it updates without completely refreshing, saving bandwidth. (see step 6)
Is this correct, I can imagine the cache having a node added, rather then flushed and renewed, but I don't get how this scenario could work in the visitor's feedreader.
If so how can it (selective update to cache and or reader) be achieved with php?
Could this selective node update-mechanism be extended to exclude error nodes, like;
error:node not found
So when random nodes in the mashup feed (lifestream) originating from a specific service, ea twitter, dissapear because the servide is offline, the nodes dont get replaced with the offline error, but their previous state sticks?
Normally feedreaders keep all items ever included in a feed. Or let you configure the maximum age or number of items to keep.
Rsscache.com probably stores the items of a feed and which clients have received which items is a database. With that information it's possible to dynamically create a feed with only items not returned yet.
So when you start reading a feed through rsscache.com all items are returned but in later requests only the new items.
Here's one approach that might work :
Keep a local cache of the feeds, and do conditional GETs (using If-Modified-Since header) based on the date of this cached version (resulting in less bandwidth for the webmaster IF his server supports conditional GETs). Once you have the feed check every item in it to see if it already exists in your DB or not. If it already exists, skip it, if it doesn't then add it including a timestamp to reflect when you added it, and you probably want to remove "dead" items for the feed as well.
Now you need to keep track of the last time someone queried a specific feed on the server. If it's the first time someone asks for a feed, then just return all items you stored in the DB for that feed, and add a record containing user (ip?), feed and the current time. If he's been there before for that feed then select all records for that feed that have been added after his previous query (and afterwards update the last_query time for that specific user and feed to the current time). And if there are no new items simply return an empty feed.