cakePHP - creating new user account, several problems - validation

I have two tables, users and tokens.
Each user have a activated field and each token have the {id, token, user_id, created} fields.
The way the app should work is:
On the creation, the app will -
make sure that the activated field is empty (to avoid manipulations to the submitted data).
a token will be created in the tokens table.
On update, the app will -
NOT create a new token.
NOT allow an update of any kind to the activated field.
check if a new email has been submitted, and if so: will create a new token and set the activated field to false.
I know how to activate the account through the controller and how to setup the router for that.
What I need is mainly the model configuration.
For example:
I think that the token creation should be done in the afterSave method, so - how do I determine if the method is called by an update or by a create operation?
Thanks for any help

yossi you can also specify the fields that should be saved from the form though - a whitelist of fields it is ok to save in you $this->save() call. That way you can stop a hacker passing an ID in the request, and you should just set it in the controller yourself then with $this->Token->id = whatever you have, I would personally use saveField ('activated) in conjunction with this (just saves a single field!). Fat models is best if you can but get it working first then refactor it if you have got stuck. Better than wasting lots of time writing perfect first time.

You question is unclear. If you have a default value for a field, then why not set it in the database rather than doing something in aftersave? If you need to do something that should be done only in certain circumstances, then write a custom method in your model to perform the tasks you want either on creation or update.
Edit
So, if your record has an id, then you know it exists in the database. So, the simple thing to do is (in any method) check to see if the model has an id field and that it is not empty. If it's empty, then you know that you are creating a record and you can do x task. If it isn't, then do y task.
if(isset($modelData['ModelName']['id']) && !empty($modelData['ModelName']['id'])){
//This is an update
} else {
//This is a new record
}

Related

Why does Laravel group RESTful methods the way they do?

I'm brand new to Laravel and am working my way through the Laravel 6 from Scratch course over at Laracasts. The course is free but I can't afford a Laracasts membership so I can't ask questions there.
I've finished the first several sections of the course and am a little confused about some of the concepts around the whole RESTful idea. The instructor, who seems very good and experienced with Laravel, describes 7 methods that are going to be part of pretty much any CRUD (Create Read Update Delete) application (and most applications are CRUD in nature.) He says naming of these 7 methods should be consistent with this:
index - a list of all the resources in a collection e.g. all articles in a blog
show - display a specific resource from a collection e.g. a specific article in a blog
create - create a new instance of a resource e.g. add a new article to a blog
store - save a new instance of a resource to a data store like a database
edit - modify the contents of an existing resource e.g. change the title of an article
update - save the modified resource to a data store
destroy - remove a resource from a collection e.g. delete a blog article
I'm a little puzzled by this division of work into 7 separate methods. It seems to me that Create and Store belong together in a single method; ditto for Edit and Update. Creating a new record has two phases: displaying an empty form to gather up the data needed to construct a new article, then validating the data and storing it on the database. By the same token, changing an existing record consists of two phases: displaying the current data in a form and letting the user change what needs changing, then validating it and sending it to the database (or back to the user for corrections).
I would also argue that to be consistent with the approach they've used for create/store and edit/update, destroy should be divided into two methods, Destroy and Remove, where Destroy displays the full record that the user wants to remove with two buttons at the bottom: Delete and Cancel. Then, if the user clicks on Delete, they go to a Remove method that actually deletes the record f from the database.
I've been coding for a fair while and I've never seen a system where the user was allowed to delete any important record without first being shown the record and being asked if they're sure they want to delete it. Now, maybe that's fallen out of fashion and I didn't notice but it seems a pretty prudent thing to do.
So why are the methods what they are, at least as RESTful is implemented in Laravel?
It seems to me that Create and Store belong together in a single method
Well, Laravel generate all those methods thinking in a server-side rendered app. So in a SSR, before you store your data, you must be able to see a creation form.. that's why this create() function exists. The create(), normally, should return a view that will show the user the valid fields to create a resource, this is all done in a GET request. Then, when the users hit the "create"/"add" button, it will reach the store() method that will implement the logic to persist this data storing a new record in your database, this is done in a POST request.
The same goes for edit()/update().
I've been coding for a fair while and I've never seen a system where the user was allowed to delete any important record without first being shown the record and being asked if they're sure they want to delete it
That is because those validations are commonly implemented in the client-side, so, you do this with JS in your front-end, for validations of that kind you shouldn't hit the server.
So why are the methods what they are, at least as RESTful is implemented in Laravel?
Finally, for a RESTful API you don't need all of those methods. Just index, show, store, update and delete ones. If you just need this kind of methods in your controller, you could exclude the create/edit ones by adding the --api flag when creating your controller through Artisan. From the documentation:
API Resource Routes
// ...
To quickly generate an API resource controller that does not include the create or edit methods, use the --api switch when executing the make:controller command:
php artisan make:controller API/PhotoController --api

Adding attribute to a user when register in Laravel 5.1

When a user Register, I want to add location data for the user.
I get those with GeoIP.
So, each time a user is created, I would like somewhere to add Country, City, etc.
I was thinking about setting Hidden fields in view, but I think it a hugly way to do it, and I'm sure there is a better way to do...
Any Idea???
Any time I create a record that needs extra data, involves inserting additional records into additional tables, etc, I create a service class. Something like "UserCreator" then I pass it the input, do any additional operations, wrap multiple database calls in a transaction and so on.
That said there are so many ways to do what you want. You could Input::merge(...) then save, you could separate the process of creating a user from your controller / route function, etc.
If you are just getting started with Laravel and/or your project is rather simple, then you probably want to look at Input::merge
I solved it using Request Contructor as said here in laracast
In the Form Request's constructor I inject \Illuminate\Http\Request. I can then add my value to the request instance as such:
public function __construct(\Illuminate\Http\Request $request)
{
$request->request->add(['date_of_birth' => implode('-', $request->only('year', 'month', 'day'))]);
}

Couchdb conceptual problems

As I understand, to update any object with couchdb. I have to send the whole object back since it is actually "inserting" a new revision for the same id. This is all neat and works quite well.
But then I have a problem, I'm not so sure how should I handle that. I have an object that can't be sent to my user completely. I have to hide certain informations such as password hash.
The data is sent to the client, the revision is sent too. Now when I try to update my object I have one problem. Since some data is missing, the update will erase the attributes that are missing from my user.
That said, the easiest way I have is to get the object from couchdb, check if id and rev matches. If it does match, merge the object with the missing attributes. It will work pretty well and I can support deleting attributes too.
Then using this technique, I could add my objects to a cache that will reduce the time to query frequent objects from the database. If the object can be updated, then clear the cache for that id. If the object is newer, then I'll have to handle the error or merge the object.
Is there any better "good way" to handle this problem?
edit
After thinking about it during the night, I think I found a much much better solution. Instead of having my username and password inside my profile. I'll separate the identification object from the use profile.
In other words, I'll have to split up the object as much as possible to keep things isolated... On the plus side, I can add multiple authentication for one profile without messing with the profile itself. I can return profiles and anything necessary without returning any secret object.
It will complicate a bit the logic of insertion but it should be quite easy...
Get 1 id from couchdb using the uuid api "_uuids"
Insert password authentications (username, password, profile_id) using that uuid
If succeed, insert profile using the uuid that we got at 1
If anything wrong happen, rollback and tell the users what's wrong.
Also the nice thing about this method is that I can add access_token for oauth2 using the profile id and the logic will be almost the same as password, the auth type will differ but any auth type should work almost the same.
Yeah, extracting the secret stuff from the profile documents sounds like the way to go.

CakePHP Auth Loads Too Many Session Variables

Using CakePHP2.0 Beta I managed to write a custom login handler for my existing database schema. All's well, except that upon logging in I printed out the session variables stored and what Cake's Auth component did is store the entire record from the "Member" table (where my usernames+hashes come from) in session. It is storing an array with data fields that are totally irrelevant to the session. For instance it stores the date the member was created, their address, etc. All pretty useless information for me as I basically only need their ID and maybe username, name, email address.
The offending lines for me are found in: /lib/Cake/Controller/Component/AuthComponent.php line 512. It states,
$this->Session->write(self::$sessionKey, $user);
So my custom authenticate component returns $user and it throws this whole thing into the session. Now, I don't want to go about editing in the core libraries because this project is definitely going to be upgraded when 2.0 comes out. Is there any way to store less information in sessions? I want to keep this whole thing more lightweight.
Possible solution: Change my custom authentication component to only return the fields I need into the $user variable. Are there any concerns about what data I should/shouldn't be returning?
I've solved the problem using my "possible solution". In /app/Controller/Component/auth/MyController.php, I changed the "ClassRegistry::init($userModel)->find" method to have a parameter for 'fields' where I specify only the fields I need. Works like a charm.

MVC 3 Remote Validation, problem with duplicate check in Edit view

I am using remote validation to make sure that the email and username fields in a user class stop a user from entering a username and/or email that already exists within the database.
This works fine on the create view, however the obvious problem I run into in the edit view is that when I try save some changes for a given user - I get the same validation messages on the username and email saying that they already exist in the database! Therefore stopping me from editing anyone because their emails and usernames already exist.
I have been looking around and was surprised that I could not find a similar problem to mine. I have seen many examples of dupliate name/email/value validation on create pages but nothing on the inevitable problem that will arise in the Edit view.
Any hints/tips on a way around this would be greatly appreciated. Maybe there is a way to make the validation only work in the create view? Though ideally, I want the validation in the edit view, just excluding the user's own name and email in the validation checks.
Thanks in advance for any answers!
You should use view models. Those are classes which are specifically designed to meet the requirements of a view. Controller actions should take/pass only view models to views and never your domain models. So you will have two controller actions, one for inserting and one for editing, and two corresponding view models with their respective validation rules.
The way I've gotten around the problem is having 2 different validation methods; one takes a single argument (the user name) and one takes 2 arguments (the new user name, the original user name). The Edit method validates against the 2 argument method, where it looks for the new user name unless it matches the original user name.

Resources