-2

I'm having a bit of trouble with the OOP CRUD method. My POST method is not retrieving or posting data to the DB. And I'm not sure where to look since it does not give any errors to display.

The logic above the form:

$id = $_GET['id'];


//Add Board
$b = new Board();
$userID = $_SESSION['id'];
$boards= $b->loadBoards($userID);

if(isset($_POST['addBoard'])){
try{
    $sB = new Board();
    $postID = 61;
    $boardID = 1;
    $sBoard = $sB->savePostToBoard($postID, $boardID);
} catch (Exception $e) {
        $error = $e->getMessage();
}
}

This is the form:

<form method="post">
 <div class="btn-group" data-toggle="buttons">
<?php foreach($boards as $key) : ?>

 <label class="btn btn-primary active">
 <input type="radio" name="option[]"value="
  <?php echo $key['boardID'];?>">
  <?php echo $key['boardTitle']; ?></label>
  <?php endforeach ?>
  <input class="btn btn-danger"type="submit" value="Toevoegen" 
  id="addBoard" name="addBoard">
    </div>
</form>

And the class function:

public function getConnection() {
    $conn = Db::getInstance();
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    return $conn;
}
private function getInputParameterDataType($value) {
$dataType = PDO::PARAM_STR;
if (is_int($value)) {
    $dataType = PDO::PARAM_INT;
} elseif (is_bool($value)) {
    $dataType = PDO::PARAM_BOOL;
}
return $dataType;
}
public function savePostToBoard($postID, $boardID)
{
$sql ="UPDATE board SET postID=:". $postID . " WHERE boardID=:boardID";
$statement = $this->getConnection()->prepare($sql);
$statement->bindValue(":boardID",$boardID, $this-
>getInputParameterDataType($boardID));
$statement->bindValue(":postID", $postid);
return $statement->execute();

}

Any feedback is highly appreciated, thanks for taking the time. Kind regards

Database Layout Table Board

The FrontEnd with Form Database Layout Table Items

Moya
  • 89
  • 1
  • 2
  • 10

2 Answers2

0

*) All your radio buttons have the same id attribute. It should be unique.

*) Give the id "addBoard" to the submit button.

*) Why do you use POST and GET?

$boardID = $_POST['option'];
$postID = $_GET['id'];

*) You missed the $ sign in statement->bindValue(":boardID",boardID);!

*) Posted data type should correspond to db data type. Use a third parameter in bindValue() to define the corresponding data type. And use a function:

private function getInputParameterDataType($value) {
    $dataType = PDO::PARAM_STR;
    if (is_int($value)) {
        $dataType = PDO::PARAM_INT;
    } elseif (is_bool($value)) {
        $dataType = PDO::PARAM_BOOL;
    }
    return $dataType;
}

And then call like this:

$statement->bindValue(":boardID",$boardID, $this->getInputParameterDataType($boardID));

*) PDO::prepare() can throw a PDOException OR the value FALSE. So you should handle both cases. I wrote an answer about this: My answer for exception handling of prepare() & execute().

*) Have you made some changes until now? Works everything, or not yet?

Ok, I'll study it now.

Solutions for the new code:

*) Don't use semicolon ";" at the end of sql statements.

*) Update should have this form:

UPDATE [table-name] SET [col1]=:[col1],[col2]=:[col2] WHERE [PK-name]=:[PK-name]

*) For readability: pass the sql statement in a variable and use points to delimit used variables in it. Like:

$sql = "UPDATE board SET postID=:" . $postid . " WHERE boardID=:boardID"
$statement = $conn->prepare($sql);

*) As @teresko reminded you: you didn't pass $boardID to savePostToBoard():

$sBoard = $sB->savePostToBoard($postID, $boardID);
public function savePostToBoard($postID, $boardID) {...}

*) Use either $postID or $postid overall. Right now you are using both forms. Make a choice.

It should work now. Let me know.

Some recommandations:

*) Let your methods do only one thing (if possible). In your question, the connection creation doesn't belong in the method. If you call 20 methods which require a connection, then you have to write the same connection creation code in each of them. In your case, better define a getConnection() method in the Board class.

