0

I am working in a recipe book with SQL and PDO. My 'recipes' table has a column for 'id', 'name', 'attachment_id'; The 'attachment_id' column is the foreign key.

The 'attachments' table, has colunms 'id', 'attachment_path'.

At the moment, if I remove a recipe, the image, which its path gets stored on the "attachments" table, stays there. What I want to achieve is, if I remove a recipe, the "attachment" that belongs to it also needs to be removed. I have done some research and I understand I need to create a trigger but it keeps displaying it is wrong and I can't undertand how it works....or what to do with "delimiter"....

So.... here we go:

functions.php:

 function delete_recipe($recipe_id = ':recipe_id', $attachment_id = ':attachment_id') {
              include 'db_connection.php';
        try {
            $sql = "DELETE FROM recipes ";
            $sql .= "WHERE id =:recipe_id ";
            $sql .= "LIMIT 1";

            $results = $conn->prepare($sql);
            $results->bindParam(':recipe_id', $recipe_id, PDO::PARAM_INT);

        if($results->execute()) {
          echo '1 row has been removed';  
          // if the recipe gets deleted, then delete its attachment
          delete_attachment($attachment_id);

        }

        $conn = null;

        } catch(PDOException $e) {
            echo 'Error: ' . $e->getMessage() . '<br />';
            return false;
        }

        return true;  
    }

function delete_attachment($attachment_id = ':attachment_id') {
       include 'db_connection.php';
    try {
        $sql = 'DELIMITER $$';
        $sql = 'CREATE TRIGGER image_before_delete_recipe';
        $sql .= ' AFTER DELETE ON `recipes`;
        $sql .= ' FOR EACH ROW BEGIN';
        $sql .= ' IF NEW.deleted THEN ';  

        $sql .= "DELETE FROM attachments ";
        $sql .= "WHERE id =:attachment_id ";
        $sql .= "LIMIT 1"; 

        $sql .= 'DELIMITER $$';

        $results = $conn->prepare($sql);
        $results->bindParam(':attachment_id', $attachment_id, PDO::PARAM_INT);

    if($results->execute()) {
      echo '1 row has been removed';  
    }

    $conn = null;

    } catch(PDOException $e) {
        echo 'Error: ' . $e->getMessage() . '<br />';
        return false;
    }

    return true;
}

I know the delete_attachment does not have any sense..... I literally can't understand how this trigger works and/or how I should build it..... is it instead the normal query for "delete"?

The way the image is uploades is:

  if ($_SERVER['REQUEST_METHOD'] == 'POST') {
        $name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
         $attach_id = filter_input(INPUT_POST, 'attach_id', FILTER_SANITIZE_NUMBER_INT);

       $folder="images/";
       $file = $_FILES['photo']['tmp_name'];
       $file_to_upload = $folder . basename($_FILES['photo']['name']);

       if(move_uploaded_file($file, $file_to_upload)) {
           echo "File is valid, and was successfully uploaded.\n";


       if($attach_id = add_image($file_to_upload)) {
           if(add_recipe($name, $attach_id)) {

               header('Location: index.php');
            exit;
          } else {
               $error_message = "Could not add recipe";
          } 
       } else {
               $error_message = "Could not add image";
          } 

       } else {
           echo 'Upload failure';
           print_r($_FILES);
       }  
    }

    include 'includes/header.php';?>
        <div class="col-container">
          <h1>Add a recipe</h1>
          <?php
          if (isset($error_message)) {
              echo '<p class="message">' . $error_message . '</p>';
          }
          ?>
          <form method="POST" action="recipe.php" enctype="multipart/form-data">   
            <div>
              <label for="name" class="required">Name</label>
              <input name="name" type="text" value="" />
            </div> 
            <div>  
        <input name="attach_id" type="text" value="" class="hidden" />  
            <label for="file">Filename:</label>
            <input type="file" name="photo" id="photo"><br>
            </div>
            <button class="submit" type="submit" name="submit">Submit</button>
          </form>
        </div>  
    <?php include 'includes/footer.php'; 

I know it very messy, and wrong, I should check on the data is coming good, no empty fields..... but for the start, I prefer to work on the functionality... Anyone could tell me if I should definitely do this with one of those triggers, and if so.... how do I start????

Thank you

eve_mf
  • 795
  • 3
  • 12
  • 36
  • `$attachment_id` equals `:attachment_id` What do you expect to find with such value? – u_mulder Nov 14 '16 at 13:16
  • Maybe I'm missing something here, but if you know the attachment ID going into the recipe delete, wouldn't it be possible to just run both deletes one after the other? Or if you need to get the attachment ID to delete from the Recipe you're deleting, run a query to grab the attachment ID, assign the value to a variable, delete the recipe record, then delete the attachment record. – SGR Nov 14 '16 at 13:17
  • well, what I want it is a way to send to this value, the value for attachment_id from the recipes book when a recipe is deleted... :S – eve_mf Nov 14 '16 at 13:17
  • A trigger is wriiten, and STORED in your database much like a procedure. It is automatically activated by MYSQL itself (not by your code) when you complete whatever event it is based on i.e. Delete a row on table xxx. So you create a trigger once, and definitely not after you have completed the action that would _trigger_ the trigger – RiggsFolly Nov 14 '16 at 13:18
  • Aha, SGR I understand that, and it is what I was trying to do at first, before I read about triggers and my mind decided I had to do it with that. The problem is, should I do another query just to get the attachment_id before the recipe gets deleted? – eve_mf Nov 14 '16 at 13:19
  • 1
    create trigger in database, after delete recipes, and replace "WHERE id =:attachment_id" to "WHERE id = OLD.ID". NOTE that this id should be recipe_id, if in your structure they are not the same – Vahe Shadunts Nov 14 '16 at 13:20
  • Then RiggsFolly, should I use a trigger to delete the recipe attachment? or instead delete the row for the recipe and then delete the attachment? – eve_mf Nov 14 '16 at 13:20
  • 1
    Also, you will need to look at the `attachment` row before it gets deleted to allow you to remove the image from the folder storing the images – RiggsFolly Nov 14 '16 at 13:20
  • aaaaha! thank's SGR, I am going to try that way, I didn't think about that! :D – eve_mf Nov 14 '16 at 13:22
  • 1
    If you are going to use @SGR method, and I agree that would be a good idea. Remember that you will want to run these 2 queries within a Transaction so you never get one row deleted without deleting both!!! – RiggsFolly Nov 14 '16 at 13:24
  • As you can learn from the linked answer, in order to implement automatic deletion, you should use not a trigger but a foreign key. which works exactly like you described; – Your Common Sense Nov 14 '16 at 13:33
  • I am sorry, but I don't get it.... At the moment, attachment_id is a foreign key of the recipes table. I have seen someone put this question as duplicate, but I can't see where my question have something to do with "MySQL Foreign Key On Delete" question.... I am getting even more lost than when I started :s WHen should I do it with a trigger then? – eve_mf Nov 14 '16 at 14:54

0 Answers0