Jump to content

Method call working in one place but not the other


TechnoDiver
Go to solution Solved by kicken,

Recommended Posts

I'm really confused and hoping someone can point me in the right direction. I feel this is one of those really simple things that I'm going to want to slap myself in the head over when it's resolved.

It simply involves displaying a comment count in a certain area of my project. I have this method to display comments here ->

<?php

public function display($post_id) {
     
  $rule = "AND comment_status='approved' ORDER BY date_added DESC";
  $field = "post_id";
  $query = $this->_db->get(self::$_table, array($field, "=", $post_id), $rule); 
  $this->_data = $query->all();

  $this->_count = count($this->_data);

  $cnt = 0;
  foreach($this->_data as $obj) {
      $data = array(
          "id" => $obj->id,
          "post_id" => $obj->post_id,
          "commenter" => $obj->username,
          "comment" => $obj->body,
          "date" => date("F d, Y H:i:s", strtotime($obj->date_added)),
          "profile_pic" => $this->_user->profilePic($obj->username),
      );

      echo HTML::comments($data, $cnt);
      $cnt++;
  }

  echo $this->count(); // JUST HERE FOR TEST PURPOSES

}

public function count() {
  return $this->_count;
}

The line that's commented for FOR TEST PURPOSES displays the comment count as expected. The issue arises when I port it to the display page.

<h5 class="title"><?php echo $comment->count(); ?> Comments</h5>

I get no error, but I get no number for the comment count either. I don't understand why. I've obviously done the instantiation at the top, I didn't overlook that (represented by $comment).

As the count stands right now it should say '2 Comments'. The $this->count() test line works, why am I getting no result where it matters?

Link to comment
Share on other sites

57 minutes ago, requinix said:

Are you sure that display() has executed by the time you try to call count()? What's the rest of the code involving the $comment object?

There's really not much more to this class right now. display() is executing because the comments are there and the line that's commented as TEST PURPOSES shows the number 2 under the displayed comments. Here is the entire comment class as it stands right now ->

<?php

class Comment {

  // public static $num_comments;

  private $_db,
          $_data,
          $_user,
          $_count;

  private static $_table = "comments";

  public function __construct() {
      $this->_db = DB::getInstance();
      $this->_user = new User();
  }

  public function add($id, $body) {
      if(!empty($body)) {

          $this->_db->insert(self::$_table, array(
              "post_id" => $id,
              "username" => $this->_user->data()->username,
              "body" => $body,
          ));
          return true;
      }
  }

  public function display($post_id) {

      $rule = "AND comment_status='approved' ORDER BY date_added DESC";
      $field = "post_id";
      $query = $this->_db->get(self::$_table, array($field, "=", $post_id), $rule); 
      $this->_data = $query->all();

      $this->_count = count($this->_data);

      $cnt = 0;
      foreach($this->_data as $obj) {
          $data = array(
              "id" => $obj->id,
              "post_id" => $obj->post_id,
              "commenter" => $obj->username,
              "comment" => $obj->body,
              "date" => date("F d, Y H:i:s", strtotime($obj->date_added)),
              "profile_pic" => $this->_user->profilePic($obj->username),
          );

          echo HTML::comments($data, $cnt);
          $cnt++;
      }

      echo $this->count(); // JUST HERE FOR TEST PURPOSES

  }

  public function count() {
      return $this->_count;
  }

As you can see I tried to do it statically at one time too and that wasn't getting there either.

In the SS you can see at the top it should say '2 Comments' but it only says 'Comments' and at the bottom you can see that it returns '2' from the TEST commented line in the display() method. I'm kind of (really) at a loss, it seems like a simple thing and I've been messing with it for a few hours. It just won't display.

As an aside, I did have this working once. That was yesterday I had a dedicated method to query the DB and count the comments for each post; though that wasn't working perfectly because once a comment was added and the page reloaded it didn't up the count until the page reloaded a second time. It wasn't until I was in bed last night that I realized it was redundant because display() would provide that count with only one DB query, so today I went to tighten it up a bit and now I can't get it to display the count in that location at all.

fucked_up_comment_count.png

Edited by TechnoDiver
Forgot SS
Link to comment
Share on other sites

2 hours ago, requinix said:

Are you sure that display() has executed by the time you try to call count()? What's the rest of the code involving the $comment object?

Yea, yea, I'm really stupid sometimes. I got thinking about what you said again and the more I thought the more sense it made. You're right that's exactly the issue.

<div class="comment-area clearfix">
                                
    <!-- need to make this dynamic -->
    <h5 class="title"><?php echo $comment->count(); ?> Comments</h5>

    <?php if(!$message): ?>
        <h4>Leave a comment</h4>
    <?php else: ?>
        <div class='success'>
            <p class='bg-color-third text-center text-color-primary'>Your comment has been published</p>
        </div>
    <?php endif; ?>