public function getConnection() {
    $conn = Db::getInstance();
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    return $conn;
}

And now you have only this in your savePostOnBoard() by calling it:

public function savePostToBoard($postID) {
    $statement = $this->getConnection()->prepare(...);
    //...
}

*) In general, it's better to use the constructor for passing the variables used later by the methods. That's the role of the constructor: to initialize, e.g to give initial values to the object properties on creation. Example:

class Auto {

    private $color;
    private $doors;
    private $airConditioning;

    public __function __construct($color = 'blue', $doors = 3, $airConditioning = true) {
        $this->color = $color;
        $this->doors = $doors;
        $this->airConditioning = $airConditioning;
    }
}

$myAuto = new Auto('red', 4, false);
$hisAuto = new Auto('yellow', 8, true);

Oh, and always give easy-to-follow names to variables, functions, classes, etc. In your case, the upper phrase and this one would apply, for example, like this:

$board = new Board($boardID);
$boardUpdated = $board->update($postID);

See? Nicer names, more logical (following our real-world perception) arrangement of the arguments.

*) I would also recommend you to split your code in methods. This way you achieve a better reusability of code pieces and an elegant, easy-to-follow structure. Maybe something like this in analogy with your code:

public function savePostToBoard($postID, $boardID) {
    $sql = "UPDATE board SET postID=:" . $postID . " WHERE boardID=:boardID";
    $bindings = array(
        ':postID' => $postID,
        ':boardID' => $boardID
    );
    $statement = $this->execute($sql, $bindings);
    return $statement->rowCount();
}

protected function execute($sql, array $bindings = array()) {
    $statement = $this->prepareStatement($sql);
    $this->bindInputParameters($statement, $bindings);
    $this->executePreparedStatement($statement);
    return $statement;
}

private function prepareStatement($sql) {
    $statement = $this->getConnection()->prepare($sql);
    return $statement;
}

private function bindInputParameters($statement, $bindings) {
    foreach ($bindings as $key => $value) {
        $statement->bindValue(
                $this->getInputParameterName($key)
                , $value
                , $this->getInputParameterDataType($value)
        );
    }
    return $this;
}

private function getInputParameterName($key) {
    if (is_int($key)) {
        return $key + 1;
    }
    $trimmed = ltrim($key, ':');
    return ':' . $trimmed;
}

private function getInputParameterDataType($value) {
    $dataType = PDO::PARAM_STR;
    if (is_int($value)) {
        $dataType = PDO::PARAM_INT;
    } elseif (is_bool($value)) {
        $dataType = PDO::PARAM_BOOL;
    }
    return $dataType;
}

private function executePreparedStatement($statement) {
    $statement->execute();
    return $this;
}

Good luck with your project!

