How should changes to MVC objects be propagated? - php

This is a follow-up to a previous question: Should sub-objects be fetched in the Model or the Model Mapper?
Let's say a User can have one or more PhoneNumber objects. According to the answer in the above question, these sub-objects will be fetched upon instantiation of the User. If I were to delete a PhoneNumber from the User's phoneNumbers property (an array of PhoneNumbers), or modify one of the PhoneNumber objects, where should this change be propagated?
Should I manually delete/update the sub-objects in the database, or should the User do that automatically on save? Thank you,

Let's see If I got it the right way.
The user is logged and it's on his profile page. On this page the user clicks a link "delete this phone number".
On the page where the action is performed it will executed DELETE FROM phones ETC.
Now after this is performed when you will load the User, the constructor will load the phonenumber etc and considering you performed the DELETE sql early the current user object will not have, of course, the just deleted phonenumber.
This is at least what happens in my MVC framework.

Related

Symfony3 Entity Field Level Permissions

I'm working on building an API backend with Symfony3 and have a question about how to apply field level permissions to the PUT endpoint for updating an object (User in this example).
My User entity has multiple fields, firstName, lastName, username, etc.
If a PUT request is sent to the /users/{userId} endpoint, I deserialize the request JSON into an array, pass the array (and the User fetched from the database) into a normalizer which applies the request data to the User properties.
I would like an ADMIN to be able to update all fields, but the user themselves to only be able to update their first and last names.
So somewhere in my code I need to check before I apply the updates to the User object, e.g. if the username field is present in the PUT request, I need to check if the requesting user is an admin before applying that update to the user object.
Injecting security into the normalizer seems like an obvious solution, but feels like security should not be a concern of the normalizer.
I could check the permissions after deserializing the request, and before passing to the normalizer, and then just remove fields from the array if the user does not have access, e.g. if not admin remove [username] from array.
Looking for thoughts/suggestions on the right way to accomplish this....
Thanks!
Wanted to post some feedback I got in #symfony IRC:
I would not have the normalizer write into the user. I'd have the
normalizer generate a DTO, which you would then validate given the
permissions of the target user and user taking the action.
If that validator fails, throw the whole thing out and return a
permission denied error, otherwise apply the DTO to the user and
persist it.
the "validator" could be a form (build a form with acceptable to
modify fields given active and target user; form is not valid if there
are extra fields submitted). Or it could be a security voter, or your
own custom mechanism.

logging activity to database yii framework

I'm using yii framework and I want to make an activity logging for every action that user do in my web. All of their activity will be saved to a table in database.
The things that will be recorded are:
user ID
table name (inserted, deleted, edited item)
time_action
activity (what did they do. ex: created project_name)
Please help. Thanks in advance.
I'm not sure what you are trying to do but is it like when a user deletes some item; then entry should be logged in database for that user?
If yes, then you can create a common class and a static method in it like,
yourCommonClass::setActivityLog(user_id,activity_msg,time);
and put this code in every action that you have written. ex. actionUpdate, actionDelete.
you can get the user_id from Yii::app()->user->id
put you custom activity message like "User #user_id created new item" etc.
time you can get it while saving into database.
By the way, create a table and model for the same like ActivityLog. ;)
This is what I did in my project.

Laravel add additional information for user

I'm using Laravel for a little app. In this app I added the auth things of Laravel (verison 5.3), so I automatically got a possibility to register and log in.
So what I got now are a few controllers, 2 vies and a table users, with name, email and password and a unique auto incrementing primary key. What I want now, is to make the logged in user able to add additional information, like City, Street, Telephone, etc..
I don't want to make the user able to add this directly at register. What I want instead, is, that if the user is logged in, he can navigate to a view (lets say its reachable through the route /changeUserData. There, he can find a form. In this form, initally there is no data, he can enter everything (as I said, like City, Street, etc.) and save information. I'd like to save this information in another table in the db, called user_infos, with several columns containing City, Street, Telephone, etc. I'd like to be able to have this second table without a primary key, but with a foreign key - the primary key of the users table.
So the process would be, navigates to the view with the form /changeUserData. Then there is a lookup in the table user_infos, if the logged in user already saved information there. Therefore, I'd need to look up the primary key of the user via the email-adress (unique as well), which is stored in {{auth::user()->email}}. If he didn't save any information there yet, then he gets a blank form, where he can enter everything. Clicking on save, makes a new entry in the user_infos table, containing all information entered, as well as the foreign key got from the users table. If there is already an entry for the user, the information should be already shown in the form inputs, and the user should also be able to edit the information and save the updated information.
I know this was much text. Basically what I need to know is how to really do the database things. So how can I lookup the primary key (respectively the column with the name id) with the email-adress. How can I then create a new row in the other table, containing this id and the information entered? And how can I get the information from the database then to add in to the form inputs? Basically what I found is Eloquent ORM, but I doesn't seem to understand it. Can anybody give me an example of how I can do this?
Please note, that I'm completely new to Laravel, as well as this hole Object - Model thing, this might be the reason, why I'm confused about it.
Have a look at this series https://laracasts.com/series/laravel-5-fundamentals
The Eloquent tutorial: https://laracasts.com/series/laravel-5-fundamentals/episodes/8
The directory structure will probably be a little bit different as it is a slightly older version of Laravel but it will get you started.
Hope this helps!

Adding entries into database instantly or after filling out form

