sonicsleuth / mvc-framework-php

A Model-View-Controller framework written in PHP. Easy Install. Auto/Pattern-Routing, Schema Mapping Models using PDO.
MIT License
3 stars 1 forks source link

how to Vendor/Autoload/Composer with framework #4

Closed jackttcoms closed 6 years ago

jackttcoms commented 6 years ago

i want to use the php mailer library etc but with this framework where abouts do i call it, like what file etc?

Also please can you explain further about the update/select/insert functionality and whether or not i am doing it correctly!

Here is a sample insert (do i need the return true?):

    public function register($data)
    {
        $date = date("Y-m-d H:i:s");
        $profile = 'default.png';
        $this->lastlogin($data['email']);
        $data1 = [
                "name"  => $data['name'],
                "username"  => $data['username'],
                "email"    => $data['email'],
                "password"    => $data['password'],
                "joined"    => $date,
                "profile"    => $profile
                ];
        $this->db->insert("msi_users", $data1);
        return true;
    }

Here is a sample update (the login_amount + 1 is the bit that won't work):

    public function lastlogin($email)
    {
        $date = date("Y-m-d H:i:s");
        $ip = $_SERVER['REMOTE_ADDR'];

        $update = array(
           "last_login" => $date,
           "last_ip" => $ip,
           "login_amount" => 'login_amount + 1'
        );
        $bind = array(
            ":email" => $email
        );
        $this->db->update("msi_users", $update, "email = :email", $bind);
        return true;
    }

Here is a sample select (seems to work fine):

    public function login($email,$password)
    {
        $bind = [':email' => $email];
        $results = $this->db->select('msi_users','email = :email', $bind);

        $hashed_password = $results['password'];
        if ( password_verify($password,$hashed_password) ) {
            $this->lastlogin($email);
            return $results;
        } else {
            return false;
        }
    }

Thanks

sonicsleuth commented 6 years ago

Using the CRUD Model methods (also known as an ORM) are well documented in the core/Model. The key function they provide is auto-pairing to the db table schema. When you pass in a $data array, only those key names that match table column names are processed, all others are dropped. Each of the CRUD methods builds an SQL statement and passes it to the core/Model -> run() method. You can also call the run() method directly if you need to build complex SQL queries like table joins etc. Again, check out the method comments which contain examples.

This is a code error: "login_amount" => 'login_amount + 1' // this is just a single string inside quotes. Should be: "login_amount" => login_amount + 1 // this is an addition statement, no quotes, var + 1.

To use the default PHP mailer function I would make a Mail Model class with various functions to clean and protect the incoming data before emailing it (prevent hacking). Then call your send() method in this new Mail class from any controller you need it. Remember to instantiate your Mail Model to use it in any Controller. Remember, Model classes should be the main focal point for how you want to manage data/documents/email/ ... anything external to the application. That's best practice coding.

Also, if you have small common functions used in the application, you can create Helpers - see /app/helpers/ directory. There make your helper files as needed then include them into your Controller as needed.

jackttcoms commented 6 years ago

Thanks very much and

I thought/tried that before but then i got an error so assumed it must be the wrong way: Notice: Use of undefined constant login_amount - assumed 'login_amount' in /customers/a/d/5/domain.com/httpd.www/app/models/Users.php on line 98 Warning: A non-numeric value encountered in /customers/a/d/5/domain.com/httpd.www/app/models/Users.php on line 98

This is how i used to do it:

        public function lastlogin($email){
            $date = date("Y-m-d H:i:s");
            $ip = $_SERVER['REMOTE_ADDR'];
            $this->db->query('UPDATE users SET last_login = :lastlogin, login_amount = login_amount + 1, last_ip = :ip WHERE email = :email');
            // Bind values
            $this->db->bind(':email', $email);
            $this->db->bind(':lastlogin', $date);
            $this->db->bind(':ip', $ip);

            // Execute
            if($this->db->execute()){
                return true;
            } else {
                return false;
            }
        }

And now this is my code:

   public function lastlogin($email)
    {
        // Update user data everytime login
        $date = date("Y-m-d H:i:s");
        $ip = $_SERVER['REMOTE_ADDR'];

        $update = array(
           "last_login" => $date,
           "last_ip" => $ip,
           "login_amount" => login_amount + 1 //This generates the error
        );
        $bind = array(
            ":email" => $email
        );
        $this->db->update("msi_users", $update, "email = :email", $bind);
    }

Thanks again for being so helpful! I'm still getting used to the framework but slowly getting there. I'm planning on building tonnes of applications with it such as a blog and forum! (blog almost done)


One final thing, how would you suggest i have access to user details all the time. At the moment i am using sessions for the id/username/email but that is all. I don't want to place everything in sessions as for example if i change the users role from user to admin they would have to log out and then back in again so how do i/where do i place a piece of code like how i used to do it on my old script so that its globally (would i place it in the construct?)...

if($user->is_loggedin()){
    $userDetails = $user->details($_SESSION['uid']);
}

$user was the class/model and then i used to go <?php echo $userDetails['plan_id'];?> and get live details but how would you suggest i do this so its global on every page because otherwise my user authentication and roles/permissions are screwed!

Thanks again so much!

sonicsleuth commented 6 years ago

The value of login_amount is not being defined in your lastlogin() method from what I see in your example. If this is a "counter" set on your table then you could make a new method that needs to look up the current value of login_amount where email = X and use that to set it.

This original code you have...

$update = array( "last_login" => $date, "last_ip" => $ip, "login_amount" => login_amount + 1 //This generates the error );

Could become...

$currentAmount = this->getLastLoginAmountByEmail($email)
$update = array(
          "last_login" => $date,
          "last_ip" => $ip,
          "login_amount" => $currentAmount + 1;
       );

With a sub-function of...

public function getLastLoginAmountByEmail($email) {
     get the current value of login_amount from the table,
     then return that value.
}

Alternatively, I would set the value of login_amount into a session value upon login so you don't need to look it up every time.


Your question about where to store user data, in the session? Is an architectural choice. Typically, you should develop a Session Db table to store all user session values (encrypted of course) then only store a unique session ID in the user's session. This will allow you to add unlimited data to the session as well as destroy it or update it as an admin while the user is logged in. Do some Google'ing on PHP Database Session management to learn more.

PS: I am leaving on vacation for a few weeks later tonight. I won't be available for support then. Have a good time building your app.

jackttcoms commented 6 years ago

Thanks very much! Enjoy your holiday!

jackttcoms commented 6 years ago

also when your back from holiday you might want to take a look at this (i'm pretty sure its a bug):

Basically my database right now has two rows in it and the foreach works fine but as soon as i delete/disable 1 row so there is only 1 remaining it does not work and breaks everything!

Here is my controller code:

    public function index()
    {
        $data = $this->blog->getPosts();
        $this->view('blog/index', $data);
    }

    public function category($id)
    {
        $data = $this->blog->getPostsByCategory($id);
        $this->view('blog/category', $data);
    }

Here is my model code:

    public function getPosts()
    {
        /* get all posts */
        $results = $this->db->select('msi_posts','status = 1');
        return $results;
    }

    public function getPostsByCategory($id)
    {
        /* get all posts by category*/
        $bind = [':cat_id' => $id];
        $results = $this->db->select('msi_posts','active = 1 AND cat_id = :cat_id', $bind);
        return $results;
    }

Here is my view code:

<?php foreach($data as $post) : ?>
<div class="card card-body mb-3">
    <div class="card-block">
    <h4 class="card-title"><?php echo $post['title']; ?></h4>

    <a href="<?php echo FULL_ROOT; ?>/blog/post/<?php echo $post['id']; ?>" class="btn btn-dark">More</a>
    </div>
</div>
<?php endforeach; ?>

image image image

Thanks again

jackttcoms commented 6 years ago

Fix is this but i'm unsure if this will affect something else:

        if(empty($data)) { 
            return false; // return FALSE
        } elseif (count($data) > 0) { or count($data) >= 1) {
            return $data; // return full index of records.
        } else {
            return $data[0]; // return single record.
        }

Actually it breaks the login:

    public function login($email,$password)
    {
        $bind = [':email' => $email];
        $results = $this->db->select('msi_users','email = :email', $bind);

-------        $hashed_password = $results['password'];
        if ( password_verify($password,$hashed_password) ) {
            $this->lastlogin($email);
            return $results;
        } else {
            return false;
        }
    }