Community
  • 1
  • 1
  • I made the changes as described above. I use $_GET['id'] to bind the value from the url (detail.php?id=62) to the postID (they are the same) – Moya May 14 '17 at 00:28
  • I don't quite understand. You submit a form with `method="post"`, right? And when you submit it, you read also a GET-value, e.g. the "id" your url in address bar? And you also have a `$_SESSION['id']`. –  May 14 '17 at 00:36
  • That is correct sir, this is actually a school project and collaboration with other students, it seems that the variable $id contains $_GET['id'] and is already declared above my code. I suppose I can use the variable $id instead of redeclaring it as $postID. As for the $_SESSION['id'] this contains the user id to link content from that user. – Moya May 14 '17 at 00:57
  • ok, thanks for the explanation. I can't really comment, so I'll right further in my answer by editing it. –  May 14 '17 at 01:02
  • Thanks for your extensive view on my project! I've made some changes and updated my code but it's still not doing anything. I've added some screenshots from the tables and front end to give you a clearer view – Moya May 14 '17 at 10:32
  • With pleasure. I'm looking at them. –  May 14 '17 at 10:57
  • In my answer I added also some other proposals. Have you read them? One of them: change overall $postid to $postID, please. –  May 14 '17 at 11:02
  • Pass `$boardID` to `$sBoard = $sB->savePostToBoard($postID);`. So, it MUST be `$sBoard = $sB->savePostToBoard($postID, $boardID);`. –  May 14 '17 at 11:05
  • @Moya, sorry, I forgot to notify you (by including your username in my comments). Read my upper two comments. –  May 14 '17 at 11:17
  • I really appreciate your input for this matter! I made the changes as you explained to me. But i'm not sure what you mean with $postid, I did a quick search in my class code and all the variables needed are now $postID – Moya May 14 '17 at 11:33
  • Do you mean that I should implement the methods you so kindly provided? – Moya May 14 '17 at 11:41
  • I noticed that the variable $boardID is not defined with a value, it has to be the value being echoed in the radio button (value="") – Moya May 14 '17 at 11:49
  • @Moya, no, no, you can make your code prettier after you are sure it works. I just ment: Instead `$postid` (with small "id") you must have `$postID` (with big "ID") in your code, overall. Especially in `savePostToBoard()` function. And please, if you change something, make this changes also in your question-post by reediting it. Thanks. –  May 14 '17 at 11:51
  • Yes, of course, I'm updating my question-post whenever I make changes. I just can't wrap my head around this. I've build several POST forms that worked perfectly but this is giving me a headache lol – Moya May 14 '17 at 11:53
  • @Moya Exactly: $boardID shod gain the value from radio button - `value="`. I think it's time for you to just give values by-hand. Like: `$boardID = 123;`, `$postID = 43;`. –  May 14 '17 at 11:58
  • Ok, I'll update the question code above, the values are now declared before the IF statement $postID = 61; - $boardID = 1; these are corresponding to the data in table board (PK ID) and items (PK ID) – Moya May 14 '17 at 12:06
  • @Moya tell me please exactly what you make and what doesn't work. Feel free to write more comments if you need a lot of words. The next step will then be to simplify your code. And after that to go in db and check the data types, which must correspond to the ones posted by your update function. Ok? –  May 14 '17 at 12:11
  • @Moya You still didn't change this. Please write `$sBoard = $sB->savePostToBoard($postID, $boardID);` instead of yours! That's why your function makes no update. $boardID is NOT passed as argument in your function CALL! –  May 14 '17 at 12:15
  • Yes sir, totally agree. Sorry I updated the question code, my local code was updated as you suggested. So to sum up briefly, I'm trying to make a POST form with radio buttons generated by a PHP foreach loop. The radio buttons should contain the value of the boards corresponding to the user (wich it does). I now want to make an UPDATE function where the item displayed in the front-end (postID), gets posted in the allocated field in the database board table 'postID' – Moya May 14 '17 at 12:18
  • @Moya ... And bring `$postID=61` and `$boardID=1` inside of `try-catch` block. –  May 14 '17 at 12:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/144168/discussion-between-moya-and-aendeerei). – Moya May 14 '17 at 12:22
  • @Moya Great explanation. But you wrote I knew already :-) I mean, I know what your whole code does. What I don't know is what happens exactly from the moment in which you are clicking the submit button. Your submit and update operations should have a certain behavior, right? But they don't behave as expected. So, which negative effects are you observing, that make you say "this and that doesn't work"? That's what interests me. –  May 14 '17 at 12:30
  • I noticed that there is a second form with method post in the same HTML page, could these two be in conflict? – Moya May 14 '17 at 12:30
  • @Moya YES!! If one form is inside the other, then this can definitely have a negative effect. Also, when they have the same names, id's, elements,etc etc. So please delete one of them in order to properly test your code. And let's go in chat –  May 14 '17 at 12:34
-1

You really should use these in your PDO instantiation:

 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Then you would have seen the syntax error in your query:
for some reason you have VALUES (:postID;) (notice the semicolon).

Also, you are not actually passing $boardID to the savePostToBoard() method at any point. You should add a second prarameter in that method.


As for your general application structure, you really should avoid using singletons to share the database connection and you should separate the domain logic from the persistence logic. Reading this post might be beneficial for you.

Community
  • 1
  • 1
tereško
  • 58,060
  • 25
  • 98
  • 150
  • Thanks for your response, I'll have a look at the documentation you gave me. And I'm adding those setAttribute lines to my function. – Moya May 14 '17 at 00:34