inserting records using a transaction - database

I am trying to insert records in the database using Eloquent. I have the following code wherein I am creating a new user and then inserting a new row in the profile table so that the user update his/her profile as and when he/she logs in.
$user = new User();
$user->fill(Input::all());
$user->save();
$profile = new Profile();
$user->profile()->save($profile);
return Response::json(array('message' => 'Your account has been created.'));
The biggest disadvantage of my code here is - it leaves my tables in a half fried state. For example if the user's record were created but for some reason , there was an issue while creating the profile record, a user can exist where a profile has not been created for him/her.
Is there a way this can be circumvented ? I know I can check for the existence of the profile when I am about to access the user's profile (and create it if it has not been created - with the default values) but I would like to know if there are any other methods apart from this.
I believe using transaction is the way forward, if yes - can you please provide me an example ?
thanks

You can use transaction here:
$user = new User();
$user->fill(Input::all());
try {
DB::beginTransaction();
$user->save();
$profile = new Profile();
$user->profile()->save($profile);
DB::commit();
return Response::json(array('message' => 'Your account has been created.'));
}
catch (QueryException $e) {
DB::rollBack();
return Redirect::to('url')->withInput()
->with('error', 'Error occurred. Try again or contact administrator');
}

You can use this
$user = new User();
$user->fill(Input::all());
$profile = new Profile();
return DB::transaction(function() use ($user, $profile) {
$user->save();
$user->profile()->save($profile);
return Response::json(array('message' => 'Your account has been created.'));
});

Related

CakePhp 3 - All roles of my Users Table are register in my Client Table, but I only want Client role