I'm working on a PHP/MySQL application that allows for organization members to be maintained within the database. Currently, upon clicking on a "Add Member" span, I insert a blank entry into the database and return the created ID to PHP. Upon receipt of a valid ID, the application user is redirected via jQuery to an edit page that refers to the newly-created member.
As far as I can tell, this has the following advantages/disadvantages:
Advantages
Can instantly associate purchases/payments with a member upon submitting a jQueryUI dialog, since I already have the ID of that member.
Unifies what would have been separate add/edit screens, so easier maintainability on my side.
Disadvantages
There is a high possibility that I will have stale entries. That is, someone could click on "Add Member" multiple times and not save the new page, therefore causing entries to remain blank.
Not able to enforce as many constraints in the table, since I need to be able to accept NULL for all of the columns.
Am I thinking of all of the scenarios/advantages/disadvantages? Should I make a separate page for adding members, or is it better to accept the stale entries, and possibly add a few checks when I fetch all members to make sure that I'm not displaying a stale entry?
My database function for adding members currently:
public static function addMember()
{
$q = 'INSERT INTO ' . MemberTable::TABLE_NAME
. ' (' . MemberTable::ID
. ') VALUES (null)';
try
{
$db = new DBConnection();
$toRet = $db->execute($q);
}
catch(Exception $e)
{
error_log($e->getMessage());
$toRet = -1;
}
if($toRet > 0)
{
DBSystemEvent::logMessage("Added new member with ID $toRet");
}
unset($db);
return $toRet;
}
EDIT 1: After rereading the question, I need to clarify that members and users referred to in the first paragraph are different. Users refer to the person logged into the application. Members are not able to log into the application. This is similar to a hospital application (patients may not log in or edit their own information; only application users such as nurses or doctors may log in and edit information).
EDIT 2: While none of the given answers completely fit my problem (since I may have to insert into the database without knowing an ID), I decided to accept an answer based on how my question was worded (since making it any more specific may cross into too-localized territory).
It's a common problem - you need to know the ID before INSERT, but it's known only after. So there is only one adequate solution: use GUID (http://en.wikipedia.org/wiki/Globally_unique_identifier) instead of autoincrement ID. Generate guid from PHP code, for example com_generate_guid(), and do not preINSERT empty rows at all. And make relations between tables with GUID fields.
It's little bit unclear to me what exactly is the workflow of your site.
If user comes to you page then I assume that he must login from where you get his ID. If he is new user then he is redirected to userdata.php?id=0 where he enters his data. After submitting you should check if $id=0 and if the user with the same username/id/.. exists (SELECT... WHERE ID=xxx) and warn user to change his username. If no match is found then you can do INSERT and obtain the new ID.
If in future user wants to change his data then after login you can direct him to userdata.php?id=123 (where 123 is his ID). Then you can check if $id>0 and do UPDATE.
If you can, switch to postgresql. This will allow you to use a sequence to provide you with a unique ID without entering empty entities into you database.
Funny enough one of my clients is using the same approach you haven chosen and so far this lead to a lot of maintenance and work load overhead to weed out the empty entries from the db.
If you cannot use a database that offers sequences consider using an otherwise empty table which only atomically gives you unique ids. That way you can already start using the id to prepare relations on the client side and then enter them in bulk into the db when the member is finally created.

Where do you put common data setters in DDD for update/insert?

I have a question regarding Domain Driven Design. Let's imagine a simple scenario.
I have an Entity called "User" that has some properties. One of these properties is "date_created", "date_modified" and "last_login_ip".
Let's say we have a form that creates a user and if the create is successful, it authenticates him.
The controller gets the POST data
Sends the post data to a UsersService via the method "createAndAuthenticateUser"
The service receives the data, validates it (doing it here and NOT in the entity because the validation is tied to repositories, such as to validate if the email already exists, etc).
If the validation is OK, it creates a new Entity, assigns the data to it and then sends the entity to the repository to save it. The repository then saves this user in a datasource.
So far so good. The problem here is that, the date_created/date_modified/last_login_ip have to be set in this service method.
What if I want to set the date_modified ANYTIME when the user object is updated (for instance,at login I want to update the date_modified, at user update i want it again, at user creation I want it again.
Logically, my own answer would be to put this in the repository like...
(meta code here sort of, the syntax doesn't matter)
function save($User) {
if (!$User->id) $User->date_created = 'YYYY-MM-DD HH:II:SS';
$User->date_modified = 'YYYY-MM-DD HH:II:SS';
$DataSource->Save($User);
return $User;
}
However, from what I've been reading, the repository should always just map data between the caller and the datasource (and the reverse) and that's it. It should never SET data or anything like that.
Of course, you could tell me this is a behavior, so I could have a behavior that says $User->markAsUpdated() which would just set the date_modified property. But again, this means that this method must be called from more than one place, instead of having a centralized place to do it. I don't see the benefit of NOT having this code in the repository.
Any ideas?
If the concept of last login ip is actually central to your user for some reason, then it's valid to update the user on login. The fact that you're expressing concern about performing that update to save the last login IP implies that it's not really a user concept, but a security, audit, or otherwise-external-to-user concept.
As for setting the modify and create dates, I'd make the same argument. If it's a requirement of the system that the user both maintain and expose that information, then create a private method on the user that each public method calls when it modifies the state, which will set the modify date. If it's not, then you pretty much have two options - either create an auditing service that is notified of the update and keeps its own audit record, or have the repository set the fields when it updates the record.

Categories