    <div class="contact-form-area mb-5">
        <form action="single_post.php?post_id=<?php echo $post_id; ?>&related=<?php echo $related; ?>" method="POST">
            <div class="row">
                <div class="col-12">
                    <textarea name="comment" class="form-control" id="message" placeholder="Comment"></textarea>
                </div>
                <div class="form-group">
                    <input type="submit" name="submit" value="Submit Comment" class="btn bg-color-primary text-color-fourth">
                </div>
            </div>
        </form>
    </div>

    <?php echo $comment->display($post_id); ?>

display() is being called after count().

Is the only way to rectify this to put them into different class methods to be called separately??

I tried assigning display() to a variable at the top of the page to be called later, and that had catastrophic consequences. 

So is there any other way to do this and still keep the $this->count inside the display method or do I need to put it in a method of its own?

Link to comment
Share on other sites

14 hours ago, kicken said:

Move the first part of your display method that loads the data into it's own method and call it from the constructor.

OK. It wasn't immediately obvious what you meant at first, after a cup of tea and some contemplation it clarified itself and things are almost working properly. In fact they are working properly except upon 'submit' the page reloads, I get the message 'true' that the comment has been submitted, and it is present in the DB.

But it doesn't show the comment nor the updated commented count until I manually reload the page a second time: click 'submit (only change is it says the comment has been submitted and comment goes to DB) -> manually reload page (now the comment count refreshes and the comment is visible).

I have no idea why this is happening, any hints??

Here's my amended Comment class ->

<?php

class Comment {

  // public static $num_comments;

  private $_db,
          $_user,
          $_data,
          $_count;

  private static $_table = "comments";

  public function __construct($post_id) {
      $this->_db = DB::getInstance();
      $this->_user = new User();

      $rule = "AND comment_status='approved' ORDER BY date_added DESC";
      $field = "post_id";
      $query = $this->_db->get(self::$_table, array($field, "=", $post_id), $rule); 
      $this->_data = $query->all();

      $this->_count = count($this->_data);
  }

  public function display() {

      $cnt = 0;
      foreach($this->_data as $obj) {
          $data = array(
              "id" => $obj->id,
              "post_id" => $obj->post_id,
              "commenter" => $obj->username,
              "comment" => $obj->body,
              "date" => date("F d, Y H:i:s", strtotime($obj->date_added)),
              "profile_pic" => $this->_user->profilePic($obj->username),
          );

          echo HTML::comments($data, $cnt);
          $cnt++;
      }

  }

  public function count() {
      return $this->_count;
  }

  public function add($id, $body) {
      if(!empty($body)) {

          $this->_db->insert(self::$_table, array(
              "post_id" => $id,
              "username" => $this->_user->data()->username,
              "body" => $body,
          ));
          return true;
      }
  }

And here's the top of the display page (excuse all the instantiations, they'll be put in a require() eventually, it's just easier for me to see everything at the level I'm at) ->

<?php 
require_once($_SERVER["DOCUMENT_ROOT"] . "/qcic/assets/core/init.php"); 
$user = new User();
$actors = new Actors();
$category = new Category();
$post = new Post();
$comment = new Comment(Input::get("post_id"));
$subs = new Subs();

$post_id = Input::get("post_id");
$related = Input::get("related");
$message = false;

//simply increase #views per page load
if($post_id && !empty($post_id)) {
    $post->viewCount($post_id);

    //comment to db                 
    if(Input::get('submit')) {
        // mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT);
       
        if($comment->add($post_id, Input::get('comment'))) {
            $message = true;
        }    
    }
}

like I said, upon 'submit' click, comment goes to DB, message goes to 'true' but the comment count and the comment don't update on the initial reload. I have to reload a second time for them to take effect. It's not something I've experienced before.

Edited by TechnoDiver
forgot to add the code
Link to comment
Share on other sites

4 hours ago, TechnoDiver said:

I have no idea why this is happening, any hints??

Essentially it's the same problem you had with your count.

The original problem with the count was that you were trying to echo the count before you loaded the data.  The new problem is because you're loading the data before you insert the new comment. 

There are a few ways you could solve the issue.

  1. You could simply re-load the data after adding a new comment.
  2. You could re-arrange you code to submit the new comment first, then load the data after.
  3. You could leave the code as-is, but redirect the user after adding a comment so the page gets reloaded automatically.

Typically when submitting data you'd do a redirect as in option #3.  That is known as a Post/Redirect/Get process and prevents people re-submitting duplicate data by trying to reload the page after making a submission.