I'm a newbee in Cakephp and I have to build a project-management interface for the company where I work in internship. My boss gave me the tables and I have to make the associations.
I have 3 main tables :
MyUsers = a User can have a role between this 3 : Associate, Collaborater, Client
Role = Associate, Collaborater, Client
Client = a "subpart" of the MyUsers table for save informations of Clients.
When I create MyUser and attritute the Client role I would like to register a new Entity in the Client Table. At the moment I tried this in the add function of MyUsersController:
public function add()
{
$myUser = $this->MyUsers->newEntity();
if ($this->request->is('post')) {
$myUser = $this->MyUsers->patchEntity($myUser, $this->request->getData());
if ($this->MyUsers->save($myUser)) {
$clientsTable = TableRegistry::get('Clients');
$client = $clientsTable->newEntity();
// association id user au client
$client->user_id = $myUser->id;
if ($clientsTable->save($client)) {
debug('Yeah !');
}
$this->Flash->success(__('The my user has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('The my user could not be saved. Please, try again.'));
}
$roles = $this->MyUsers->Roles->find('list', ['limit' => 200]);
$this->set(compact('myUser', 'roles'));
}
Obviously it doesn't work because the role 'Client' is assigned at the time of creating the user. With this function all my Users are register in the Clients Table without role distinction.
Do you have any idea how to do to have only Users with Client role?
This is the first time I'm posting here so please tell me if you need any other part of code :)
I hope my English is not too bad :/
Thank's :)
I have trouble getting the problem right I think. But to recap it: You simply want to create "clients" record for an user IF the role is client? So you have a "User has one Client" association.
Assuming this is right, you want to read the Saving Data chapter of the documentation. You must have setup the associations before. If you don't know how to do that read the Associations chapter.
From where does the client data come from? And the role? Based on assumptions:
$myUser = $this->MyUsers->patchEntity($myUser, $this->request->getData());
if ($myUser->role !== Roles::CLIENT) {
$myUser->unsetProperty('client');
}
$this->MyUsers->save($myUser);
Client data is expected to be in $myUsers->client if the form (pure assumption) is containing the data. If not you can just add it there so the ORM realizes it should create a new client record.
I don't think you have understood the basics of the framework and recommend you to do the tutorials first. They'll teach you the required knowledge to deal with the basics of the ORM.

How to create user in database manually in Yii2?

I do import of users from a csv file to the database. In csv file I have some kinda username and password string. So how do I create a new user manually?
As I understand I need to getPasswordHash and generateAuthKey (last one generates random string). But probably I loose something important since when I try to log in I get an error that Username or Password is incorrect. Did anyone ever experienced such situation? Thanks in advance.
This should be the minimum required in your case. $username and $password are raw values taken from the CSV. Remember that there will be validation applied.
$user = new User();
$user->username = $username;
$user->setPassword($password);
$user->generateAuthKey();
return $user->save();
I think you forgot to set an active status of new User. You should check it in Login method of User model in your app, or in actionLogin of SiteController. For example, in my app the login method is:
public function login()
{
if ($this->validate() and $this->getUser()->status !== User::INACTIVE_STATUS) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
}
return false;
}
If you show your code we can help you faster)
So if you are importing a list of users from a csv file, you will probably process this in a loop, try:
foreach ($csv_data as $user_data) {
$user = new User();
$user->setPassword($password);
$user->username = $user_data->username // or anything else, depending on your code
$user->status = 1 // or = User::STATUS_ACTIVE, depending on your code
$user->save();
}

Troubles with logging in with a newly created user

I created a CRUD that allows me to create users, societies and schools in a back office.
However, for an unknown reason, I can't log in with a created user with the password I gave him.
Here is my controller (the part where the user is created)
/**
* Creates a new User entity.
*
* #Route("/new", name="user_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$user = new User();
$form = $this->createForm('UserBundle\Form\UserType', $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$password = $this->get('security.password_encoder')->encodePassword($user, $user->getPassword());
$user->setPassword($password);
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_show', array('id' => $user->getId()));
}
return $this->render('user/new.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
}
After registering a new user, when I check it in the fos_user table, I can see that the password has been encrypted. However, if I try to login with the password I used, I simply get "bad credential" from my login form.
I can't figure out why.
Tell me if you need to see another file, I'll update my question
Any idea ?
Thank you in advance
The correct way to create user and set password in FOSUserBundle is the following:
$userManager = $this->container->get('fos_user.user_manager');
$userAdmin = $userManager->createUser();
$userAdmin->setUsername('System');
$userAdmin->setEmail('system#example.com');
$userAdmin->setPlainPassword('test');
$userAdmin->setEnabled(true);
$userManager->updateUser($userAdmin, true);
Password is kept encrypted in database. And to make it harder to bruteforce, database contains an additional field, named salt. You don't store it in your code, that's why it's impossible later to check password. But actually, you don't have to encrypt password and store it in database. User model contains a special method for it, setPlainPassword, which is intended to encrypt password populate both fields salt and password in database with correct values.

Phpunit password comparison

I would like to test a login function that one of the developers produced. What I would like to do is have test-users be created in my setUp and then I would like to use these users to test the login function. I would like to see that it returns the correct boolean when username and password are equal to the ones stored in our database. My problem is that when I am inserting my users at the moment I am giving the passwords in plain-text hence they are being stored in the database in plain-text, however there is an issue here. The login function hashes the password as you are trying to log in as the passwords in the database are hashed when registration is done. So basically the plain-text password I just inserted will never be matched since the login function hashes the password in an attempt to find a match. So what I would need to do is hash the test-user's password as I insert it. How would I go about doing this? This is what my code looks like at the moment:
<?php
include 'functions.php';
class Test extends PHPUnit_Framework_TestCase {
protected function setUp(){
global $mysqli;
$mysqli = new mysqli('localhost', 'xxx', 'xxxxx', 'xxxxx');
$mysqli->query("INSERT INTO members (id, username, pnumber, password) VALUES ('200', 'testbrute', '920314', 'xxxxx')");
}
public function testLogin(){
global $mysqli;
$correctPass = Login('920314','xxxxxx', $mysqli);
$this->assertTrue($correctPass);
$wrongPass = Login('920314','xxxxxxxxx', $mysqli);
$this->assertFalse($wrongPass);
$NoUserExists = Login("980611-5298","--..--..--", $mysqli);
$this->assertFalse($NoUserExists);
}
protected function tearDown(){
$mysqli = new mysqli('localhost', 'xxx', 'xxxxx', 'xxxxx');
$mysqli->query("DELETE FROM members WHERE id IN (200)");
}
}
?>
This is what the login function looks like:
function login($pnumber, $password, $mysqli) {
// Using prepared Statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password, salt FROM members WHERE pnumber = ? LIMIT 1")) {
$stmt->bind_param('s', $pnumber); // Bind "$pnumber" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
$stmt->bind_result($user_id, $username, $db_password, $salt); // get variables from result.
$stmt->fetch();
$password = hash('sha512', $password.$salt); // hash the password with the unique salt.
if($stmt->num_rows == 1) { // If the user exists
// We check if the account is locked from too many login attempts
if(checkbrute($user_id, $mysqli) == true) {
// Account is locked
// Send an email to user saying their account is locked
return "account locked";
} else {
if($db_password == $password) { // Check if the password in the database matches the password the user submitted.
// Password is correct!
$ip_address = $_SERVER['REMOTE_ADDR']; // Get the IP address of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
$user_id = preg_replace("/[^0-9]+/", "", $user_id); // XSS protection as we might print this value
$_SESSION['user_id'] = $user_id;
$username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username); // XSS protection as we might print this value
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512', $password.$ip_address.$user_browser);
// Login successful.
return "login successful";
} else {
// Password is not correct
// We record this attempt in the database
$now = time();
$mysqli->query("INSERT INTO login_attempts (user_id, time) VALUES ('$user_id', '$now')");
return 'pass incorrect';
}
}
} else {
// No user exists.
return 'no exist';
}
}
}
I am new to phpunit and testing in general so please be overly-descriptive.
Forget trying to test against the actual database. As a general rule, you don't want to have your tests dependent on external services if you can help it.
You can inject a mock mysqli object and specify it's behavior. Then you don't have to worry about any values being added to the database or are dependent on having the database even exist.
So in your test rather than declaring a global $mysqli do:
$mockMysqli = $this->getMockBuilder('mysqli')
->disableOriginalConstructor()
->setMethods(array('prepare'))
->getMock();
$mockMysqli->expects($this->once())
->method('prepare')
->will($this->returnValue($mockStmt) //Have to also create a mock mysqli_stmt object
Based on how your function is, you will end up with a few mock objects returning other mock objects which is a code smell that you function is doing too much. Because of this, you would be better off breaking it up into smaller pieces that can then be mocked and tested separately. I find that generally speaking if the function is hard to test, that it is not a good design and should be refactored. Most good designs end up being easy to test with one or two mock objects.

I can't log in in Kohana 3.2 ORM Auth module?

Well, thats a trouble. The code is simple:
public function action_index()
{
$post = $this->request->post();
if ($post) {
// if I type it like this, manually - it will work
$success = Auth::instance()->login('admin','password');
}
if (isset($success) and $success) { echo "Пользователь залогинен"; }
}
Unfortunately it log in only a first record in the database, which is admin as by default config was in the table, If I create a new user. Like this:
$auth = Auth::instance();
$user = new Model_User();
$user->username = "Victor";
$user->$auth->hash_password('psw123');
$user->email = "me#email.com";
$user->save();
And than use it like I said, only with a real data as
$post["email"] or $post["username"] with $post["password"]
code:
if ($post) {
// the values from posts: 'Victor' or 'me#email.com` & 'psw123'
$success = Auth::instance()->login('me#email.com','psw123');
}
it will not log in me.
upd I can't login as admin, but all working perfectly if I'll change the role to login (it's 1 in the database). But if the role will be set to 2 (it's an admin role) it will not accept me, even do not make an instance of Auth.
$post = $this->request->post();
$success = Auth::instance()->login($post['email'], $post['pass']);
if ($success)
{
echo "SUCCESS!";
}
Once again, if the role will be 2 (it means admin) this is not will Success me instead of login role.
What can be a reason of this trouble?
I'm assuming you're using a default ORM auth driver. You don't need to hash your password when saving a new user - it is done automatically by a filter in the model. So saving a new user should look something like that:
$user = ORM::factory("user");
$user->username = "Victor";
$user->password = "psw123";
$user->email = "me#email.com";
$user->save();

Resources