Hey Guys I have researched and have tested few method for logging user activity such as when an user updates his profile details or when an user updates his status in a task.
What I require to log :
User ID from session
Table being updated
Field Name
Old Value
New Value
Timestamps
Method 1:
Run an additional query along with the insert/update/delete query to store details.
Method 2:
Using http://packalyst.com/packages/package/regulus/activity-log
In both the above methods I have to write multiple code for each create/update/delete I would like to know if there exist a better way to handel this problem.
You want to store revisions of the data being manipulated by the user.
This calls for Revisionable.
Revisionable works using trait-implementation. Every action made by the user, will have the old and new value of the column stored in a seperate table. You can then query the revisionable table to get the changes made by the user.
Please note that the Revisionable version quoted above, doesn't store INSERT actions.
A few days ago I've created such package, which, unlike VentureCraft's one, logs only static data - tables, values. No fks, no model names etc.
Also it handles the revisions in different manner, which makes it much easier to eg. compare given 2 versions, since it doesn't log single field change per row, but all the data involved per row.
Check this out: Sofa/Revisionable
This is pretty young and will be improved.
It's also not Eloquent specific, but it works out of the box with Laravel 4. You simply download it, adjust config if needed, add a few lines of code to your models and it's ready to go.
Related
I want to make a log details for my database while a record insert into any table and update any table and delete any record from an table in MYSQL - PHP. Please give me some ideas.
You've used laravel tag, so I assume you want to find a 'Laravel way' to do it.
The best practice is to use Eloquent Events.
Each time when Laravel will hit the DB, it will try to run some of these events: creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored
-ing events are used before hitting DB, -ed events are used right after hitting DB.
Example:
public function boot()
{
User::created(function () {
Log::info('User was just created successfully');
});
}
Read this Tutorial carefully i think its work for you
http://web.stanford.edu/dept/its/communications/webservices/wiki/index.php/How_to_create_logs_with_PHP
One solution is writing a helper function that logs successful insert/update sql queries if you have full control over your PHP application. A helper function can be called on every instance of insert/update queries which logs the features of the sql query you have. Some features for example can be the table name, the record id, and the type of operation i.e. insert or update, along with the system date.
In the module I have developed and have the link for below, these features are extracted from the original sql query automatically. This is one solution to the logging problem.
Here is my working solution. See the repository's Readme file to see how to add the module to your PHP application
Here is how it works:
We pass our original sql query to a function in the logging module;
The function will extract sql features from the query;
It will save all features to the log table we have setup in the database, along side system date and IP (Other features can be extracted also);
To see the logged data (as an interface to what we have logged):
We call the main function in the front-end side of the module;
This main function will get as parameter the number of most recent log records it should return;
It will present the log records neatly, for example it will collect repeat number of operations on same record in to one entry. The CSS styling can be adjusted as needed.
The whole interface can be minimized or restored using a show/hide button.
I have a business listings website. I am currently building an interface for users to log in and update their listings.
The functionality I would like to implement is as follows:
user edits listing and submits
the edits are sent to admin for approval
in the meantime the existing listing remains on the site
admin reviews the edits and corrects any mistakes before approving
Now usually something like this can be accomplished by storing a 'duplicate' row in the database, with a flag set to 'pending'.
However if possible I would like to try a different approach, as the listing data is stored across several tables, including one which contains multiple category selections.
So ideally I would prefer not to create additional database records. Is there a better alternative I could use?
There are actually 2 different approaches.
Use the database (either in the same tables, or some "pending changes" tables with almost the same structure as the original ones), although one way or another it creates records.
Don't use the database at all, but some intermediate store (key / value store; message queue; memcache; email;just some files; whatever comes to mind ;))
With option 2 you can easily do as the 2 commenters on your question already said: create a data structure and serialize this structure and store it anywhere until the admin "approves" the data and updates it in the database.
At first glance the second option would of course be quicker to implement, although implementing it in the database could give you the ability to "rollback" changes by using a current or state flag. Secondly, imho, you want to keep all your (related) data close together to keep it maintainable
Got a big problem that's confusing as hell. I'm using Laravel (3.2.5 and now 3.2.7) and I'm using the Eloquent ORM for updating a database (PostgreSQL).
Here's what I'm doing:
I have a db full of data
I'm pulling info from an external API to update my db full of data
I run a script that puts the db full of data into arrays and same with API. This gets compared
I fill a data object with an array full of changes
I "save" it
nothing happens -.-
$updateLinks = array_diff($dbLinkArray, $dbLinkArrayOriginal);
$dbLink->fill($updateLinks);
Log::info('1st LOG Original: '.$dbLinkArrayOriginal['link_text'].' New: '.$dbLinkArray['link_text']);
Log::info('2nd Log Dirty: '.implode(', ', $dbLink->get_dirty()));
$dbLink->save();
Log::info('3rd Log Supposed to be changed: '.implode(', ',array_keys($updateLinks)));
I employed some logging and the debug toolbar to figure out wtf happened. Here's the info:
all the SQL queries run to update with correct information. When the Query is run via phpPgAdmin, it updates as it should. The problem here is that the query updates EVERY column in the row instead of just the changes. Using "update" instead of "fill/save" creates the same problem.
none of the table information gets updated, ever.
The 1st log shows that the link_text isn't equal. This is okay because it shows the link_text needs to be updated. However, it's a clear indicator that nothing was updated the next time I run my script. The log shows the same info every time and just as many log events happen.
The 2nd log shows that the ENTIRE object is dirty rather than just what was supposed to be updated. This is why the SQL gets updated
The 3rd log spits out exactly what's supposed to be updated. 3-5 columns max and that's it. And all is in correct format.
Any idea why, first of all, the database is not getting updated even though Laravel marks the SQL as being run and shows the correct query?
Also, any idea why the ENTIRE object is dirty and the query tries to update the entire object (23+ columns) instead of only the changes (3-5 columns)?
For your second question (why all columns update, instead of just the dirty ones). The Laravel documentation states:
By default, all attribute key/value pairs will be store during mass-assignment. However, it is possible to create a white-list of attributes that will be set. If the accessible attribute white-list is set then no attributes other than those specified will be set during mass-assignment.
Does this help you?
Kind regards,
Hendrik
First, I've been using CakePHP for a long time, and I'm very comfortable with the API. I'm pretty sure this is going to be a face-palm error, but I'll need some fresh eyes on this because I've been stuck for over an hour.
I have three models, User, Job, and Company.
Company hasMany User
Company hasMany Job
Sometimes, when a user is updating a job record, the user needs to change the job's company_id field. When this happens, I also have a requirement to change the user's own company_id field. So, in effect, the User and the Job will both be re-assigned to a different company.
In the CRUD update method of the JobsController, I have added this logic:
$this->Job->User->read(NULL, $this->Session->read('User.id'));
$this->Job->User->set('company_id', $this->data['Job']['company_id']);
$this->Job->User->save();
I have verified using typical debugging techniques, like var_dump() that $this->Session->read('User.id') contains a proper value, and $this->data['Job']['company_id'] contains the correct value that was submitted from the form helper.
The correct User record is updated, because the modified timestamp in the table indicates that it is so, but the company_id field is set to NULL instead of the correct company_id from the data array.
Interestingly, after the above snippet I save the Job record, and it does get updated with the correct company_id (using the same $this->data array).
It's just $this->Job->User->save() that seems to pass a NULL value to the table.
<facepalm type="lame">
Turns out a new junior dev monkeyed with the code at a further point in the application flow. This dev was trying to complete the same ticket, and incorrectly executed a save method loaded with NULL data (after the job data save, which is why I didn't notice, since I was working before the job save...).
At any rate, walking down the SQL dump made me find the error, so credit should be given to #dhofstet for pointing me down the right debug path. Thank goodness for version control.
</facepalm>
Have you checked that $this->data['Job']['company_id'] is not null?
Maybe there is some problem with validation. Have you tried saveField instead set & save?
Why so complicated?
a simple
$this->Job->User->save($this->data);
will to the trick
assuming you fill up the array with [User][company_id] etc
I work on a market research database centric website, developed in PHP and MySQL.
It consists of two big parts – one in which users insert and update own data (let say one table T with an user_id field) and another in which an website administrator can insert new or update existing records (same table).
Obviously, in some cases end users will have their data overridden by the administrator while in other cases, administrator entered data is updated by end users (it is fine both ways).
The requirement is to highlight the view/edit forms with (let’s say) blue if end user was the last to update a certain field or red if the administrator is to “blame”.
I am looking into an efficient and consistent method to implement this.
So far, I have the following options:
For each record in table T, add another one ( char(1) ) in which write ‘U’ if end user inserted/updated the field or ‘A’ if the administrator did so. When the view/edit form is rendered, use this information to highlight each field accordingly.
Create a new table H storing an edit history containing something like user_id, field_name, last_update_user_id. Keep table H up-to-date when fields are updated in main table T. When the view/edit form is rendered, use this information to highlight each form field accordingly.
What are the pros/cons of these options; can you suggest others?
I suppose it just depends how forward-looking you want to be.
Your first approach has the advantage of being very simple to implement, is very straightforward to update and utilize, and also will only increase your storage requirements very slightly, but it's also the extreme minimum in terms of the amount of information you're storing.
If you go with the second approach and store a more complete history, if you need to add an "edit history" in the future, you'll already have things set up for that, and a lot of data waiting around. But if you end up never needing this data, it's a bit of a waste.
Or if you want the best of both worlds, you could combine them. Keep a full edit history but also update the single-character flag in the main record. That way you don't have to do any processing of the history to find the most recent edit, just look at the flag. But if you ever do need the full history, it's available.
Personally, I prefer keeping more information than I think I'll need at the time. Storage space is very cheap, and you never know when it's going to come in handy. I'd probably go even further than what you proposed, and also make it so the edit history keeps track of what they changed, and the before/after values. That can be very handy for debugging, and could be useful in the future depending on the project's exact needs.
Yes, implement an audit table that holds copies of the historical data, by/from whom &c. I work on a system currently that keeps it simple and writes the value changes as simple name-value string pairs along with date and by whom. It requires mandatory master record adjustment, but works well for tracking. You could implement this easily with a trigger.
The best way to audit data changes is through a trigger on the database table. In your case you may want to just update the last person to make the change. Or you may want a full auditing solution where you store the previous values making it easy to restore them if they were made in error. But the key to this is to do this on the database and not through the application. Database changes are often made through sources other than the application and you will want to know if this happened as well. Suppose someone hacked into the database and updated the data, wouldn't you like to be able to find the old data easily or know who did it even if he or she did it through a query window and not through the application? You might also need to know if the data was changed through a data import if you ever have to get large amounts of data at one time.