  • Thanks 1
Link to comment
Share on other sites

7 minutes ago, kicken said:

Typically when submitting data you'd do a redirect as in option #3.  That is known as a Post/Redirect/Get process and prevents people re-submitting duplicate data by trying to reload the page after making a submission.

Ok, I get this. There's been times that I've had to reload multiple time (f5) when messing with an issue and it's duplicated the comment. So this is interesting.

I'm going to read that article and give it a go. Thank you, I may have to come back and readdress this but hopefully I can get this working on my own. Have a great weekend

Link to comment
Share on other sites

On 10/28/2021 at 4:32 PM, kicken said:

The new problem is because you're loading the data before you insert the new comment.

Hay kicken, I've finally been able to get back to my project. I had to refresh my brain on the issues to solve the last few days and I figured a good way to do this was to return to the responses here.

I'm not really clear on exactly what you mean in the line I quoted you in. If you find the time and the will would you mind breaking it down into what exactly is happening behind the scenes regarding this?!

I think you mean that the previously existing data is being loaded before the new data (in this case the comment) is being inserted. But I feel, well I'm not sure how I feel, and if what I think you mean is correct then I'm not sure why it's doing that.

From my perspective the very last command in the top of the display page is the one that changes $message to True, and that is functional as after 'submit' is clicked the message is shown, just not the comment or the count.

I'm also not clear on where to put the redirect or exactly how to implement it. My redirect looks like this ->

<?php

Redirect::to("single_post.php?post_id=<?php echo $post_id; ?>&related=<?php echo $related; ?>");

I thought it should go within this if statement at the top of the display page

<?php

//simply increase #views per page load
if($post_id && !empty($post_id)) {
    $post->viewCount($post_id);

    //comment to db                 
    if(Input::get('submit')) {
        // mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT);
       
        if($comment->add($post_id, Input::get('comment'))) {
            $message = true;
        }  
        
    }
}

And tried it after the statement outside of it. In all cases I've received this gut-wrenching error that I can't make sense of within the context of the redirect. I can't see why a redirect using the same URL that gets one to this page is causing this chaotic error message.

Quote

Warning: Undefined array key 0 in /opt/lampp/htdocs/qcic/assets/class/DB.php on line 132

Warning: Attempt to read property "num_views" on null in /opt/lampp/htdocs/qcic/assets/class/Post.php on line 223

Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /opt/lampp/htdocs/qcic/assets/class/DB.php:35 Stack trace: #0 /opt/lampp/htdocs/qcic/assets/class/DB.php(35): PDOStatement->execute() #1 /opt/lampp/htdocs/qcic/assets/class/DB.php(121): DB->query('UPDATE posts SE...', Array) #2 /opt/lampp/htdocs/qcic/assets/class/Post.php(227): DB->update('posts', '<?php echo 86; ...', Array) #3 /opt/lampp/htdocs/qcic/newsnet/single_post.php(16): Post->viewCount('<?php echo 86; ...') #4 {main} thrown in /opt/lampp/htdocs/qcic/assets/class/DB.php on line 35

So if you get the time and/or will to go into a bit more detail on this (or anyone reading this) I'd really love to read it, Thanks and have a great weekend

Edited by TechnoDiver
Link to comment
Share on other sites

  • Solution
2 hours ago, TechnoDiver said:

I think you mean that the previously existing data is being loaded before the new data (in this case the comment) is being inserted

Yes.  You're loading your existing comments in the constructor of the Comments class, so all your data gets loaded here:

$comment = new Comment(Input::get("post_id"));

The data you load at that point is what you'll end up displaying later on when you call display() and count().  Whether or not $message is true isn't really relevant to how this functions.

2 hours ago, TechnoDiver said:

I'm also not clear on where to put the redirect or exactly how to implement it. My redirect looks like this

That's wrong from a syntax perspective.  If that's what you have, you should be getting a syntax error I would think.  You don't use <?php ?> tags to embed variables into strings.  You use concatenation and/or interpolation.

Redirect::to("single_post.php?post_id=$post_id&related=$related");

With the syntax fixed, replace your $message = true; line with the redirect.  You'll need to use an alternate means of determining whether or not to show your message, such as by adding a message=true parameter to the URL or storing something in the session.

2 hours ago, TechnoDiver said:

I've received this gut-wrenching error that I can't make sense of

This is possibly related to the bad syntax of the redirect.  Notice in the stack trace it shows the php tags as part of the parameters:

Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /opt/lampp/htdocs/qcic/assets/class/DB.php:35 
Stack trace: 
   #0 /opt/lampp/htdocs/qcic/assets/class/DB.php(35): PDOStatement->execute() 
   #1 /opt/lampp/htdocs/qcic/assets/class/DB.php(121): DB->query('UPDATE posts SE...', Array) 
   #2 /opt/lampp/htdocs/qcic/assets/class/Post.php(227): DB->update('posts', '<?php echo 86; ...', Array) 
------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^
   #3 /opt/lampp/htdocs/qcic/newsnet/single_post.php(16): Post->viewCount('<?php echo 86; ...') 
---------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^
   #4 {main} thrown in /opt/lampp/htdocs/qcic/assets/class/DB.php on line 35 

 

Edited by kicken
  • Great Answer 1
Link to comment
Share on other sites

21 minutes ago, kicken said:

With the syntax fixed, replace your $message = true; line with the redirect

Haha, this is the first place that I placed the redirect and got that error message. After the error the wind completely left my sails because I couldn't figure out where else it should have gone and if it didn't go here then it called into question everything I thought I understood. Seeing it was my naive syntax error with the link string and that it works now where I had originally put the redirect gave me back some confidence.

re-placing the message = True isn't a big deal.

Thank you for you response

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.